Lescasse Consulting
 Home    Company    News    Prices    Download    Buy    Forums   
Read Me
Buy
Forums
Resume
AntiSpam 1.2
wBackup 1.11
NetAccess 2.0
Visual APL 1.0 
APL+Win 8.0 
APL+Win Products 
APL+Win Objects™ 
APL+Win Training 
APL+Web Services
APL+Web Component 
APL+ History
Dyalog.Net Tutorial
Conferences 
Powerpoint
White Papers
Web Hosting
References
Links
 
APL+Win Objects™ 6.0

TADO5
TADO5 Tutorial
TAPLDraw5
TAPLEdit5
TAPLSession5
TAbale5
TAboutBox5
TAccess5
TAgent5
TBlatMail5
TButton5
TCDO5
TCRC5
TCancelButton5
TCheck5
TCheckGroup5
TChildForm5
TChooseColor5
TChooseFont5
TClipBoard5
TClock5
TCodeStats5
TColors5
TCombo5
TComboDrive5
TComboFilter5
TComboList5
TComboTree5
TCommandBar5
TCommandButton5
TControlClass5
TCueCard5
TDHTML5
TDHTMLEditor5
TDateTime5
TDateTimeFr5
TDates5
TDemoHandlers5
TDisplay5
TDOS5
TDualSelect5
TEdit5
TEditAmount5
TEditDir5
TEditEnter5
TEditFile5
TEditGrid5
TEditList5
TEditListview5
TEditMenu5
TEditNum5
TEditSelect5
TEditSpin5
TEmail5
TError5
TExampleForm5
TExcel5
TExcel5 Tutorial
TFindReplace5
TFOne5
TFTP5
TFTP5 Tutorial
TFileCompare5
TFileMenu5
TFileMenuDef5
TFlatButton5
TForm5
TFormClass5
TFormEditor5
TFrame5
TGetDir5
TGif5
TGifForm5
TGifWb5
TGoMenu5
TGraphX5
TGrid5
TGridDisplay5
TGridPrint5
TGUID5
THLine5
THTML5
THTML5 Tutorial
THTTP5
THelp5
THelpMenu5
TImagelist5
TInfo5
TIniFile5
TInstall5
TInternet5
TJpg5
TJpgWb5
TLabel5
TList5
TListview5
TLock5
TLogs5
TMAPI5
TMath5
TMDIForm5
TMSOutlook5
TMaskEdit5
TMedia5
TMenu5
TMessage5
TModalCall5
TMsgBox5
TNavigator5
TNetwork5
TNonVisualClass5
TODBC5
TOKButton5
TObject5
TOpenFile5
TOption5
TOptionGroup5
TOutlook5
TOutlookMail5
TOWCSpread5
TPDF5
TPFKeys5
TPage5
TPassword5
TPicture5
TPing5
TPopupMenu5
TPowerpoint5
TPowerpoint5 Tutorial
TPrinter5
TProgress5
TProgressDlg5
TQuestion5
TRegistry5
TRegistryKey5
TResource5
TRichEdit5
TSPX5
TSQLDMO5
TScheduler5
TScroll5
TSelector5
TSpinner5
TSplitter5
TStatus5
TStopWatch5
TTest5
TTestError5
TTextFile5
TTimer5
TTip5
TTipForm5
TTLI5
TToolBar5
TToolbox5
TToolsMenu5
TTrackbar5
TTranslate5
TTree5
TVLine5
TViewMenu5
TWebBrowser5
TWebServer5
TWebSite5
TWebSiteNet5
TWinMenu5
TWord5
TYesNo5
    Visits:  2062 (42 on line) Last Update: Apr 23, 2003  
    Dialog Box Programming with APL+Win    Printer Friendly  

 
One of the basic tasks of the Windows programmer is to write dialog boxes. This chapter will show how to develop dialog boxes with APL+Win.

In order to learn the basics, we will develop a very simple dialog box which looks like this:


Figure 1 - The dialog box to develop

Using the ]WED forms editor

The simplest way to create a dialog box is to use the ]WED editor.

Simply enter a command such as:

      ]WED fmDb

where fmDb will be the name of your new dialog box form.

The following windows are displayed on the screen. The top window is the pilot window from which you can select an object (left combo box), select a property or event for this object (middle combo box) and enter a new value for this property or event (right combo box).



Figure 2 - The ]WED forms editor windows

The bottom left window is the objects palette from which you can pick objects to install on your dialog box.

The bottom right window is the dialog box we are going to design.

Perform the following steps:

Resizing the form

  1. using the left mouse button, resize the fmDb form to a smaller form

Changing form properties

  1. select the caption property from the Property combo box
  2. type: My first dialog box in the Value field and press Enter
  3. select the scale property from the Property combo box
  4. replace the content of the Value field by: 5 (5 means pixel coordinates) and press Enter

Adding a control on the form

  1. click on the OK button in the objects palette
  2. using the right mouse button, drag it to the right

Moving a control on the form

  1. click on the bn1 button you just created and move it to the top right corner of the form

Your form should now look more or less like the following:


Figure 3 - Dialog box in design mode

Adding a second button of the same size as the first one

  1. click on the bn1 button to select it
  2. select where from the Property combo box
  3. highlight the last 3 values of the where property in the Value field and press Ctrl+C (or Ctrl+Ins)
    (this copies them to the clipboard)
  4. click on the OK button in the objects palette
  5. using the right mouse button on the dialog box, drag towards right and bottom to give the button a size
  6. click on the bn2 button to select it
  7. select where from the Property combo box
  8. in the Value field, highlight the last 3 values and press Ctrl+V (or Shift+Ins) and then Enter
    (this forces button bn2 size to be the same horizontal position and size as button bn1)

As you see, you can resize an object with the mouse, by dragging one of its handles, or by changing its where property.

Changing buttons properties

  1. click on button bn1 to select it
  2. click in the Property combo and press C
  3. in the Value field, type: OK and press Enter
  4. click on button bn2 to select it

