View RSS Feed

LianjaDev

HOWTO Build standalone executables in Lianja on Windows

Rate this Entry
Lianja provides the ability to build standalone executables on Windows.

This has been a popular request, so we have added in this functionality.

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.

This functionality is primarily for building small GUI Apps not for business Apps running under the Lianja App Center under the control of Permissions and Roles.

After installing Lianja 7.0 (beta or later).

Open the example_timeclock app which is included with Lianja 7.0.

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.

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.

Unsurprisingly there is very little code required to build this App and very few differences between the code for LianjaScript, Python and JavaScript due to the brevity (low-Code) of the Lianja UI Framework usage in all supported Scripting languages.

Building standalone LianjaScript executables


Let's look at the LianjaScript code.

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

Code:
local oform = createObject("Form")
oform.resize(600, 600)
oform.closable = 1
oform.caption = "Time clock"
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"
ocamera.stop()

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 " + time())
endproc

proc clockout()
    ocamera.takePhoto()
    thisform.showSuccessMessage("You clocked out on " + dtoc(date()) + " at " + time())
endproc

// dynamically assign the click events for the "Clock in" and "Clock out" commandbuttons
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 standalone Python executables

Upgrading pip to the latest version

Open a command prompt.

Code:
cd x:\lianja\bin
python -m pip install --upgrade pip --no-warn-script-location
In the console workspace , create the python3 directory to contain the modules local to the App

Code:
mkdir python3
Installing local python modules in the console workspace (you can now use pip in the Lianja/VFP tab)

Specifying the --target command line switch installs the Python modules local to your App so you can import them directly.

e.g.

import numpy

Code:
set backticks on
pip install --target=`cd`\python3\ numpy
Let's look at the Python code.

Code:
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"
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"
ocamera.minheight = 400
ocamera.stop()

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 %H:%M:%S"))

def clockout(self):
   ocamera.takePhoto()
   now = datetime.now()
   oform.showSuccessMessage("You clocked out at " + now.strftime("%m/%d/%Y %H:%M:%S"))

# We can dynamically bind events to custom classes in Lianja/Python using the new bindEvent() build-in Lianja/Python function
bindEvent(obtn1, clockin, "click")
bindEvent(obtn2, clockout, "click")

# modal form
oform.show()

# read_events() is the equivalent  of READ EVENTS in Lianja Script
read_events()
Building standlone JavaScript executables

Code:
var oform = createObject("Form");
oform.resize(600, 600);
oform.closable = 1;
oform.caption = "Time clock";
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";
//ocamera.stop()

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())
};

// we can assign event handlers like this in JavaScript
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();
Howto build a standalone executable

1. Select the scripting language in the App settings

Click image for larger version. 

Name:	Screen Shot 2022-01-04 at 1.06.30 PM.jpg 
Views:	1486 
Size:	50.2 KB 
ID:	2720

2. Check "Standalone" in the UI Presentation rules of the App Settings.

Click image for larger version. 

Name:	Screen Shot 2022-01-04 at 1.07.37 PM.png 
Views:	1350 
Size:	52.7 KB 
ID:	2721

3. Write the "main" script with the same name as the App. In this case example_timeclock.prg or example_timeclock.js or example_timeclock.py. (See code above). You can switch the "Scripting language" in the App settings to test each one.

4. Click the "Desktop App View" icon in the top right of the App Builder window. The standalone executable will be built and run externally.

Click image for larger version. 

Name:	Screen Shot 2022-01-04 at 1.30.01 PM.jpg 
Views:	1496 
Size:	65.1 KB 
ID:	2722

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 Qt libraries etc are included in the standalone application directory.

In this case:

x:\lianja\installers\standalone\example_timeclock

If your application is built in Python there is a python3 directory included which contains the python modules you have installed with pip. This enables the application to be installed anywhere and run by executing the executable (in this case) example_timeclock.exe.

You can study this folder structure in file explorer.

Submit "HOWTO Build standalone executables in Lianja on Windows" to Google Submit "HOWTO Build standalone executables in Lianja on Windows" to Facebook Submit "HOWTO Build standalone executables in Lianja on Windows" to Twitter

Updated 2024-02-05 at 23:17 by barrymavin

Tags: None Add / Edit Tags
Categories
ProCode

Comments

  1. cchsr's Avatar
    This is great now we can have the freedom to build a lot of stand alone exe's.
Journey into the Cloud
Join us