Difference between revisions of "Working with Forms in Lianja"
Yvonne.milne (Talk | contribs) |
Yvonne.milne (Talk | contribs) (→See Also) |
||
(25 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
− | + | ==See Also== | |
+ | [[Attributes]], [[Canvas Designer]], [[Custom Delegates]], [[Form|Form Framework Class]], [[Lianja Methods|Lianja System Object Methods]], [[Page Builder Assistant]], [[Standalone Executables on Windows]], [[TabView Sections]], [[TabView Section Attributes]], [[Visual Components|Working with Visual Components]], [[:Category:WebView Based Sections|WebView Based Sections]] | ||
+ | |||
==Overview== | ==Overview== | ||
− | Lianja provides the ability to visually create | + | Lianja provides the ability to visually create Forms that will run on Desktop, Web and Mobile devices. |
− | If you come from a Visual FoxPro background this is the equivalent of the Visual FoxPro | + | If you come from a Visual FoxPro background this is the equivalent of the Visual FoxPro Form Designer. |
[[{{ns:file}}:working_with_forms1.png|800px|left|border|link={{filepath:working_with_forms1.png}}|Working with Forms in Lianja]] | [[{{ns:file}}:working_with_forms1.png|800px|left|border|link={{filepath:working_with_forms1.png}}|Working with Forms in Lianja]] | ||
<br clear=all> | <br clear=all> | ||
− | You can visually build | + | You can visually build Forms 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 | * LianjaScript/VFP | ||
* Python | * Python | ||
Line 14: | Line 16: | ||
* Typescript | * Typescript | ||
− | This article builds a | + | This article builds a Form that uses [[:Category:Python_Scripting|Python]] as its [[App_Settings#Delegates|scripting language]]. |
Forms are based on a [[TabView Sections|TabView Section]] which contains [[Canvas Designer|Canvas]], [[Grid_Section_Attributes|Grid]] or [[:Category:WebView Based Sections|WebView Based Sections]] in its tabs. | Forms are based on a [[TabView Sections|TabView Section]] which contains [[Canvas Designer|Canvas]], [[Grid_Section_Attributes|Grid]] or [[:Category:WebView Based Sections|WebView Based Sections]] in its tabs. | ||
Line 26: | Line 28: | ||
* A statusbar | * A statusbar | ||
− | ==Creating a new | + | ==Creating a new Form== |
− | You can create a new | + | You can create a new Form from the [[:Category:Home_Workspace|Home workspace]]: |
[[{{ns:file}}:working_with_forms2.png|800px|left|border|link={{filepath:working_with_forms2.png}}|Working with Forms in Lianja]] | [[{{ns:file}}:working_with_forms2.png|800px|left|border|link={{filepath:working_with_forms2.png}}|Working with Forms in Lianja]] | ||
Line 43: | Line 45: | ||
</code> | </code> | ||
− | The | + | The Form will be created in its own App as a [[TabView Sections|TabView Section]] with one [[Canvas Designer|Canvas]] section Tab. You can then add other [[Canvas Designer|Canvas]], [[Grid_Section_Attributes|Grid]], or [[:Category:WebView Based Sections|WebView Based Sections]] to it. |
− | Once the new | + | Once the new Form is created you should specify the [[App_Settings#Delegates|scripting language]] that you want to use for the delegates in the Form: |
[[{{ns:file}}:working_with_forms4.png|800px|left|border|link={{filepath:working_with_forms4.png}}|Working with Forms in Lianja]] | [[{{ns:file}}:working_with_forms4.png|800px|left|border|link={{filepath:working_with_forms4.png}}|Working with Forms in Lianja]] | ||
<br clear=all> | <br clear=all> | ||
− | You can then [[TabView_Sections#Creating_a_TabView_Content_Section|add new tabs to the | + | You can then [[TabView_Sections#Creating_a_TabView_Content_Section|add new tabs to the Form by clicking on the "+" icon in the TabView TabBar]]. |
[[{{ns:file}}:working_with_forms5.png|800px|left|border|link={{filepath:working_with_forms5.png}}|Working with Forms in Lianja]] | [[{{ns:file}}:working_with_forms5.png|800px|left|border|link={{filepath:working_with_forms5.png}}|Working with Forms in Lianja]] | ||
Line 60: | Line 62: | ||
<br clear=all> | <br clear=all> | ||
− | ==Modifying an existing | + | ==Modifying an existing Form== |
− | You can modify an existing | + | You can modify an existing Form from the [[Visual_Components#Visual_Component.2FForm_Manager|Visual Component/Form Manager]]: |
[[{{ns:file}}:working_with_forms7.png|800px|left|border|link={{filepath:working_with_forms7.png}}|Working with Forms in Lianja]] | [[{{ns:file}}:working_with_forms7.png|800px|left|border|link={{filepath:working_with_forms7.png}}|Working with Forms in Lianja]] | ||
<br clear=all> | <br clear=all> | ||
− | or from the | + | or from the [[:Category:Command_Window_CLI|Command window]] or the [[:Category:Console_Workspace|Console workspace]] by typing: |
<code lang="recital"> | <code lang="recital"> | ||
Line 72: | Line 74: | ||
</code> | </code> | ||
− | ==The lifecycle of a | + | ==The lifecycle of a Form== |
− | During development you customize the | + | During development you customize the Forms and activate them by clicking the 'Desktop App View' icon: |
[[{{ns:file}}:working_with_forms8.png|800px|left|border|link={{filepath:working_with_forms8.png}}|Working with Forms in Lianja]] | [[{{ns:file}}:working_with_forms8.png|800px|left|border|link={{filepath:working_with_forms8.png}}|Working with Forms in Lianja]] | ||
Line 89: | Line 91: | ||
</pre> | </pre> | ||
− | or, to | + | or, to activate ''app:/form_name/form_name'' |
<pre> | <pre> | ||
Lianja.showForm("Window title", "form_name") | Lianja.showForm("Window title", "form_name") | ||
</pre> | </pre> | ||
− | or, to activate | + | or, to activate ''app:/form_name/form_name'' with the default window title |
<pre> | <pre> | ||
Lianja.showForm("form_name") | Lianja.showForm("form_name") | ||
</pre> | </pre> | ||
− | When a | + | When a Form is activated, the 'initform' delegate is called. This is where you can open a database and its tables and dynamically create the menubar and the toolbar. |
− | In this delegate thisform references the | + | In this delegate ''thisform'' references the Form itself. |
You can reference the menubar, toolbar and actionbar like this: | You can reference the menubar, toolbar and actionbar like this: | ||
Line 112: | Line 114: | ||
==Creating the menubar dynamically== | ==Creating the menubar dynamically== | ||
− | The quickest way to layout the Menubar is to assign a layout string to the menubarlayout property like this: | + | The quickest way to layout the Menubar is to assign a layout string to the ''menubarlayout'' property like this: |
− | + | <pre>thisform.menubarlayout = "File(Open...,Save),Reports(Customers,Orders,Order Details)"</pre> | |
Note that a menuitem may also have an icon associated with it. e.g. | Note that a menuitem may also have an icon associated with it. e.g. | ||
Line 120: | Line 122: | ||
<pre>lib:/images/mycustomersicon.png@Customers</pre> | <pre>lib:/images/mycustomersicon.png@Customers</pre> | ||
− | When you click a menuitem the menubarclick delegate of the | + | When you click a menuitem the menubarclick delegate of the Form is called with the fullpath of the menuitem clicked. The fullpath is a | separated list. |
− | e.g | + | e.g. |
<pre>"Reports|Customers|Save as XML..."</pre> | <pre>"Reports|Customers|Save as XML..."</pre> | ||
Line 135: | Line 137: | ||
thisform.menubar = 0 | thisform.menubar = 0 | ||
</pre> | </pre> | ||
+ | |||
==Creating the Toolbar dynamically== | ==Creating the Toolbar dynamically== | ||
− | The quickest way to layout the Toolbar is to assign a layout string to the toolbarlayout property like this: | + | The quickest way to layout the Toolbar is to assign a layout string to the ''toolbarlayout'' property like this: |
<pre>thisform.toolbarlayout = "lib:/images/mycustomobersicon.png@Customers,lib:/images/myordersicon.png@Orders"</pre> | <pre>thisform.toolbarlayout = "lib:/images/mycustomobersicon.png@Customers,lib:/images/myordersicon.png@Orders"</pre> | ||
− | When an icon is clicked the | + | When an icon is clicked the Tooltip e.g. "Customers" is passed as an argument to the toolbarclick delegate. |
You can hide and show the toolbar dynamically using: | You can hide and show the toolbar dynamically using: | ||
Line 163: | Line 166: | ||
</pre> | </pre> | ||
− | This is typically done in the toolbarclick delegate as you hide and show | + | This is typically done in the toolbarclick delegate as you hide and show tabs of the TabView container in the Form. |
==Referencing UI controls dynamically== | ==Referencing UI controls dynamically== | ||
Line 182: | Line 185: | ||
<pre>el = thisform.get ( cname )</pre> | <pre>el = thisform.get ( cname )</pre> | ||
− | When referencing objects by name you should use the fully qualified name e.g. "page1.section1.field1". All objects in the | + | When referencing objects by name you should use the fully qualified name e.g. "page1.section1.field1". All objects in the Form and its child containers will be introspected and an object reference to the UI control will be returned. |
==Dynamically setting attributes== | ==Dynamically setting attributes== | ||
Line 193: | Line 196: | ||
<pre>el.text = "hello world"</pre> | <pre>el.text = "hello world"</pre> | ||
− | Each time a | + | Each time a Form is activate, the activated delegate is called. Each time it is deactivated the deactive delegate is called. |
==Dynamically binding delegates== | ==Dynamically binding delegates== | ||
− | Delegates are normally specified in the Assistant (or the Attributes) for a UI element. | + | Delegates are normally specified in the [[Page Builder Assistant|Assistant]] (or the [[Attributes]]) for a UI element. |
If required you can dynamically bind delegates like this: | If required you can dynamically bind delegates like this: | ||
Line 232: | Line 235: | ||
==Understanding events and delegates== | ==Understanding events and delegates== | ||
− | Custom Forms are built in the Canvas Designer. You drag and drop UI controls onto the canvas. Clicking on the border of a UI control (a formitem in Lianja terminology) selects the control and its caption in the | + | Custom Forms are built in the [[Canvas Designer]]. You drag and drop UI controls onto the canvas. Clicking on the border of a UI control (a formitem in Lianja terminology) selects the control and its caption in the [[Page Builder Assistant|Assistant]] and the [[Attributes]]. You can then customize the appearance and the behavior of the UI control. |
− | A UI control handles events e.g. Click of a CommandButton, InteractiveChange of a ComboBox or Change of text in a TextBox using | + | A UI control handles events e.g. ''Click'' of a CommandButton, ''InteractiveChange'' of a ComboBox or ''Change'' of text in a TextBox using 'Delegates'. [[Custom Delegates|Delegates]] are scripting language independent event handlers. |
− | You edit delegates by selecting them in the | + | You edit delegates by selecting them in the 'Delegates' combobox of the [[Page Builder Assistant|Assistant]] or in the [[Attributes]]. |
− | When an event occurs e.g. | + | When an event occurs e.g. change of the text in a TextBox, the event delegate is executed. In the event delegate you can reference the UI control (the formitem) that the event occurred for using: |
− | Python: | + | '''Python:''' |
− | In Python use self. | + | In Python use ''self''. |
− | LianjaScript: | + | '''LianjaScript:''' |
− | In LianjaScript/VFP use this. | + | In LianjaScript/VFP use ''this''. |
− | JavaScript: | + | '''JavaScript:''' |
− | In JavaScript use this. | + | In JavaScript use ''this''. |
− | You can get an object reference to other UI controls on the | + | You can get an object reference to other UI controls on the Form using: |
− | thisform.get("page1.section1.formitem1") | + | <pre>thisform.get("page1.section1.formitem1")</pre> |
or | or | ||
− | thisform.controls("page1.section1.formitem1") | + | <pre>thisform.controls("page1.section1.formitem1")</pre> |
==Handling click events from the menubar== | ==Handling click events from the menubar== | ||
− | You normally specify a menubarclick delegate for the | + | You normally specify a ''menubarclick'' delegate for the Form in the [[TabView Section Attributes]]. |
− | When you click a menubar item the menubarclick delegate of the | + | When you click a menubar item the ''menubarclick'' delegate of the Form is called with the fullpath of the menuitem clicked. |
− | e.g | + | The fullpath is a | separated list, e.g. |
− | "Reports|Customers|Save as XML..." | + | <pre>"Reports|Customers|Save as XML..."</pre> |
− | You can edit the menubarclick delegate in the Canvas Designer attributes. | + | You can edit the menubarclick delegate in the [[Canvas Designer]] attributes. |
− | Python: | + | '''Python:''' |
− | + | <code lang="python"> | |
def mymenubarclick(action): | def mymenubarclick(action): | ||
action = action.lower() | action = action.lower() | ||
Line 281: | Line 284: | ||
</code> | </code> | ||
− | LianjaScript: | + | '''LianjaScript:''' |
− | + | <code lang="recital"> | |
proc mymenubarclick(action) | proc mymenubarclick(action) | ||
action = lower(action) | action = lower(action) | ||
Line 295: | Line 298: | ||
</code> | </code> | ||
− | JavaScript: | + | '''JavaScript:''' |
− | + | <code lang="javascript"> | |
function mymenubarclick(action) | function mymenubarclick(action) | ||
{ | { | ||
Line 314: | Line 317: | ||
==Handling click events from the toolbar== | ==Handling click events from the toolbar== | ||
− | You normally specify a toolbarclick delegate for the | + | You normally specify a ''toolbarclick'' delegate for the Form in the [[TabView Section Attributes]]. |
− | When you click an toolbar button the toolbarclick delegate of the | + | When you click an toolbar button the ''toolbarclick'' delegate of the Form is called with the text of the tool button tooltip that was clicked. In this delegate you typically show Tab panels containing the UI elements of your Form. |
− | + | '''Python:''' | |
− | + | <code lang="python"> | |
− | + | ||
− | + | ||
def mytoolbarclick(action): | def mytoolbarclick(action): | ||
action = action.lower() | action = action.lower() | ||
Line 333: | Line 334: | ||
</code> | </code> | ||
− | LianjaScript: | + | '''LianjaScript:''' |
− | + | <code lang="recital"> | |
proc mytoolbarclick(action) | proc mytoolbarclick(action) | ||
// place your code here | // place your code here | ||
Line 343: | Line 344: | ||
</code> | </code> | ||
− | JavaScript: | + | '''JavaScript:''' |
− | + | <code lang="javascript"> | |
function mytoolbarclick(action) | function mytoolbarclick(action) | ||
{ | { | ||
Line 355: | Line 356: | ||
==Handling click events from the actionbar== | ==Handling click events from the actionbar== | ||
− | You can specify | + | You can specify an ''actionbarclick'' delegate for the Form in the TabView section attributes. If the TabView has a recordsource data navigation is automatically handled for the Form without any coding requirement. See [[#Data Binding|Data Binding]] below. |
− | When you click an actionbar button the actionbarclick delegate of the | + | When you click an actionbar button the ''actionbarclick'' delegate of the Form is called with the text of the tool button tooltip that was clicked. In this delegate you can navigate, add, update and delete records. |
− | + | '''Python:''' | |
− | + | <code lang="python"> | |
− | + | ||
− | + | ||
def myactionbarclick(action): | def myactionbarclick(action): | ||
action = action.lower() | action = action.lower() | ||
Line 390: | Line 389: | ||
</code> | </code> | ||
− | LianjaScript: | + | '''LianjaScript:''' |
− | + | <code lang="recital"> | |
proc myactionbarclick(action) | proc myactionbarclick(action) | ||
// place your code here | // place your code here | ||
Line 400: | Line 399: | ||
</code> | </code> | ||
− | JavaScript: | + | '''JavaScript:''' |
− | + | <code lang="javascript"> | |
function myactionbarclick(action) | function myactionbarclick(action) | ||
{ | { | ||
Line 413: | Line 412: | ||
You can update the recno and the reccount in the actionbar like like: | You can update the recno and the reccount in the actionbar like like: | ||
− | + | <pre>thisform.actionbar.recno = nExpr | |
− | thisform.actionbar.reccount = nExpr</ | + | thisform.actionbar.reccount = nExpr</pre> |
You can update the statusbar like this: | You can update the statusbar like this: | ||
− | + | <pre>thisform.message = "Hello world"</pre> | |
You can provide user feedback like this: | You can provide user feedback like this: | ||
− | + | <pre>thisform.showSuccessMessage("Operation succeeded") | |
thisform.showErrorMessage("Operation failed") | thisform.showErrorMessage("Operation failed") | ||
thisform.showWarningMessage("Operation succeeded with warnings") | thisform.showWarningMessage("Operation succeeded with warnings") | ||
thisform.showInfoMessage("Operation is being performed. Please wait.") | thisform.showInfoMessage("Operation is being performed. Please wait.") | ||
− | thisform.hideMessage()</ | + | thisform.hideMessage()</pre> |
==Data binding== | ==Data binding== | ||
− | Specifying a | + | Specifying a [[Data_Attributes#Data_source|Data source]] in the formitem attributes in the Canvas Designer binds a control to a table.column. |
− | In the initform delegate for the | + | In the ''initform'' delegate for the Form you can assign a 'database!table' or a SQL statement to the ''recordsource'' property of the TabView. |
− | As you navigate records in the | + | As you navigate records in the Form by clicking the icons in the actionbar, the bound controls will automatically be refreshed on the Form. |
All CRUD (Create, Read, Update, Delete) operations will be handled automatically for you. | All CRUD (Create, Read, Update, Delete) operations will be handled automatically for you. | ||
− | Alternatively, you can call the recordsource data navigation methods manually on the container if you have your own navigation controls on the | + | Alternatively, you can call the recordsource data navigation methods manually on the container if you have your own navigation controls on the Form as custom commandbuttons. |
The relevant methods available on a container are: | The relevant methods available on a container are: | ||
− | add() | + | * add() |
− | delete() | + | * delete() |
− | first() | + | * first() |
− | next() | + | * next() |
− | previous() | + | * previous() |
− | last() | + | * last() |
− | save() | + | * save() |
− | cancel() | + | * cancel() |
− | refresh() | + | * refresh() |
==Responsive UI using anchors== | ==Responsive UI using anchors== | ||
− | The UI elements (formitems) that you add to Canvases in your | + | The UI elements (formitems) that you add to Canvases in your Form are not responsive to changes in geometry of screen sizes (e.g. phones, tablets, maximizing the Form window etc.). To make your Forms responsive you can use [[Data_Attributes#Anchor|anchors]] which you will find in the [[Page Builder Assistant|Assistant]]. |
− | You can check the top, | + | You can check the top, bottom, left and right [[Data_Attributes#Anchor|anchors]] to make the UI control adjust its geometry and respond to changes in display geometry. |
[[{{ns:file}}:working_with_forms9.png|800px|left|border|link={{filepath:working_with_forms9.png}}|Working with Forms in Lianja]] | [[{{ns:file}}:working_with_forms9.png|800px|left|border|link={{filepath:working_with_forms9.png}}|Working with Forms in Lianja]] | ||
<br clear=all> | <br clear=all> | ||
− | |||
==Dynamically referencing UI controls in delegates== | ==Dynamically referencing UI controls in delegates== | ||
− | The best way to reference UI controls on | + | The best way to reference UI controls on Forms is to use the fully qualified name with [[Lianja_Methods#Object_Referencing|Lianja.get()]]. This works in LianjaScript, Python and JavaScript, e.g. |
− | + | ||
− | e.g. | + | |
<pre>Lianja.get("page1.section1.field1").text = "Hello world"</pre> | <pre>Lianja.get("page1.section1.field1").text = "Hello world"</pre> | ||
− | + | ==Building a standalone Form executable== | |
− | ==Building a standalone | + | You can build a Form as a standalone executable. |
− | You can build a | + | |
See [[Standalone Executables on Windows]] for details. | See [[Standalone Executables on Windows]] for details. | ||
− | ==Using | + | ==Using Forms in Web and Mobile Apps== |
Forms and Components are generated when you save an App. The Form is also saved as a component that can be used in Web Apps with [[Lianja_Methods#showDialog|Lianja.showDialog()]], [[Lianja_Methods#showDialogPanel|Lianja.showDialogPanel()]] and [[Lianja_Methods#showDialogForm|Lianja.showDialogForm()]]. To use this in Web Apps they should be developed in JavaScript or Python. | Forms and Components are generated when you save an App. The Form is also saved as a component that can be used in Web Apps with [[Lianja_Methods#showDialog|Lianja.showDialog()]], [[Lianja_Methods#showDialogPanel|Lianja.showDialogPanel()]] and [[Lianja_Methods#showDialogForm|Lianja.showDialogForm()]]. To use this in Web Apps they should be developed in JavaScript or Python. | ||
− | Forms are based in [[TabView Sections]] inside an App with the same name as the | + | Forms are based in [[TabView Sections]] inside an App with the same name as the Form. The App, if JavaScript or Python is the selected scripting language, will also run in the Web or can be generated as an [[:Category:Electron_Apps|Electron App]] or (coming soon) a React Native mobile App. |
+ | |||
+ | [[Category:Visual FoxPro Scripting]] | ||
+ | [[Category:JavaScript Scripting]] | ||
+ | [[Category:Python Scripting]] |
Latest revision as of 08:15, 12 April 2024
Contents
- 1 See Also
- 2 Overview
- 3 Creating a new Form
- 4 Modifying an existing Form
- 5 The lifecycle of a Form
- 6 Creating the menubar dynamically
- 7 Creating the Toolbar dynamically
- 8 Hiding and showing the Actionbar dynamically
- 9 Referencing UI controls dynamically
- 10 Dynamically setting attributes
- 11 Dynamically binding delegates
- 12 Understanding events and delegates
- 13 Handling click events from the menubar
- 14 Handling click events from the toolbar
- 15 Handling click events from the actionbar
- 16 Data binding
- 17 Responsive UI using anchors
- 18 Dynamically referencing UI controls in delegates
- 19 Building a standalone Form executable
- 20 Using Forms in Web and Mobile Apps
See Also
Attributes, Canvas Designer, Custom Delegates, Form Framework Class, Lianja System Object Methods, Page Builder Assistant, Standalone Executables on Windows, TabView Sections, TabView Section Attributes, Working with Visual Components, WebView Based Sections
Overview
Lianja provides the ability to visually create Forms that will run on Desktop, Web and Mobile devices.
If you come from a Visual FoxPro background this is the equivalent of the Visual FoxPro Form Designer.
You can visually build Forms 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
This article builds a Form that uses Python as its scripting language.
Forms are based on a TabView Section which contains Canvas, Grid or WebView Based Sections in its tabs.
Forms can be displayed as a modal or non modal dialog.
Forms can optionally contain the following (TabView Section attributes accessed in the Page Builder Assistant):
- A menubar
- A toolbar
- An actionbar
- A statusbar
Creating a new Form
You can create a new Form from the Home workspace:
or alternatively from the Develop menu:
or from the Command window or the Console workspace by typing using the CLI:
create form [<form_name>]
The Form will be created in its own App as a TabView Section with one Canvas section Tab. You can then add other Canvas, Grid, or WebView Based Sections to it.
Once the new Form is created you should specify the scripting language that you want to use for the delegates in the Form:
You can then add new tabs to the Form by clicking on the "+" icon in the TabView TabBar.
Note that you can 'Hide TabBar' in the TabView attributes and programatically show Tab Panels (typically from the menubar or the toolbar) e.g.
Modifying an existing Form
You can modify an existing Form from the Visual Component/Form Manager:
or from the Command window or the Console workspace by typing:
modify form [<form_name>]
The lifecycle of a Form
During development you customize the Forms and activate them by clicking the 'Desktop App View' icon:
In code, Forms are activated (made visible) using Lianja.showForm():
Lianja.showForm("Window title", "component:/mycomponents/form_name")
or
Lianja.showForm("Window title", "app:/form_name/form_name")
or, to activate app:/form_name/form_name
Lianja.showForm("Window title", "form_name")
or, to activate app:/form_name/form_name with the default window title
Lianja.showForm("form_name")
When a Form is activated, the 'initform' delegate is called. This is where you can open a database and its tables and dynamically create the menubar and the toolbar.
In this delegate thisform references the Form itself.
You can reference the menubar, toolbar and actionbar like this:
thisform.menubar thisform.toolbar thisform.actionbar
The quickest way to layout the Menubar is to assign a layout string to the menubarlayout property like this:
thisform.menubarlayout = "File(Open...,Save),Reports(Customers,Orders,Order Details)"
Note that a menuitem may also have an icon associated with it. e.g.
lib:/images/mycustomersicon.png@Customers
When you click a menuitem the menubarclick delegate of the Form is called with the fullpath of the menuitem clicked. The fullpath is a | separated list.
e.g.
"Reports|Customers|Save as XML..."
You can hide and show the menubar dynamically using:
thisform.menubar = 1
or
thisform.menubar = 0
Creating the Toolbar dynamically
The quickest way to layout the Toolbar is to assign a layout string to the toolbarlayout property like this:
thisform.toolbarlayout = "lib:/images/mycustomobersicon.png@Customers,lib:/images/myordersicon.png@Orders"
When an icon is clicked the Tooltip e.g. "Customers" is passed as an argument to the toolbarclick delegate.
You can hide and show the toolbar dynamically using:
thisform.toolbar = 1
or
thisform.toolbar = 0
Hiding and showing the Actionbar dynamically
You can hide and show the actionbar dynamically using:
thisform.actionbar = 1
or
thisform.actionbar = 0
This is typically done in the toolbarclick delegate as you hide and show tabs of the TabView container in the Form.
Referencing UI controls dynamically
You can dynamically reference UI controls in the Form like this:
otabview = thisform.controls( 1 )
You dynamically reference UI elements in the Form by by objectname using:
el = thisform.controls ( cname )
or
el = thisform.getElementByID ( cname )
or
el = thisform.get ( cname )
When referencing objects by name you should use the fully qualified name e.g. "page1.section1.field1". All objects in the Form and its child containers will be introspected and an object reference to the UI control will be returned.
Dynamically setting attributes
You can dynamically reference the attributes of a UI element using:
el.attribute = expression
e.g
el.text = "hello world"
Each time a Form is activate, the activated delegate is called. Each time it is deactivated the deactive delegate is called.
Dynamically binding delegates
Delegates are normally specified in the Assistant (or the Attributes) for a UI element.
If required you can dynamically bind delegates like this:
Python:
def myafterclose(self): # place your code here pass thisform.afterclose = myafterclose
LianjaScript:
proc myafterclose() // place your code here endproc thisform.afterclose = myafterclose
JavaScript:
function myafterclose() { // place your code here }; thisform.afterclose = myafterclose;
Understanding events and delegates
Custom Forms are built in the Canvas Designer. You drag and drop UI controls onto the canvas. Clicking on the border of a UI control (a formitem in Lianja terminology) selects the control and its caption in the Assistant and the Attributes. You can then customize the appearance and the behavior of the UI control.
A UI control handles events e.g. Click of a CommandButton, InteractiveChange of a ComboBox or Change of text in a TextBox using 'Delegates'. Delegates are scripting language independent event handlers.
You edit delegates by selecting them in the 'Delegates' combobox of the Assistant or in the Attributes.
When an event occurs e.g. change of the text in a TextBox, the event delegate is executed. In the event delegate you can reference the UI control (the formitem) that the event occurred for using:
Python:
In Python use self.
LianjaScript:
In LianjaScript/VFP use this.
JavaScript:
In JavaScript use this.
You can get an object reference to other UI controls on the Form using:
thisform.get("page1.section1.formitem1")
or
thisform.controls("page1.section1.formitem1")
You normally specify a menubarclick delegate for the Form in the TabView Section Attributes.
When you click a menubar item the menubarclick delegate of the Form is called with the fullpath of the menuitem clicked.
The fullpath is a | separated list, e.g.
"Reports|Customers|Save as XML..."
You can edit the menubarclick delegate in the Canvas Designer attributes.
Python:
def mymenubarclick(action): action = action.lower() if (action == "file|open..."): # handle action pass thisform.menubarclick = mymenubarclick
LianjaScript:
proc mymenubarclick(action) action = lower(action) if action = "something" // handle action elseif action = "something else" // handle action endif endproc thisform.menubarclick = mymenubarclick
JavaScript:
function mymenubarclick(action) { action = lower(action); if action == "something" { // handle action } else if action == "something else" { // handle action } } thisform.menubarclick = mymenubarclick;
Handling click events from the toolbar
You normally specify a toolbarclick delegate for the Form in the TabView Section Attributes.
When you click an toolbar button the toolbarclick delegate of the Form is called with the text of the tool button tooltip that was clicked. In this delegate you typically show Tab panels containing the UI elements of your Form.
Python:
def mytoolbarclick(action): action = action.lower() if (action == "something"): # handle action elif (action == "something else"): # handle action thisform.toolbarclick = mytoolbarclick
LianjaScript:
proc mytoolbarclick(action) // place your code here endproc thisform.toolbarclick = mytoolbarclick
JavaScript:
function mytoolbarclick(action) { // place your code here }; thisform.toolbarclick = mytoolbarclick;
Handling click events from the actionbar
You can specify an actionbarclick delegate for the Form in the TabView section attributes. If the TabView has a recordsource data navigation is automatically handled for the Form without any coding requirement. See Data Binding below.
When you click an actionbar button the actionbarclick delegate of the Form is called with the text of the tool button tooltip that was clicked. In this delegate you can navigate, add, update and delete records.
Python:
def myactionbarclick(action): action = action.lower() if (action == "add"): # handle Add action elif (action == "delete"): # handle Delete action elif (action == "refresh"): # handle Refresh action elif (action == "first"): # handle First action elif (action == "previous"): # handle Prev action elif (action == "next"): # handle Next action elif (action == "last"): # handle Last action elif (action == "edit"): # handle Edit action elif (action == "save"): # handle Save action elif (action == "cancel"): # handle Cancel action thisform.actionbarclick = myactionbarclick
LianjaScript:
proc myactionbarclick(action) // place your code here endproc thisform.actionbarclick = myactionbarclick
JavaScript:
function myactionbarclick(action) { // place your code here }; thisform.actionbarclick = myactionbarclick;
You can update the recno and the reccount in the actionbar like like:
thisform.actionbar.recno = nExpr thisform.actionbar.reccount = nExpr
You can update the statusbar like this:
thisform.message = "Hello world"
You can provide user feedback like this:
thisform.showSuccessMessage("Operation succeeded") thisform.showErrorMessage("Operation failed") thisform.showWarningMessage("Operation succeeded with warnings") thisform.showInfoMessage("Operation is being performed. Please wait.") thisform.hideMessage()
Data binding
Specifying a Data source in the formitem attributes in the Canvas Designer binds a control to a table.column.
In the initform delegate for the Form you can assign a 'database!table' or a SQL statement to the recordsource property of the TabView.
As you navigate records in the Form by clicking the icons in the actionbar, the bound controls will automatically be refreshed on the Form.
All CRUD (Create, Read, Update, Delete) operations will be handled automatically for you.
Alternatively, you can call the recordsource data navigation methods manually on the container if you have your own navigation controls on the Form as custom commandbuttons.
The relevant methods available on a container are:
- add()
- delete()
- first()
- next()
- previous()
- last()
- save()
- cancel()
- refresh()
Responsive UI using anchors
The UI elements (formitems) that you add to Canvases in your Form are not responsive to changes in geometry of screen sizes (e.g. phones, tablets, maximizing the Form window etc.). To make your Forms responsive you can use anchors which you will find in the Assistant.
You can check the top, bottom, left and right anchors to make the UI control adjust its geometry and respond to changes in display geometry.
Dynamically referencing UI controls in delegates
The best way to reference UI controls on Forms is to use the fully qualified name with Lianja.get(). This works in LianjaScript, Python and JavaScript, e.g.
Lianja.get("page1.section1.field1").text = "Hello world"
Building a standalone Form executable
You can build a Form as a standalone executable.
See Standalone Executables on Windows for details.
Using Forms in Web and Mobile Apps
Forms and Components are generated when you save an App. The Form is also saved as a component that can be used in Web Apps with Lianja.showDialog(), Lianja.showDialogPanel() and Lianja.showDialogForm(). To use this in Web Apps they should be developed in JavaScript or Python.
Forms are based in TabView Sections inside an App with the same name as the Form. The App, if JavaScript or Python is the selected scripting language, will also run in the Web or can be generated as an Electron App or (coming soon) a React Native mobile App.