(note that the current property stays set to caption)

  1. in the Value field, type: Cancel and press Enter

Your form should like the following:


Figure 4 - Dialog box in design mode (continued)

Adding more controls

  1. click on the tools palette object which displays LABEL
  2. on the form, towards the bottom, drag to the right and bottom to give a size to your label
  3. select the caption property and type: Question then press Enter
  4. select the where property and change the next to last value to: 16 and press Enter
  5. click on the tools palette object which displays EDIT
  6. on the form, towards the bottom, drag to the right and bottom to give a size to your edit control
  7. select the where property and change the next to last value to: 20 and press Enter

The dialog box should look like the following:


Figure 5 - Dialog box in design mode (continued)

If you could obtain a form similar to the above one, congratulations, you did it right.

Saving your work

At any time while working with the ]WED forms editor you can press Ctrl+S to save your work.

When you press Ctrl+S, an image of your form, as defined so far, is saved in a variable called formname_def where formname is your current form name (here: fmDB).

Another way to save your work is to press Ctrl+D: this saves your form definition as an APL function, called formname_Make where formname is your current form name (here: fmDB). You can also press Ctrl+E at any time to exit after saving your form's definition as an variable called formname_def.

Note that when pressing Ctrl+S, Ctrl+D or Ctrl+E you are saving your work in the active workspace: you still need to save your active workspace!

  1. press Ctrl+D now, then press Ctrl+E.

This should have created variable fmDb_def and function fmDB_Make in your APL workspace.

Here is what the fmDb_def nested array looks like:

      fmDb_def
710430785 66055 19961016 132011390 OfmDb  .717986918E10 CF
orm 768 Pscale  5 0 0 193 305  Pcaption My first Dialo
g Box C_Window 512 Pextent 12.0625 38.125  Pwhere  11
21.875  Obn1 0 Cbutton 1024 Pcaption OK C_Window 512
Pwhere  10 220 25 75  Obn2 0 CButton 1024 Pcaption Can
cel C_Window 512 Pwhere 40 220 25 75  Ol1 0 CLabel 25
60 Pcaption Question C_Window 512 Pwhere  145 5 15 290
Oed1 0 CEdit 1792 C_Window 512 Pwhere  165 5 20 290
˝fmDb_def
56

fmDb_def[9 10]
Pscale  5 0 0 193 305

Do not try to manually change this nested array: you would not be able to reload the form in the ]WED editor from it later! That is why I think it is better to work with the formname_Make functions and to save your work with Ctrl+D followed by Ctrl+E.

Here is what the fmDb_Make function looks like:

    ’ fmDb_Make;x;Śwself
[1]   ©'fmDb_Make - Created 10/16/96 at 14:24:24
[2]   'fmDb' Świ 'Delete'
[3]
[4]   Śwself„'fmDb' Świ 'New' 'Form' 'Close'
[5]   Świ 'scale' 5 0 0 193 305
[6]   Świ 'caption' 'My first Dialog Box'
[7]   Świ 'extent' 12.0625 38.125
[8]   Świ 'where' 11 21.875
[9]
[10]  Śwself„'fmDb.bn1' Świ 'New' 'Button'
[11]  Świ 'caption' 'OK'
[12]  Świ 'where' 10 220 25 75
[13]
[14]  Śwself„'fmDb.bn2' Świ 'New' 'Button'
[15]  Świ 'caption' 'Cancel'
[16]  Świ 'where' 40 220 25 75
[17]
[18]  Śwself„'fmDb.l1' Świ 'New' 'Label'
[19]  Świ 'caption' 'Question'
[20]  Świ 'where' 145 5 15 290
[21]
[22]  Śwself„'fmDb.ed1' Świ 'New' 'Edit'
[23]  Świ 'where' 165 5 20 290
’

At any time you may run this fmDb_Make function to recreate a form identical to the one you designed with ].

Handling events

Unlike DOS programming which used to be " procedural", Windows programming is " events programming".

Events programming consists in associating APL functions (or APL expressions) to events that occur in your form. Such functions are called " event-handler functions" or " callback functions".

Events are special object properties which names are prefixed by " on". Example: onClick denotes a mouse click event occurring on an object. Events are listed in the Property combo box of the ]WED main form.

In order to make our form a useful form, we must return the text entered by the user in the edit control and we need to do this when the user clicks the OK button.

We also need to close the form when the user clicks the OK button.

So, let us start again the ]WED editor:

      ]WED fmDb

When you do so, your fmDb form is displayed in its last saved state.

  1. click on the OK button to select it
  2. click on the Property combo box and select onClick
  3. click on the [...]button to the right of the Value field
    (this opens an edit window with the fmDb_bn1_Click function name already typed in)

You can start writing your fmDb_bn1_Click callback function right there, without quitting the ]WED editor.


Figure 6 - Edit session for function fmDb_bn1_Click

The fmDb_bn1_Click callback function will be executed whenever a click occurs on the OK button.

The first instruction queries the text property of the fmDB.ed1 edit control (i.e. the text entered by the user in the edit control) and saves it in variable A.

The second instruction sets the value property of the fmDB form to be this exact text. We need this because a form returns its value property as a result of its Wait method when it is closed.

The third line asks the form to invoke its Close method.

As this short example shows:

  • object names are named according to a parent-child relationship denoted with the . symbol
  • objects have properties (like text, value, ...) that can be queried or set with the ŒWI system function. In APL+Win properties always start with a lowercase letter and are entirely lowercase. Case is significant.
  • objects have methods (like Close, ...) which are built in object behavior which can be invoked using the ŒWI system function (methods are very similar to programs which are run to perform a certain task on the object). Methods always start with an uppercase letter, all other letters being lowercase. Case is significant.
  1. press Ctrl+D, confirm updating the fmDb_Make function and press Ctrl+E

Tip: do not forget to save your workspace or save the fmDb_Make and fmDb_bn1_Click functions to your UCMD (User Command) library file.

Running a dialog box

We now need to run our brand new Windows fmDb application. This is simply done by asking the fmDb form to run its Wait method:

      'fmDb'Świ'Wait'

