Standalone Executables on Windows

From Lianjapedia
Revision as of 01:52, 20 March 2024 by Barrymavin (Talk | contribs)

Jump to: navigation, search

See Also

Deployment, Lianja Package Manager, Packaging Lianja Desktop Apps for Windows

Overview

From Lianja 7.0 developers can build standalone executables on Windows.

These executables can only be built for Apps that have been hand-coded in LianjaScript, Python, JavaScript, TypeScript or Babel using the Lianja UI Framework.

Alternatively, you can also visually build forms in the App Builder that use any of the following scripting languages as the Lianja UI framework is scripting language independent across Desktop, Web and Mobile Apps.

- LianjaScript/VFP

- Python

- JavaScript

- Typescript

Forms are based on a tabview section which contains canvas, grid or webview based sections in its tabs. See the blog article Working with forms in Lianja for further details.

This functionality is primarily for building small GUI Apps, not for business Apps running under the Lianja App Center with Users and Roles.

Sample App: example_timeclock

The example_timeclock sample App is included in the Lianja App Builder distribution from v7.0.0 in the 'General' category.

This app uses the new Camera UI Framework class and is a small App to handle clocking in and out of employees in a company.

Sample App: example_timeclock


Feel free to enhance this to suit your own needs by adding support for storing the clock in/out date and time along with the employees photo.

Building Standalone Executables

Scripting Language

Select the scripting language in the App Settings:

Scripting Language


Standalone

Check 'Standalone' in the UI Presentation Rules App Settings.

Standalone Lib

From v9.5, checking the 'Standalone Lib' setting will include a copy of the library folder in the executable's directory. When the standalone app is run the library directory is set to the standalone App library directory.

Standalone Zip

From v9.5, checking the 'Standalone Zip' setting will create a zip file for the standalone App.

Standalone Exe

From v9.5, checking the 'Standalone Exe' setting will create an installer as a self-extracting exe file for the standalone App.

Standalone Data

From v9.5, specifying a list of databases in the 'Standalone Data' setting will copy the databases into the standalone App directory. When the standalone app is run the data directory is set to the standalone App data directory.

Script

Then write the 'main' script with the same name as the App. In the case of the sample example_timeclock App, this is example_timeclock.prg or example_timeclock.js or example_timeclock.py (see code below). You can switch the 'Scripting language' in the App Settings to test each one.

LianjaScript/Visual FoxPro

Note the READ EVENTS at the end of the code which is needed for a standalone App.

example_timeclock.prg

local oform = createObject("Form")
oform.resize(600, 600)
oform.closable = 1
oform.caption = "Time clock - LianjaScript"
oform.minwidth = 600
oform.minheight = 600
 
oform.addObject("ocont", "container")
ocont.margin = 10
ocont.autosize = 1
ocont.layout = "V"
ocont.backcolor = "black"
 
ocont.addObject("obadgenolab", "label")
obadgenolab.fixedheight = 24
obadgenolab.autowidth = 1
obadgenolab.alignment = "center"
obadgenolab.caption = "Enter Badge Number"
obadgenolab.backcolor = "darkgray"
obadgenolab.forecolor = "white"
obadgenolab.fontbold = 1
obadgenolab.fontsize = 10
 
ocont.addspacing(10)
ocont.addObject("obadgeno", "textbox")
obadgeno.fixedheight = 24
obadgeno.autowidth = 1
obadgeno.placeholder = "Enter your badge number, Take a Photo then CLOCK IN or CLOCK OUT"
 
ocont.addspacing(10)
ocont.addObject("obadgenolab2", "label")
obadgenolab2.fixedheight = 24
obadgenolab2.autowidth = 1
obadgenolab2.alignment = "center"
obadgenolab2.caption = "Take a Photo"
obadgenolab2.backcolor = "darkgray"
obadgenolab2.forecolor = "white"
obadgenolab2.fontbold = 1
obadgenolab2.fontsize = 10
 
ocont.addspacing(10)
ocont.addObject("ocamera", "camera")
ocamera.autowidth = 1
ocamera.autoheight = 1
ocamera.backcolor = "black"
 
ocont.addspacing(10)
ocont.addObject("obadgenolab3", "label")
obadgenolab3.fixedheight = 24
obadgenolab3.autowidth = 1
obadgenolab3.alignment = "center"
obadgenolab3.caption = "Clock in / Clock out"
obadgenolab3.backcolor = "darkgray"
obadgenolab3.forecolor = "white"
obadgenolab3.fontbold = 1
obadgenolab3.fontsize = 10
 
ocont.addObject("ocont2", "container")
ocont2.layout = "H"
ocont2.fixedheight = 60
ocont2.backcolor = "black"
ocont2.spacing = 10
 
