When non modal forms were first introduced with UNIFACE version 7 I wondered how I could use this new ability to have several different forms active at the same time, and to switch focus from one to the other just by clicking the mouse. After converting my sample application from v6 to v7 and doing a little experimentation I soon found the answer. Firstly, let me identify Golden Rule #1 regarding non-modal forms:
Now let us take the scenario where I have a parent form which contains multiple occurrences of an entity, and which has a series of command buttons which activate a different child form. I start with an empty parent form (LIST1), then select the child form which adds a new entry (ADD1).
Form ADD1 appears, allowing me to fill in its details and press the STORE button. ADD1 updates the database, sends a message to its parent saying 'I have just added a new record', then clears its own screen ready for new input. Form LIST1 receives the message, then updates its display accordingly, as shown below.
The message is sent using the putmessage
command, with $msgid
set to 'add' and $msgdata
created by using putlistitems/occ
on the newly created occurrence. The message is received in the <ASYNC INTERRUPT> trigger of the parent form, which creates an empty occurrence and fills it with the contents of $msgdata
using getlistitems/occ
. This removes the need for the parent form to retrieve the data from the database.
Using this technique I can remain in form ADD1 and create as many new entries as I wish. Each time I press the STORE button the details are immediately echoed in the parent form, giving me instant confirmation that the action has worked successfully.
If the child form were to perform a delete, then the parent form would use the contents of $msgdata
to locate the corresponding occurrence in its structure then discard
it. If the child form were to modify the data then the occurrence in the parent would be overwritten by the contents of $msgdata
. In neither case would it be necessary for the parent to rebuild its contents by re-reading the database (with the exception of foreign entities).
In this scenario I first retrieve occurrences into the LIST form. I select one of these occurrences and then press one of the buttons to activate a child form, in this example ENQ1. This causes the primary key of the selected occurrence to be passed to the child form as a parameter. The child form will then use this to retrieve data from the database before displaying the results.
When a child form is activated it receives focus, indicated by the colour of the title bar. Those forms that do not have focus have their title bars greyed out. I am now able to switch focus from form ENQ1 back to LIST1 just by clicking the mouse anywhere inside the boundaries of LIST1. If I select a different occurrence inside LIST1 then press the button for ENQ1 again another instance of ENQ1 appears, but this time containing the data for the latest selection. This is shown below.
For this to work successfully it is necessary to use the new_instance
command to create an instance name for form ENQ1 which is different from the existing instance of ENQ1. Rather than generate instance names at random I tend to construct one using a mixture of the form name plus the primary key of the selected occurrence. This would give me instance names of ENQ1_PA and ENQ1_FB in this example. Using this mechanism I can easily link a child instance with a particular occurrence, not by its occurrence number within LIST1's structure which could change due to additions or deletions, but by its primary key, which can never change. Simple, but effective and foolproof (until the world generates a better class of fool, that is).
The one disadvantage with the previous technique is that each time I want to see the details of a different occurrence I have to select the occurrence in LIST1 then press the button to activate the child form again. I may also have to delete any previous instances of the child form before the application area gets too cluttered with all these active windows. Ideally what I would like to do is select my first occurrence, select one or more child forms, then simply change the selection in the parent form and have the change automatically passed down to the existing child processes. This is shown in the following pictures. In the first picture I have selected child forms ENQ1 and LIST5 using the person id of 'PA'.
Moving my cursor back to LIST I now click on the occurrence with person id 'FB' and the contents of the child forms instantly change to echo the new selection. Quick and simple.
The code to achieve this is relatively simple. The <OCCURRENCE GETS FOCUS> trigger of the entity inside form LIST1 contains the following two proc statements:
$keyfields
function and the putlistitems/id
command to load the primary key of the current occurrence into a variable as an associative list.$instancechildren
function to obtain a list of all the child instances which belong to the current form, then reactivates each of these children (ignoring non-form components) using the latest primary key as a parameter. Each child instance will then clear
its current contents before refreshing itself from the new primary key.This technique means that I can fill the parent form with a list of occurrences, then click on a button to activate a child form which will, for example, allow me to modify the first occurrence. After completing the modification I press the STORE button to update the database but leave the child instance active (the OK button would terminate the instance after the STORE). I can then simply click on a different occurrence inside the parent form and see the contents of the child form(s) change instantly to echo the new selection. This is far more efficient than having to terminate the current child instance and press the button to activate it again after I have selected a new occurrence. I have effectively reduced three mouse clicks down to one - you can't get much more efficient than that!
It should be obvious that these two options cannot both be available at the same time, so I had to devise a method to switch between the two. The solution was to have a switch which would turn the ability to refresh the child instances either ON or OFF, and to have this switch controlled from a pulldown menu option.
$$refresh_children
.<predisplay> trigger $check = $$refresh_children ; show current setting <option> trigger $$refresh_children = !$$refresh_children ; switch setting $check = $$refresh_children ; show new setting
if ($$refresh_children & !$empty) call LP_PRIMARY_KEY call REFRESH_CHILDREN endif
I hope that I have managed to convince you that, far from being a novelty feature, it is possible to use non-modal forms to provide speedier access to various functions, thus increasing productivity.
Tony Marston
13th September, 2000
mailto:tony@tonymarston.net
mailto:TonyMarston@hotmail.com
http://www.tonymarston.net