Our form immediately displays itself on the screen.


Figure 7 - Dialog box in run mode

  1. click in the edit control field, type APL+Win and click the OK button.

As soon as the form closes, the 'fmDb'Œwi'Wait' instruction terminates and returns the edit control content (APL+Win).

Naming objects

It is good practice, in order to make programs more readable and maintainable, to use meaningful objects names.

For example, instead of using the default fmDb.bn1 and fmDb.bn2 button names, it would be much better to use fmDb.bnOK and fmDb.bnCancel.

It is also recommended APL+Win practice to prefix objects with a few characters which help identify their class (example: fm for form, bn for button, l for label, ed for edit control, etc.). We are doing that systematically here.

Similarly, it would be better to use fmDb.lQst and fmDb.edQst than fmDb.l1 and fmDb.ed1, especially if there were other labels and edit controls on the form.

We should have renamed these objects immediately after their creation.

Let us rename all of our dialog box objects. Pay attention, this also means changing our fmDb_bn1_Click callback function accordingly.

Enter the form's editor once again:

      ]WED fmDb
  1. select an object by clicking on it
  2. click name in the Property combo box
  3. change its name in the Value field and press Enter
  4. repeat these steps for each object
    (rename the objects as described above)
  5. select the OK button by clicking on it
  6. select the onClick event from the Property combo box
  7. click on the [...]button to the right of the Value field
  8. change the fmDb_bn1_Click so that it now reads:
    ’ fmDb_bnOK_Click;A
[1]   A„'fmDb.edQst'Świ'text'
[2]   'fmDb'Świ'value' A
[3]   0 0˝'fmDb'Świ'Close'
’
  1. press Ctrl+E to save the new function definition
  2. change fmDb_bn1_Click to fmDb_bnOK_Click in the Value field

Note Renaming an object for which the caption property has been set different from its name property, automatically changes the caption property: therefore you will have to change the label's caption back to Question after you rename the label to lQst.

Tip as you see, DO NOT WAIT for renaming objects with meaningful names: do it right at the time you create them, to avoid having to makes changes in callback functions.

Handling more events

As it stands, we already have a functioning Windows application! And we have had very little code to write: just 3 lines of easy APL code:

    ’ fmDb_bnOK_Click;A
[1]   A„'fmDb.edQst'Świ'text'
[2]   'fmDb'Świ'value' A
[3]   0 0˝'fmDb'Świ'Close'
’

Our application knows how to behave in case of a Click on the OK button, but we have not yet taught it to behave in case of Click on the Cancel button.

In case of Click on the Cancel button, it would be a good idea to return a value that the user could not type in the edit control, so that we can easily test the way our form was closed. I propose to return an empty integer matrix: [0 0˝0 when the user clicks the Cancel button.

  1. click on the Cancel button to select it
  2. select onClick in the Property combo box
  3. click on the [...]button to the right of the Value field
    (this opens an edit window with the fmDb_bnCancel_Click function name already typed in for you)

Define your fmDb_bnCancel_Click callback function as follows:


Figure 8 - Edit session for function fmDb_bnCancel_Click

The fmDb_bnCancel_Click callback function will be executed whenever a click occurs on the Cancel button.

  1. press Ctrl+D, confirm updating the fmDb_Make function and press Ctrl+E

Tip Do not forget to save your workspace or save the fmDb_Make and fmDb_bn1_Click functions to your UCMD (User Command) library file.

Testing the dialog box

We can once again test our dialog box to check our Cancel button behavior.

Remember to rerun function fmDb_Make before running your form:

      fmDb_Make
(0 0˝0)­'fmDb' Świ 'Wait'



Figure 9 - Testing the Cancel button

  1. press Cancel

Tip It is necessary to rerun function fmDb_Make before running the form, because we have made several changes using the ]WED editor and in particular added a callback to the Cancel button; without rerunning the fmDb_Make function, we would use the old version of the form which did not know about this callback):

Improving our application

You may think that our Windows application is finished. However, it may be significantly improved before it can become a real utility Windows application.

One thing you may have noticed is that we must click within the edit control before we can type in it: this is because this control is not given the focus by default when the application starts.

Giving the focus to the edit control at startup

How can we force the focus to go to the edit control when the form starts up?

Knowing that edit control objects have a Focus method, you might suggest that we simply invoke this method on the fmDb.edQst object just before calling our application. Let's try it:

      'fmDb.edQst' Świ 'Focus'
ŚWI FOCUS ERROR: Window not open
'fmDb.edQst' Świ 'Focus'
						 ^

This is unfortunately not possible, because we cannot invoke methods on closed objects.

The solution is (as it is almost ALWAYS the case) to run this method in a callback function.

The question you will ask, then, is: a callback function for which event on which object?

That's a good question. More generally, the question, when you need to perform a task which does not seem directly related to an event occurring in your application:

which event should I use to perform the Windows task I need to perform?

You must know that, when a form is started, a number of events are automatically generated. These events are:

Open, Resize, Show, Focus, Paint, Wait

The general answer to the above general question is:

you must perform a Windows task in the event which most closely relates to the task

For example, if you need to draw a picture on your form, you must do it in the onPaint event handler of your form. If you need to resize an object on your form, you need to do it in the onResize event handler of your form.

Here we need to force the focus to go to the fmDb.edQst object when the form is started, so we need to do that in the onFocus event handler of the form.

Start the ]WED editor again:

      ]WED fmDb

then:

  1. click on the form outside any object
    (fmDb must appear in the Object field in the top window)
  2. select onFocus from the Property combo box
  3. click on the [...]button to the right of the Value field
  4. define your event handler as follows:


Figure 10 - Edit session for function fmDb_Focus

  1. press Ctrl+D, confirm updating the fmDb_Make function and press Ctrl+E

Tip Do not forget to save your workspace or save the fmDb_Make and fmDb_bn1_Click functions to your UCMD (User Command) library file.

Let's test our form again:

      fmDb_Make