ocont2.addObject("obtn1", "commandbutton")  
obtn1.resize(60, 50)
obtn1.flat = 1
obtn1.fixedheight = 50
obtn1.caption = "CLOCK IN"
obtn1.stylesheet = "btn"
ocont2.addObject("obtn2", "commandbutton")  
obtn2.flat = 1
obtn2.resize(60, 50)
obtn2.fixedheight = 50
obtn2.stylesheet = "btn"
obtn2.caption = "CLOCK OUT" 
 
// event handlers
proc clockin()
	ocamera.takePhoto()
	thisform.showSuccessMessage("You clocked in on " + dtoc(date()) + " at " + ampm())
endproc
 
proc clockout()
	ocamera.takePhoto()
	thisform.showSuccessMessage("You clocked out on " + dtoc(date()) + " at " + ampm())
endproc
 
obtn1.click = clockin
obtn2.click = clockout
 
// modal form
oform.show()
 
// must put read events at the bottom so the window stays open until closed by user
read events

Python

  • Check that pip is the latest version. From a Windows Command Prompt (replace drive: with the drive for your Lianja App Builder installation):
cd drive:\lianja\bin
python -m pip install --upgrade pip --no-warn-script-location
  • In the Lianja App Builder Console Workspace, create the python3 directory to contain the modules local to the App (this has already been created for the example_timeclock App):
mkdir python3
  • Install local Python modules (pip can be run from the Lianja/VFP tab in the Console Workspace Command Window), e.g. numpy:
pip install --target=drive:\lianja\apps\example_timeclock\python3\ numpy

Note: the local installation of the Python modules causes these modules to be included when the standalone executable is generated. During App development, any required modules also need to be installed in the default location for Lianja, i.e. without a --target specified.

To check modules installed in the default location:

pip list

To check the Python path (from the Python tab):

import sys
print(sys.path)

example_timeclock.py

import sys
import types
from datetime import datetime
import Lianja
 
class myCommandbutton(Lianja.Commandbutton):
	pass
 
oform = createObject("form")
oform.resize(600, 600)
oform.closable = 1
oform.caption = "Time clock - Python"
oform.minwidth = 600
oform.minheight = 600
 
oform.addObject("ocont", "container")
ocont.margin = 10
ocont.autosize = 1
ocont.layout = "V"
ocont.backcolor = "black"
 
ocont.addObject("obadgenolab", "label")
obadgenolab.fixedheight = 24
obadgenolab.autowidth = 1
obadgenolab.alignment = "center"
obadgenolab.caption = "Enter Badge Number"
obadgenolab.backcolor = "darkgray"
obadgenolab.forecolor = "white"
obadgenolab.fontbold = 1
obadgenolab.fontsize = 10
 
ocont.addspacing(10)
ocont.addObject("obadgeno", "textbox")
obadgeno.fixedheight = 24
obadgeno.autowidth = 1
obadgeno.placeholder = "Enter your badge number, Take a Photo then CLOCK IN or CLOCK OUT"
 
ocont.addspacing(10)
ocont.addObject("obadgenolab2", "label")
obadgenolab2.fixedheight = 24
obadgenolab2.autowidth = 1
obadgenolab2.alignment = "center"
obadgenolab2.caption = "Take a Photo"
obadgenolab2.backcolor = "darkgray"
obadgenolab2.forecolor = "white"
obadgenolab2.fontbold = 1
obadgenolab2.fontsize = 10
 
ocont.addspacing(10)
ocont.addObject("ocamera", "camera") 
ocamera.autowidth = 1
ocamera.autoheight = 1
ocamera.backcolor = "black"
 
ocont.addspacing(10)
ocont.addObject("obadgenolab3", "label")
obadgenolab3.fixedheight = 24
obadgenolab3.autowidth = 1
obadgenolab3.alignment = "center"
obadgenolab3.caption = "Clock in / Clock out"
obadgenolab3.backcolor = "darkgray"
obadgenolab3.forecolor = "white"
obadgenolab3.fontbold = 1
obadgenolab3.fontsize = 10
 
ocont.addObject("ocont2", "container")
ocont2.layout = "H"
ocont2.fixedheight = 60
ocont2.backcolor = "black"
ocont2.spacing = 10
 
ocont2.addObject("obtn1", "myCommandbutton")  
obtn1.resize(60, 50)
obtn1.flat = 1
obtn1.fixedheight = 50
obtn1.caption = "CLOCK IN"
obtn1.stylesheet = "btn"
ocont2.addObject("obtn2", "myCommandbutton")  
obtn2.flat = 1
obtn2.resize(60, 50)
obtn2.fixedheight = 50
obtn2.stylesheet = "btn"
obtn2.caption = "CLOCK OUT" 
 
# event handlers
def clockin(self):
	ocamera.takePhoto()
	now = datetime.now()
	oform.showSuccessMessage("You clocked in at " + now.strftime("%m/%d/%Y %I:%M:%S %p"))
 
def clockout(self):
	ocamera.takePhoto()
	now = datetime.now()
	oform.showSuccessMessage("You clocked out at " + now.strftime("%m/%d/%Y %I:%M:%S %p"))
 
