4 VLT GUI Guidelines
This chapter provides guidelines on how to write GUI applications in the VLT environment.
This chapter is meant to be for the `experienced user' and collects proposed solutions to cases or problems of common interest that have been found during the development of the VLT GUI applications.
4.1 RECOMMANDATIONS
During the development of the panel editor some procedures have become obsolete therefore this chapter is a reminder to use certain procedures to improve the robustness of the GUI.
Some applications still use the `old' procedure dbRead to read database values, but this procedure does not handle properly error conditions and as consequence the application may crash. The following example shows the correct usage of panDbRead.
set attr ":PARAMS:SCALARS.scalar_int32"
# panDbRead stores the database value in the variable `value'
if {[cequal [panDbRead $attr value] FAILURE]} {
The use of seq procedures such as seq_dbreadSymbolic or seq_dbWriteSymbolic, without a proper error handling could make the application crash.
The panel editor provides higher level procedures containing a proper error handling such as panDbRead. or panDbWrite.
# Call seq_dbWriteSymbolic with error handling.
# read a database value : the current value is stored into
if {[panDbRead ":PARAMS:SCALARS.scalar_int32" value] == "FAILURE"} {
If you add `by hand' widgets (not graphic elements) in the canvas the panel editor will not be able to edit the GUI any more. (If you need to do something specific that requires widgets to be added in a specific pattern - e.g.- the widgets re-create the positioning of M1 actuators - see example 4.3.12 )
4.2 OPTIMIZATION OF PERFORMANCES
This chapter gives some suggestions on how to optimize the CPU load of a panel.
The reduction of the load can involve both the pure GUI design but also how the control programs are designed.
4.2.1 Optimization of Control Programs
The performance of the GUI applications can also depend on the design of the processes and in particular on how the control processes write data in the database.
A change on any element of a table generates an event ( this also applies for the scanning mechanism). For example if two widgets are configured with the event mechanism to display elements of a vector/table , both widgets will get an event each time the control process writes data to any location of the vector/table.
Another situation to be treated with care is when widgets are updated on "event" and corresponding database attributes are scanned-up to the WS.
For example, let's suppose to scan a 150 elements table and that the control process change 50 of them. In the worst case this can generate 150x50 events, with the good chance of killing the environment filling the message queue.
4.2.2 Optimization of panels
This will reduce the number of event produces each time the control process updates the vector/table.
Beware that the filter "on change" does not work for VECTORS and TABLE, but events are always generated "at any write" .
This will reduce the number of event produces each time the control process updates the vector/table.
This widget is designed to read a portion of a VECTOR or of a TABLE columns and displays each element in a different output widget.
4.3 EXAMPLES
4.3.1 Show the same DB value with several widgets
Sometimes there is the need to use the same DB value with different widgets. This is not possible for all combinations of widgets, in particular when it is used for input and output widgets at the same time.
They share the same variable name, but only one is connected to the database -.i.e.- for only one of the two the DB flag is set to "ON".
This is possible only using scale and listBox widgets, in that case both input and output widgets share the same variable name and both the variable's DB flag is set to "ON".
4.3.2 Change Widget Configuration
A typical application is to change the configuration parameters of a widget : the following is a simple example of a panel containing three widgets , two buttons and a bitmap. The two buttons re-configure the bitmap widget to switch between NTT.xbm to ESO.xbm. bitmaps.
Create the panel configuring the widgets according to the following table : just leave all other parameters to their default values.
Button 1 Default Show ESOBitmap showBitmap ESO Button 2 Default Show NTT Bitmap showBitmap NTT Bitmap (load the NTT.xbm bitmap) myBitmap NTTThe two buttons invoke the procedure `showBitmap' which takes as parameter the name of the bitmap : click on "Edit procedure ..." to edit the following procedure definition :
When ready click on "Register proc" to let the TCL interpreter know the new procedure definition -i.e.- after this the procedure showBitmap can be executed by the buttons.
The procedure re-configures the widget "$cv.myBitmap" to display the selected bitmap.
4.3.3 Use panel procedures in normal tcl/tk scripts.
The programmatic interface provided by the panel is designed to work within panel-applications. However it is possible to use the procedures provided by the panel in `normal' tcl/tk scripts by calling panConfigure at the beginning of the script.
4.3.4 Interaction between classContainer and classFrame
In this example we want to create two widgets (classContainer and classFrame) which have the following behavior :
- The classContainer shows two classes (class1_uifClass and class2_uifClass) according to the selected "Mode 1" or "Mode 2" .
- In addition the class Frame should also switch to class3_uifClass when "Mode 1" is selected or class4_uifClass when "Mode 2" is selected.
To make the classFrame switch according to the radioButton selection we have to configure the "-variable" option of classFrame to the name of the variable associated to the classContainer radioButtons.
The best way to do this, is to configure the classFrame in the <xxx>Init procedure of the panel, since this will take into account possible modifications to the classContainer widget name as well as those concerning the internal structure of the classContainer widget.
The statements to be added to the xxxInit procedure are :
# Get the current name of the radioButton variable
set rbVar [$cv.modeSelector getRbVariable]
# Set the "-variable" option to the correct name
$cv.frameSelector configure -variable $rbVar
4.3.5 Interaction between Menus and classFrame
In this example we want to select the class to be displayed in a classFrame through radioButtons elements in the menu bar, as follows :
- The classFrame shows two classes (class1_uifClass and class2_uifClass) according to the selected "Mode 1" or "Mode 2" .
4.3.6 Programmatic setting of "show" flag for classContainer
Sometimes there is the need to programmatically set the "show" flag of classContainer, for example when the panel starts.
4.3.7 Enabling/Disabling classContainer radioButtons.
The classContainer can have some radioButtons which are identified by an index which is ranging from 0, N-1 , where N is the total number of buttons.
4.3.8 Store data of a uifClass into the database.
Let's suppose you have a class with some input widgets whose values must be stored into the database independently from the rest of the widgets. In this case a button can be configured to call panDbWriteClass which takes all input widgets contained in a uifClass and writes them into the database ( It also work for nested classes ).
set classPath [$cv.myUifClass getClassPath]
4.3.9 Use the telescope identifier to derive an environment name.
The environment variable TCSID is the standard way to define the telescope identifier ranging from 1 to 4 , while number 0 is used in the `control model'. ( The control model is a `replica' at ESO headquarters of the HW and SW installed in Paranal )
Some subsystem environment names are named according to the telescope where they are installed -e.g - lt1m1m3 refers to the m1m3 cell subsystem of telescope 1.
Here follows the recommended code and the example assumes that :
4.3.10 Set the uifClass CWP according to a database attribute
Sometime there is the need to derive a Current Working Point (CWP) according to the current telescope setting, for example data regarding the adaptive optics are stored in different database branches according to the current telescope focus.
The goal is to have the uifClass switch automatically according to the current focus (this example comes from a TCS GUI application ) , therefore we need to :
Therefore the steps are the following.
Add in the <xxx>GlobalData procedure the code to define the db attribute where to read the value for the current focus from.
The widget is configured to get updated by events and the event script will update both the widget's value and will switch the class CWP as well.
Widget Parameter Value Widget Name currentFocus Variable :Appl_data:TCS:msw:foc.currentFocus Database Mode Event Filter != Event Script switchFocus currentFocus %A %T %D %Q
This is an example of user's defined event procedure which will keep the currentFocus widget up to date and at the same time it will switch the uifClass CWP according to the new focus.
4.3.11 Add Simple Graphic Element
The panel editor does not support the editing of any graphical element in the canvas but it does not prevent the user to add its own graphics by using directly the tcl/tk canvas statements.
In a panel all the widgets are placed on top of a canvas widgets which provides some methods to create simple graphics such as line, rectangle, oval, polygon etc ..
These statements can be executed in both <xxx>InitData or <xxx>Init procedures.
Here follows an example (for more details see [4] or the tcl/tk man pages )
4.3.12 Create specific widget layout.
If the user wants to `automatically' create and position widgets in a panel it is better to use a uifFrame (frame in the widget's palette) as `container' for the widgets otherwise the panel cannot be edited any longer.
To better understand this need we take as example what has been implemented for the M1 Engineering Interface where a set of buttons are automatically placed following the pattern of the M1 actuators. At the ned of this procedure the M1 actuators can be moved in any position of the panel.
2. Create a canvas within the frame. The code is added to the <xxx>Init because it must be executed after the creation of the standard `frame' widget.
Quadralay Corporation http://www.webworks.com Voice: (512) 719-3399 Fax: (512) 719-3606 sales@webworks.com |