'fmDb' Świ 'Wait'


Figure 11 - Testing the focus setting to the edit control

As the above form shows the caret is now displayed in the edit control as soon as the form shows up and you can start typing immediately in the edit control.

Changing the form border

A dialog box is a form which is normally not resizeable. It should also have a modal border.

This is achieved by changing the form's border property.

Start the ]WED editor again, select the form object by clicking in it (outside of any control) and select border from the Property combo box. You may notice that the [...]button to the right of the Value field gets enabled. Every time this button is enabled you can of course click on it.

Click on the [...]button. A form appears to let you change elements of our dialog box border property. Change them so that they look like the following:


Figure 12 - The ]WED border dialog box

then click the OK button.

The Value field should now display 3 16.

Testing your form without leaving ]WED

You may test your form even though you are still under control of the ]WED editor. Simply choose Test / Start or press Ctrl+T. The following form should be displayed:


Figure 13 - Testing the dialog box from ]WED

Note that the form does no longer have any system menu, even though we asked for one: this is because we also chose Modal border which has precedence over the System Menu choice. Also the minimize and maximize buttons have disappeared. This is the standard appearance of a modal dialog box (if you want to be convinced, load WinWord and display any dialog box from the WinWord menus, and compare).

Note that the dialog box can no longer be resized.

Once you are satisfied with your test, simply close the form to return to the ]WED design mode.

Summing up our application code so far

    ’ fmDb_Make;x;Śwself
[1]   ©' fmDb_Make - Created 10/16/96 at 21:35:43
[2]   'fmDb' Świ 'Delete'
[3]
[4]   Śwself„'fmDb' Świ 'New' 'Form' 'Close'
[5]   Świ 'scale' 5 0 0 193 305
[6]   Świ 'caption' 'My first Dialog Box'
[7]   Świ 'border' 19
[8]   Świ 'extent' 12.0625 38.125
[9]   Świ 'where' 11 21.875
[10]  Świ 'onFocus' 'fmDb_Focus'
[11]
[12]  Śwself„'fmDb.bnOK' Świ 'New' 'Button'
[13]  Świ 'caption' 'OK'
[14]  Świ 'where' 10 220 25 75
[15]  Świ 'onClick' 'fmDb_bnOK_Click'
[16]
[17]  Śwself„'fmDb.bnCancel' Świ 'New' 'Button'
[18]  Świ 'caption' 'Cancel'
[19]  Świ 'where' 40 220 25 75
[20]  Świ 'onClick' 'fmDb_bnCancel_Click'
[21]
[22]  Śwself„'fmDb.lQst' Świ 'New' 'Label'
[23]  Świ 'caption' 'Question'
[24]  Świ 'where' 145 5 15 290
[25]
[26]  Śwself„'fmDb.edQst' Świ 'New' 'Edit'
[27]  Świ 'where' 165 5 20 290
’
    ’ fmDb_Focus
[1]   'fmDb.edQst'Świ'Focus'
’
    ’ fmDb_bnOK_Click;A
[1]   A„'fmDb.edQst'Świ'text'
[2]   'fmDb'Świ'value' A
[3]   0 0˝'fmDb'Świ'Close'
’
    ’ fmDb_bnCancel_Click
[1]   'fmDb'Świ'value' (0 0˝0)
[2]   0 0˝'fmDb'Świ'Close'
’


Supplying an initialization value for the edit control

Another enhancement to our Windows application would be to be able to specify a default answer to the question. This default answer should be passed as a parameter to the fmDb_Make function and it should be displayed in the edit control as soon as the dialog box shows up.

How do we do that?

We must provide this initialization value at the time the form is launched, i.e. when the Wait method is invoked. This is done by specifying the initialization value as an argument to the Wait method.

This argument can be read in the onWait event handler. Its value is then supplied in the ŒWARG system variable.

We therefore need to do 2 things:

  • pass the initialization value as an argument to the Wait method
  • define an event handler for the onWait event, reading the argument from the ŒWARG system variable

This time we will directly edit the fmDb_Make function.

Change it so that it looks like the following (changes have been set to bold characters):

R„A fmDb_Make B;x;Śwself
[1]   ©’R„A fmDb_Make B -- Created 10/16/96 at 21:35:43
[2]   'fmDb' Świ 'Delete'
[3]
[4]   Śwself„'fmDb' Świ 'New' 'Form' 'Close'
[5]   Świ 'scale' 5 0 0 193 305
[6]   Świ 'caption' 'My first Dialog Box'
[7]   Świ 'border' 19
[8]   Świ 'extent' 12.0625 38.125
[9]   Świ 'where' 11 21.875
[10]  Świ 'onFocus' 'fmDb_Focus'
[11]  Świ 'onWait' 'fmDb_Wait'
[12]
[13]  Śwself„'fmDb.bnOK' Świ 'New' 'Button'
[14]  Świ 'caption' 'OK'
[15]  Świ 'where' 10 220 25 75
[16]  Świ 'onClick' 'fmDb_bnOK_Click'
[17]
[18]  Śwself„'fmDb.bnCancel' Świ 'New' 'Button'
[19]  Świ 'caption' 'Cancel'
[20]  Świ 'where' 40 220 25 75
[21]  Świ 'onClick' 'fmDb_bnCancel_Click'
[22]
[23]  Śwself„'fmDb.lQst' Świ 'New' 'Label'
[24]  Świ 'caption' 'Question'
[25]  Świ 'where' 145 5 15 290
[26]
[27]  Śwself„'fmDb.edQst' Świ 'New' 'Edit'
[28]  Świ 'where' 165 5 20 290
[29]
[30]  R„'fmDb'Świ'Wait' A

Tip once you start making manual changes to your fmDb_Make function, you will not be able to use ]WED any more without risking to override the manual changes to fmDb_Make.

Note
We will be using the function left argument to pass the initialization string (default answer) to it. Thr right argument will for now be the empty character string and will be used later.

Let's define the fmDb_Wait event handler function as follows:

    ’ fmDb_Wait
