Switch to: V10V9V8V7V6V5

Form Editor - Launch External Application

Added in Valentina 10.1

Valentina Studio incorporates QProcess class into its JavaScript object model, giving a way to extend the functionality of your forms and scripts with the power of other applications.

QProcess class allows you to execute an external application, specify parameters, write to its standard input, read results from its standard output and more.

For example, you can execute:

  • shell scripts (such as bash, bat)
  • macOS automation scripts ( AppleScript and JXA – JavaScript for Automation). You can send Apple Events to other applications supporting the IPC interface, e.g. Word, Excel.
  • PowerShell code on Windows. For example, you can access other applications via the COM interface (e.g. Word, Excel)
  • scripts written in interpreted languages (Python, Perl)
  • other applications with the command-line interface

QProcess class gives you full control over the execution.

In the next sections, you will find examples of QProcess usage.

bash

Bash is the GNU Project's Bourne Again SHell, a complete implementation of the IEEE POSIX and Open Group shell specification with interactive command line editing, job control on architectures that support it, csh-like features such as history substitution and brace expansion, and a slew of other features.

Use QProcess.execute to create a new directory via bash:

QProcess.execute( 'sh', [ '-c', 'mkdir /tmp/qprocess_dir' ] );

But with this approach, you don't receive information about errors.

In order to get an error, it is necessary to use QProcess.start to launch an application and read errors with QProcess.readAllStandardError method:

var p = new QProcess;
p.start( 'sh', [ '-c', 'mkdir /tmp/qprocess_dir' ]);
p.waitForFinished( -1 );
 
var result = String( p.readAllStandardError() );
 
if( result.length > 0 )
    QMessageBox.critical( 'Error', result );

On the second run, it will show a message box with text ”mkdir: /tmp/qprocess_dir: File exists

To read the output of the script QProcess.readAllStandardOutput method is used:

var p = new QProcess;
p.start( 'sh', [ '-c', 'ps ax | wc -l' ]);
p.waitForFinished( -1 );
 
var result = String( p.readAllStandardOutput() );
QMessageBox.information( 'Title', 'There are ' + result.trim() + ' processes running' );

As a result, a message box with a similar text will be shown:

Python

The following example written in Python demonstrates how to open an existing Excel file, fetch data from its first column and pass it to the text edit form control:

var pythonScript = `from openpyxl import load_workbook
 
wb = load_workbook('/tmp/records.xlsx')
 
for i in range( 2, wb.active.max_row ):
  print( wb.active[ 'A{0}'.format(i) ].value )`;
 
var p = new QProcess;
p.start( '/usr/local/bin/python3', [ '-c', pythonScript ] );
p.waitForFinished( -1 );
 
this.textEdit.plainText = String( p.readAllStandardOutput() );

MacOS automation

MacOS automation scripts allow you to communicate with other applications supporting the IPC interface.

AppleScript

Opening a new document in Microsoft Word using the AppleScript language:

QProcess.execute(
	'/usr/bin/osascript',
	[
		'-l',
		'AppleScript',
		'-e',
		`tell application "Microsoft Word"
                   activate
                   make new document
                 end tell`
	]);

The following example written in AppleScript demonstrates how to open an existing Excel file, fetch data from its first column and pass it to the form control:

var appleScript = `on convertListToString(theList, theDelimiter)
	set AppleScript's text item delimiters to theDelimiter
	set theString to theList as string
	set AppleScript's text item delimiters to ""
	return theString
end convertListToString
 
tell application "Microsoft Excel"
	open workbook workbook file name "/tmp/records.xlsx"
	tell active sheet
		tell used range
			set RowCount to count of rows
		end tell
 
		set namesList to value of range ("a2:a" & RowCount)
	end tell
end tell
 
set result to convertListToString(namesList, return)
 
copy result to stdout`;
 
var p = new QProcess;
p.start( '/usr/bin/osascript', [ '-l', 'AppleScript', '-e', appleScript ] );
p.waitForFinished( -1 );
 
this.textEdit.plainText = String( p.readAllStandardOutput() );

JavaScript

And the same tasks using the JavaScript for Automation (JXA).

Opening a new document in Microsoft Word:

QProcess.execute(
	'/usr/bin/osascript',
	[
		'-l',
		'JavaScript',
		'-e',
		`const word = Application('Microsoft Word');
		 word.activate();
		 newDocument = word.Document().make();`
	]);

Opening an existing Excel file, fetching data from its first column and passing it to the form control:

var javaScript = `var excel = Application('Microsoft Excel');
var doc = excel.open('/tmp/records.xlsx');
var rowCount = excel.activeSheet.usedRange.rows().length;
var namesList = excel.activeSheet.ranges[ 'a2:a' + rowCount ].value();
namesList.join("\\n");`;
 
var p = new QProcess;
p.start( '/usr/bin/osascript',  [ '-l', 'JavaScript', '-e', javaScript ] );
p.waitForFinished( -1 );
 
this.textEdit.plainText = String( p.readAllStandardOutput() );

PowerShell

The following sample that utilizes PowerShell interpreter demonstrates how to open an existing Excel file, fetch data from its first column and paste it in the text edit form control:

var powerShell = '$objExcel = New-Object -ComObject Excel.Application\n\
$WorkBook = $objExcel.Workbooks.Open("C:\\records.xlsx")\n\
$WorkSheet = $WorkBook.ActiveSheet\n\
$rows = $WorkSheet.UsedRange.Rows.Count\n\
$records = @($workSheet.Range( "A2:A"+$rows).Value2 )\n\
Write-Output $records';
 
var p = new QProcess;
p.start( 'PowerShell', [ '-Command', powerShell ] );
p.waitForFinished( -1 );
 
this.textEdit.plainText = String( p.readAllStandardOutput() );

Possible errors from the script execution can be obtained using the QProcess.readAllStandardError method.

Command-Line Applications

The command-line application is started with QProcess.start method. If it writes messages to the standard output they can be read using the QProcess.readAllStandardOutput method.

var p = new QProcess;
p.start( 'ping', [ '-c', '3', 'valentina-db.com' ] );
p.waitForFinished( -1 );
this.textEdit.plainText = String( p.readAllStandardOutput() );

The result will be written to the TextEdit control:

You can write to the standard input using the QProcess.write method.

In the following example text entered to the text edit control is passed to the wc utility to count words.

var p = new QProcess;
p.start( 'wc', [ '-w' ] );
p.waitForStarted( -1 );
p.write( this.textEdit.plainText );
p.closeWriteChannel();
p.waitForFinished( -1 );
 
QMessageBox.information( '', 'Number of words: ' + String( p.readAllStandardOutput() ).trim() );

wc utility is used for illustration purposes only, normally you should use JavaScript for such tasks.