# We can dynamically bind events to custom classes in Lianja/Python
bindEvent(obtn1, clockin, "click")
bindEvent(obtn2, clockout, "click")
 
# modal form
oform.show()
Lianja.readEvents()

JavaScript

example_timeclock.js

var oform = createObject("Form");
oform.resize(600, 600);
oform.closable = 1;
oform.caption = "Time clock - JavaScript";
oform.minwidth = 600;
oform.minheight = 600;
oform.deleteonclose = 1;
 
oform.addobject("ocont", "container"); 
ocont.margin = 10;
ocont.autosize = 1;
ocont.layout = "V";
ocont.backcolor = "black";
 
ocont.addObject("obadgenolab", "label"); 
obadgenolab.fixedheight = 24;
obadgenolab.autowidth = 1;
obadgenolab.alignment = "center";
obadgenolab.caption = "Enter Badge Number";
obadgenolab.backcolor = "darkgray";
obadgenolab.forecolor = "white";
obadgenolab.fontbold = 1;
obadgenolab.fontsize = 10;
 
ocont.addspacing(10);
ocont.addObject("obadgeno", "textbox");
obadgeno.fixedheight = 24;
obadgeno.autowidth = 1;
obadgeno.placeholder = "Enter your badge number, Take a Photo then CLOCK IN or CLOCK OUT";
 
ocont.addspacing(10);
ocont.addObject("obadgenolab2", "label");
obadgenolab2.fixedheight = 24;
obadgenolab2.autowidth = 1;
obadgenolab2.alignment = "center";
obadgenolab2.caption = "Take a Photo";
obadgenolab2.backcolor = "darkgray";
obadgenolab2.forecolor = "white";
obadgenolab2.fontbold = 1;
obadgenolab2.fontsize = 10;
 
ocont.addspacing(10);
ocont.addObject("ocamera", "camera");
ocamera.autowidth = 1;
ocamera.autoheight = 1;
ocamera.backcolor = "black";
 
ocont.addspacing(10);
ocont.addObject("obadgenolab3", "label");
obadgenolab3.fixedheight = 24;
obadgenolab3.autowidth = 1;
obadgenolab3.alignment = "center";
obadgenolab3.caption = "Clock in / Clock out";
obadgenolab3.backcolor = "darkgray";
obadgenolab3.forecolor = "white";
obadgenolab3.fontbold = 1;
obadgenolab3.fontsize = 10;
 
ocont.addObject("ocont2", "container");
ocont2.layout = "H";
ocont2.fixedheight = 60;
ocont2.backcolor = "black";
ocont2.spacing = 10;
 
ocont2.addObject("obtn1", "commandbutton");  
obtn1.resize(60, 50);
obtn1.flat = 1;
obtn1.fixedheight = 50;
obtn1.caption = "CLOCK IN";
obtn1.stylesheet = "btn";
ocont2.addObject("obtn2", "commandbutton"); 
obtn2.flat = 1;
obtn2.resize(60, 50);
obtn2.fixedheight = 50;
obtn2.stylesheet = "btn";
obtn2.caption = "CLOCK OUT";  
 
// event handlers
function clockin() 
{
	ocamera.takePhoto()
	oform.showSuccessMessage("You clocked in on " + new Date().toLocaleString())
};
 
function clockout()
{
	ocamera.takePhoto();
	oform.showSuccessMessage("You clocked out on " + new Date().toLocaleString())
};
 
obtn1.click = clockin;
obtn2.click = clockout;
 
// modal form
oform.show();
 
// must put read events at the bottom so the window stays open until closed by user
read_events();

Building and Testing Standalone Executables

To build and test, switch to the Console workspace and click the 'Desktop App View' button in the Headerbar:

Sample App: example_timeclock


The Output window will show the compilation and build operations.

To build and test the other scripts in the example_timeclock App - LianjaScript (.prg), Python (.py) and JavaScript (.js) are available - just select the required scripting language in the App Settings and click the 'Desktop App View' button again.

Deploying Standalone Executables

When building a standalone executable with LianjaScript, all the .prg files in the App directory are linked together into a .src file and this is compiled.

The resulting object file is bound onto the end the Lianja runtime executable and the authenticode code signing is adjusted so as to not be affected by the application payload.

All of the supporting libraries are included in the standalone application directory.

If your application is built in Python, there is a python3 directory included which contains the python modules you have installed with pip.

To deploy, install the whole standalone application directory, e.g for the example_timeclock App the directory is:
drive:\lianja\installers\standalone\example_timeclock

and it has a single bin sub-directory containing the executable and required libraries:

drive:\lianja\installers\standalone\example_timeclock\bin

To run, the executable is:

drive:\lianja\installers\standalone\example_timeclock\bin\example_timeclock.exe

Note: In v7.0, the exe and required libraries are located in the application directory itself, e.g. example_timeclock (this has been corrected in v7.1). These need to be placed in a bin directory, either by renaming the directory to bin or by creating a bin sub-directory and copying all the other files into the new sub-directory.