[1]   'fmDb.edQst'Świ'text' Śwarg
’

Now run the fmDb_Make function again to apply changes to the fmDb form and run the form:

     'APL+Win' fmDb_Make ''

Our dialog box instantaneously displays with its initialization value in the edit control:


Figure 14 - Testing the dialog box with a default answer

However this is not quite perfect yet. Most well behaved Windows application would display the default answer, selected, with the caret positioned at the end of the selected characters.

In order to do this we probably need to use some of the characteristics of the edit control object. Let's look at the Windows Interface help file provided with APL+Win.

Select Help / Windows Interface from the APL+Win session menus. In the help file, select Classes, then Edit.

The following help page displays:


Figure 15 - The APL+Win Windows Interface help file

It show us that the selection property is exactly what we are looking for. So, we should use it on the edit control, once it is initialized. Where should we change this property? Just after initializing the edit control, in the fmDb_Wait event handler, of course.

Change the fmDb_Wait event handler to the following:

    ’ fmDb_Wait;A
[1]   'fmDb.edQst'Świ'text' (A„Śwarg)
[2]   'fmDb.edQst'Świ'selection' (0,˝A)
’

Is our dialog box complete yet? Not quite: we would also like that the Enter key behaves as a click on the OK button and that the Esc key behaves as a click on the Cancel button.

Accepting the Enter and Esc keys

If we know enough of Windows programming, we should be aware that it is possible to have one button in a form which is the default button and accepts the Enter key. It is also possible to have one button which accepts the Esc key and behaves as a Cancel button.

If we search in the Windows Interface help file or in the APL+Win documentation, looking for properties of the Button class, we find that buttons may have one of the following values set in their style property:

Button Styles

Value Description
1 Default button for the entire form (Enter key generates a click on this button)
2 Cancel button (Esc key generates a click on this button)

Let's manually change the fmDb_Make function, adding these style properties to our fmDb.bnOK and fmDb.bnCancel buttons.

The function should now read:

    ’ R„A fmDb_Make B;x;Śwself
[1]   ©’R„A fmDb_Make B -- Created 10/16/96 at 21:35:43
[2]   'fmDb' Świ 'Delete'
[3]
[4]   Śwself„'fmDb' Świ 'New' 'Form' 'Close'
[5]   Świ 'scale' 5 0 0 193 305
[6]   Świ 'caption' 'My first Dialog Box'
[7]   Świ 'border' 19
[8]   Świ 'extent' 12.0625 38.125
[9]   Świ 'where' 11 21.875
[10]  Świ 'onFocus' 'fmDb_Focus'
[11]  Świ 'onWait' 'fmDb_Wait'
[12]
[13]  Śwself„'fmDb.bnOK' Świ 'New' 'Button'
[14]  Świ 'caption' 'OK'
[15]  Świ 'style' 1
[16]  Świ 'where' 10 220 25 75
[17]  Świ 'onClick' 'fmDb_bnOK_Click'
[18]
[19]  Śwself„'fmDb.bnCancel' Świ 'New' 'Button'
[20]  Świ 'caption' 'Cancel'
[21]  Świ 'style' 2
[22]  Świ 'where' 40 220 25 75
[23]  Świ 'onClick' 'fmDb_bnCancel_Click'
[24]
[25]  Śwself„'fmDb.lQst' Świ 'New' 'Label'
[26]  Świ 'caption' 'Question'
[27]  Świ 'where' 145 5 15 290
[28]
[29]  Śwself„'fmDb.edQst' Świ 'New' 'Edit'
[30]  Świ 'where' 165 5 20 290
[31]
[32]  R„'fmDb'Świ'Wait' A
’

Let's try the dialog box again:

      'APL+Win' fmDb_Make ''

Change the text in the edit control to: APL+Unix and press the Enter key.

Now press the Esc key. Nice! The form behaves as if we had clicked the OK button.

Start the form again:

      'APL+Win' fmDb_Make ''
		

Now press the Esc key. The form behaves as if we had clicked the Cancel button.

Summarizing our Windows application source code

The complete source code of all our dialog box is reproduced below:

    ’ R„A fmDb_Make B;x;Śwself
[1]   ©’R„A fmDb_Make B -- Created 10/16/96 at 21:35:43
[2]   'fmDb' Świ 'Delete'
[3]
[4]   Śwself„'fmDb' Świ 'New' 'Form' 'Close'
[5]   Świ 'scale' 5 0 0 193 305
[6]   Świ 'caption' 'My first Dialog Box'
[7]   Świ 'border' 19
[8]   Świ 'extent' 12.0625 38.125
[9]   Świ 'where' 11 21.875
[10]  Świ 'onFocus' 'fmDb_Focus'
[11]  Świ 'onWait' 'fmDb_Wait'
[12]
[13]  Śwself„'fmDb.bnOK' Świ 'New' 'Button'
[14]  Świ 'caption' 'OK'
[15]  Świ 'style' 1
[16]  Świ 'where' 10 220 25 75
[17]  Świ 'onClick' 'fmDb_bnOK_Click'
[18]
[19]  Śwself„'fmDb.bnCancel' Świ 'New' 'Button'
[20]  Świ 'caption' 'Cancel'
[21]  Świ 'style' 2
[22]  Świ 'where' 40 220 25 75
[23]  Świ 'onClick' 'fmDb_bnCancel_Click'
[24]
[25]  Śwself„'fmDb.lQst' Świ 'New' 'Label'
[26]  Świ 'caption' 'Question'
[27]  Świ 'where' 145 5 15 290
[28]
[29]  Śwself„'fmDb.edQst' Świ 'New' 'Edit'
[30]  Świ 'where' 165 5 20 290
[31]
[32]  R„'fmDb'Świ'Wait' A
’
    ’ fmDb_Focus
[1]   'fmDb.edQst'Świ'Focus'
’

’ fmDb_Wait;A
[1]   'fmDb.edQst'Świ'text' (A„ Śwarg)
[2]   'fmDb.edQst'Świ'selection' (0,˝A)
’
    ’ fmDb_bnOK_Click;A
[1]   A„'fmDb.edQst'Świ'text'
[2]   'fmDb'Świ'value' A
[3]   0 0˝'fmDb'Świ'Close'
’
    ’ fmDb_bnCancel_Click
[1]   'fmDb'Świ'value' (0 0˝0)
[2]   0 0˝'fmDb'Świ'Close'
’

As you can see, the APL+Win source code of our complete Windows application fits comfortably on one page (and we have not even written the fmDb_Make main function ourselves (it was auto generated by the ]WED editor: we just had to edit it).

But we can go one step further and I will describe this in the next section.

Nature of Windows programming in APL

This section is extremely important to clearly understand if you are new to Windows programming with APL.

If you happen to have used APL in the past on mainframes or under DOS, and if you carefully observe what we have done so far, you may be struck by the following discoveries about Windows programming with APL+Win:

Discovery 1 - everything in a Windows APL application is global

Observe our application: it is made of 5 APL functions. One, fmDb_Make is the main function which builds the interface and starts the application. The other 4 are callback functions (also called "event handlers"). Are they called by the main function as subroutines (as it used to be the case in mainframe or DOS APL applications)? No! Even if you look carefully, you will find NO line of code in our application that specifically calls any of these 4 functions. There 4 functions are global relatively to the main application function.

Let's explain a little bit better what happens when you launch program fmDb_Make.

This program executes very fast to line 32 (a couple of milliseconds maybe). Then it executes line 32 where the Wait method is invoked on the form. At this stage the fmDb_Make program stops running and waits.

What does it wait for?

Events of course!

Everytime an event occurs, most often generated by the user action (all the time in our simple application), like for example a key pressed or a mouse click, the callback function (if any defined) associated with this particular event is automatically run by the APL+Win system.

You must understand that clearly: the Wait method tells the APL+Win system to start listening to events and when it hears that one is occurring on a given object, to check if a callback function has been associated with this event on this object (by such instructions as 'fmDb'Œwi'onFocus' 'fmDb_Focus' or 'fmDb.bnOK'Œwi'onClick' 'fmDb_bnOK_Click')

This wait state could end for ever and the fmDb_Make program would never terminate. Happily there are a couple of methods which can close a form and terminate the Wait state (like the Close method which we have used).

Discovery 2 - a Windows application has a large quantities of callback functions

A very simple application like ours, which only uses one form and 4 controls, required that we wrote 4 callback functions.

The number of callback functions can be VERY large in a real life Windows application.

To understand this better, first look at the Windows Interface help file, select Classes and then any object like the Edit object, then click on the Events word at the top. You will see all the kinds of events that can occur on an edit control. Here they are:

onChange, onClose, onDdeConnect, onDdeDisconnect, onDestroy, onFocus, onHide, onKeyDown, onKeyPress, onKeyUp, onLimit, onMemory, onMouseDown, onMouseDrag, onMouseMove, onMouseUp, onMove, onOpen, onPaint, onResize, onScroll, onSend, onShow, onUnfocus.

This means that for one particular edit control in a form, you may have to write up to 24 event handlers.

Happily, you will never need to handle all these events, but a typical Edit control might require that your application reacts to a few events such as onChange, onFocus, onKeyPress, onLimit, onUnfocus and maybe onScroll. The same remark applies for other classes of controls, although the events may differ according to the controls.

If your application typically has 100 forms, each containing about 10 controls (which is a very low average) and if we assume you need to handle a mean of 4 events per control, this means your application will require you to write 100x10x4 = 4000 callback functions!

This means that we must be prepared to be VERY WELL organized in order to cope with workspaces containing 4000 callback functions, all of them being global one to each other. What about callback function names: we MUST adopt a strict naming conventions to avoid anarchy, otherwise we will soon be completely lost!

But happily, the next section will show techniques to avoid these traps and make things look easy and nice.

Discovery 3 - Callback functions are small and easy to write

This is certainly true for our application. Our most complex callback functions contains 3 simple APL instructions!

This is generally true of the vast majority of callback functions in a real life Windows application. They most often have just a few instructions. Occasionally there could be a couple of larger callback functions, but this is rare.

That is nice, because, except for creating the interface (like we did with the ]WED editor and fmDb_Create) there is NOTHING ELSE in a Windows application than callback functions.

This leads us to the next discovery.

Discovery 4 - The only place where we can run code in an APL+Win Windows application is within callback functions

This means that, once the Wait method is invoked on the main form, i.e. after a few milliseconds following the launch of the application, no other APL code can run except callback functions, called by the APL+Win system.

Think about it! What does this clearly mean?

This means that, whatever you need to do, you MUST write an event handler function and associate it with an event on an object.

Often your main concern will be to identify which event to handle on which object, rather than to find out how to write the event handler code.

A consequence is that, in order to become a real good APL+Win programmer, you will have to over time learn how Windows behaves and how the APL+Win system behaves in terms of its communications with Windows.

But don't panic: you will be able to do a lot, from the early beginning and are partly isolated from Windows thanks to the APL+Win high level oriented object tools (ŒWI, ŒWARG, ...)

Discovery 5 - We work with new entities called objects without first understanding exactly what they are

For the first time in APL, you create objects (forms, buttons, labels, edit controls, ...) which show themselves on the screen and clearly exist, without you knowing exactly what they are.

Have you asked yourself: where do I find these objects in my APL workspace? You clearly understand about functions and APL variables, because you can see them with such commands as )FNS or )VARS , but what about our Windows objects?

From the good old principle that something cannot come from nothing, the creation of these objects must correspond to the reduction of some kind of resources available to us.

Knowing that, in terms of software, everything you create directly relates to memory and finally is nothing else than a shorter or longer series of 0s and 1s stored somewhere in your computer, you can guess that APL+Win forms, buttons, edit controls, labels, ... are nothing else than MEMORY.

Whenever you create an Windows object, you are using memory resources in your machine.

Now, let's try an easy experiment that many APL+Win novices have tried and which generally disconcert them:

      Śwa
6250012
      'ff'Świ'New' 'Form'
ff


Figure 16 - Testing workspace memory used by a form

      Śwa
6250012

Here is an apparent paradox. We are sure that an object uses some memory, but we are able to create a new object and our available memory stays EXACTLY the same.

If you think a few seconds about that paradox, you will easily find the solution: APL+Win objects are created outside of the APL workspace, in some other memory space. This is just deduction.

Let's verify if this is true.

      )CLEAR
CLEAR WS


Figure 17 - Testing form surviving a )CLEAR

Our ff form is still on the screen: if it had been part of the previous workspace, it would have been destroyed by )CLEAR, just like all other APL objects (functions, variables, labels, ...) are.

Callbacks encapsulation

With the above discoveries in mind, let us revisit our dialog box example.

What would really be nice would be to make a 1 to 1 relationship between a dialog box and an APL program!

In other words, we do not want our dialog box to be represented by 5 programs, but by just 1 program. Doing this simplifies a lot of things for the Windows applications APL developer.

  • It will tremendously reduce the number of functions in the workspace
  • it will make it much easier to transfer a form from one workspace to another
  • it will make it even easier to save forms on files (1 form = 1 function)
  • it will make it much easier to copy paste between callbacks
  • it will much reduce name conflicts in the workspace
  • it will make it easier to master the whole applications
  • most of whole, it will greatly increase the reusability of your forms

How can we encapsulate the 4 callbacks within the same function that builds the interface?

Thanks to the APL+Win control structures, we can make a crystal clear fmDb_Make function.

Let me show you a better version of our dialog box application and them comment it.

    ’ R„A fmDb_Make B;x;Śwself
[1]   ©'R„A fmDb_Make B -- Created 10/16/96 at 21:35:43
[2]
[3]  :select B
[4]  :case ''
[5]       'fmDb' Świ 'Delete'
[6]
[7]       Śwself„'fmDb' Świ 'New' 'Form' 'Close'
[8]       Świ 'scale' 5 0 0 193 305
[9]       Świ 'caption' 'My first Dialog Box'
[10]      Świ 'border' 19
[11]      Świ 'extent' 12.0625 38.125
[12]      Świ 'where' 11 21.875
[13]      Świ 'onFocus' 'fmDb_Make''Focus'''
[14]      Świ 'onWait' 'fmDb_Make''Wait'''
[15]
[16]      Śwself„'fmDb.bnOK' Świ 'New' 'Button'
[17]      Świ 'caption' 'OK'
[18]      Świ 'style' 1
[19]      Świ 'where' 10 220 25 75
[20]      Świ 'onClick' 'fmDb_Make''bnOK.Click'''
[21]
[22]      Śwself„'fmDb.bnCancel' Świ 'New' 'Button'
[23]      Świ 'caption' 'Cancel'
[24]      Świ 'style' 2
[25]      Świ 'where' 40 220 25 75
[26]      Świ 'onClick' 'fmDb_Make''bnCancel.Click'''
[27]
[28]      Śwself„'fmDb.lQst' Świ 'New' 'Label'
[29]      Świ 'caption' 'Question'
[30]      Świ 'where' 145 5 15 290
[31]
[32]      Śwself„'fmDb.edQst' Świ 'New' 'Edit'
[33]      Świ 'where' 165 5 20 290
[34]
[35]      R„'fmDb'Świ'Wait' A
[36]
[37]  :case 'Focus'
[38]      'fmDb.edQst'Świ'Focus'
[39]
[40]  :case 'Wait'
[41]      'fmDb.edQst'Świ'text' (A„ Śwarg)
[42]      'fmDb.edQst'Świ'selection' (0,˝A)
[43]
[44]  :case 'bnOK.Click'
[45]      A„'fmDb.edQst'Świ'text'
[46]      'fmDb'Świ'value' A
[47]      0 0˝'fmDb'Świ'Close'
[48]
[49]  :case 'bnCancel.Click'
[50]      'fmDb'Świ'value' (0 0˝0)
[51]      0 0˝'fmDb'Świ'Close'
[52]
[53] :end

When the fmDb_Make function is called with an empty right argument ('') , then the form is built.

As you can see, the fmDb_Make function now also serves as a callback function for each of our 4 events. The object name and nature of the event is passed as a right argument to fmDb_Make. Depending on the right argument, a simple:select :case :end control structure helps branch to the right callback code.

We have omitted the form name in the fmDb_Make right arguments, because we know everything here is related to the form called fmDb (the only one used by function fmDb_Make).

At this stage, and since our function has now really become a Windows utility (I would be inclined to rather speak of a utility form) we should in fact change the name of our function, which we inherited from ]WED, to something more meaningful and more closely related to our form.

Let's rename our function: GuiInput

And let's make some adjustments and touches to this utility. It now reads:

    ’ R„A GuiInput B;Śwself
[1]   ©’R„A GuiInputB -- Created 10/16/96 at 21:35:43
[2]
[3]   :select B
[4]   :case ''
[5]       :if 0=Śnc'A' Ş A„'' Ş :end
[6]       'fmDb' Świ 'Delete'
[7]
[8]       Śwself„'fmDb' Świ 'New' 'Form' 'Close'
[9]            Świ 'scale' 5 0 0 193 305
[10]          Świ 'caption' 'My first Dialog Box'
[11]          Świ 'border' 19
[12]          Świ 'extent' 12.0625 38.125
[13]          Świ 'where' 11 21.875
[14]          Świ 'onFocus' 'GuiInput''Focus'''
[15]          Świ 'onWait' 'GuiInput''Wait'''
[16]
[17]      Śwself„'fmDb.bnOK' Świ 'New' 'Button'
[18]          Świ 'caption' 'OK'
[19]          Świ 'style' 1
[20]          Świ 'where' 10 220 25 75
[21]          Świ 'onClick' 'GuiInput''bnOK.Click'''
[22]
[23]      Śwself„'fmDb.bnCancel' Świ 'New' 'Button'
[24]          Świ 'caption' 'Cancel'
[25]          Świ 'style' 2
[26]          Świ 'where' 40 220 25 75
[27]          Świ 'onClick' 'GuiInput''bnCancel.Click'''
[28]
[29]      Śwself„'fmDb.lQst' Świ 'New' 'Label'
[30]          Świ 'caption' 'Question'
[31]          Świ 'where' 145 5 15 290
[32]
[33]      Śwself„'fmDb.edQst' Świ 'New' 'Edit'
[34]          Świ 'where' 165 5 20 290
[35]
[36]      R„'fmDb'Świ'Wait' A
[37]
[38]  :case 'Focus'
[39]  ©   'fmDb.edQst'Świ'Focus'
[40]      Świ'.edQst.Focus'
[41]
[42]  :case 'Wait'
[43]  ©   'fmDb.edQst'Świ'text' (A„ Śwarg)
[44]  ©   'fmDb.edQst'Świ'selection' (0,˝A)
[45]      Świ'.edQst.text' (A„ Śwarg)
[46]      Świ'.edQst.selection' (0,˝A)
[47]
[48]  :case 'bnOK.Click'
[49]  ©    'fmDb'Świ'value'('fmDb.edQst'Świ'text')
[50]  ©    A„'fmDb'Świ'Close'
[51]      Śwself„'fmDb'
[52]      Świ'value'(Świ'.edQst.text')
[53]      A„Świ'Close'
[54]
[55]  :case 'bnCancel.Click'
[56]  ©   'fmDb'Świ'value' (0 0˝0)
[57]  ©   A„'fmDb'Świ'Close'
[58]      Śwself„'fmDb'
[59]      Świ'value' (0 0˝0)
[60]      A„Świ'Close'
[61]
[62]  :end
’

We have made the following cosmetic adjustments to this function:

  • we have deleted the localized x variable (erroneously created by ]WED)
  • we have added a test to initialize left argument A (so that the function my be called with no left argument)
  • we have replaced 0 0˝ notation (which I dislike) by A„ in a couple of places
  • we have commented our callback functions lines and used an alternative ŒWI notation which only uses a right argument

Other improvements

To make it a real utility, we need some final adjustments to our function.

  • We need to pass additional elements in the left argument, such as:
    • the form's caption
    • the question text
  • We need to add comments

Here is the final version of the function:

   ’ R„A GuiInput B;C;D;E;Śwself
[1]  ©’R„A GuiInput B -- Created 10/16/96 at 21:35:43
[2]  ©’ Displays a form with a question and returns user answer
[3]  ©’ It returns 0 0˝0 if user pressed Esc/clicked the Cancel button
[4]  ©’ A „… 3-element nested vector of vectors
[5]  ©’      A[1] „… default answer (character string; '' if omitted)
[6]  ©’      A[2] „… form caption
[7]  ©’      A[3] „… question
[8]  ©’ B „… ''              meaning:  build the interface
[9]  ©’   or 'object.event'  meaning:  handle a callback
[10] ©’
[11] ©’
[12] ©’ fax: (33.1)46.04.60.23  email: lescasse@uniware.fr
[13] ©’ (c) 1996 Eric Lescasse  [17oct96]
[14]
[15]  :select B
[16]  :case ''
[17]      :if 0=Śnc'A' ŞA„'' 'Question' 'Question' Ş :end
[18]      (C D E)„A,(˝,A)‡'''Question' 'Question'
[19]      'fmDb' Świ 'Delete'
[20]
[21]      Śwself„'fmDb'Świ 'New' 'Form' 'Close'
[22]          Świ 'scale' 5 0 0 193 305
[23]          Świ 'caption' D
[24]          Świ 'border' 19
[25]          Świ 'extent' 12.0625 38.125
[26]          Świ 'where' 11 21.875
[27]          Świ 'onFocus' 'GuiInput''Focus'''
[28]          Świ 'onWait' 'GuiInput''Wait'''
[29]
[30]      Śwself„'fmDb.bnOK' Świ 'New' 'Button'
[31]          Świ 'caption' 'OK'
[32]          Świ 'style' 1
[33]          Świ 'where' 10 220 25 75
[34]          Świ 'onClick' 'GuiInput''bnOK.Click'''
[35]
[36]      Śwself„'fmDb.bnCancel' Świ 'New' 'Button'
[37]          Świ 'caption' 'Cancel'
[38]          Świ 'style' 2
[39]          Świ 'where' 40 220 25 75
[40]          Świ 'onClick' 'GuiInput''bnCancel.Click'''
[41]
[42]      Śwself„'fmDb.lQst' Świ 'New' 'Label'
[43]          Świ 'caption' E
[44]          Świ 'where' 145 5 15 290
[45]
[46]      Śwself„'fmDb.edQst' Świ 'New' 'Edit'
[47]          Świ 'where' 165 5 20 290
[48]
[49]      R„'fmDb'Świ'Wait' C
[50]
[51]  :case 'Focus'
[52]      Świ'.edQst.Focus'
[53]
[54]  :case 'Wait'
[55]      Świ'.edQst.text' (A„ Śwarg)
[56]      Świ'.edQst.selection' (0,˝A)
[57]
[58]  :case 'bnOK.Click'
[59]      Śwself„'fmDb'
[60]      Świ'value'(Świ'.edQst.text')
[61]      A„Świ'Close'
[62]
[63]  :case 'bnCancel.Click'
[64]      Śwself„'fmDb'
[65]      Świ'value' (0 0˝0)
[66]      A„Świ'Close'
[67]
[68]  :end
’

Conclusion

I hope you have enjoyed this dialog box tutorial.

You now know the basic concepts of dialog box programming with APL+Win and you can get started design your wonderful own Windows GUI dialog boxes.

 This entire Web site has been dynamically generated by APL+Win Objects™ 6.0
 For all questions contact:  info@lescasse.com
 Copyright © 2003-2005 Lescasse Consulting. All rights reserved.