DrDialog, or: How I learned to stop worrying and love REXX - Part 4
By Thomas Klein
A warm 'Welcome back' from a guy who's still completely overwhelmed by the impressions from this year's Warpstock Europe! This month, DrDialog will show us some of the basics in REXX GUI programming, as we'll take a look on the standard components of any graphical user interface, regardless of platform.
But let's just check last month's 'homework' first... using rexx's strip() function to - well - strip leading and trailing spaces off a string. As stated in the REXX.INF file, its syntax is
STRIP(String1 [,option] [,char])
Remember that square brackets equal optional parameters:
[char] specifies the character that is to be removes from String1 and defaults to SPACE - thus, if you don't specify an explicit character here, strip() will remove spaces.
[option] is an optional command string that specifies, which characters to remove from String1: Leading, Trailing or Both. You only need to specify the first letter of the option, like 'l' if you want to remove the leading spaces. This parameter defaults to 'Both' - and strip() will remove both leading and trailing spaces if nothing was specified. To sum up things:
If you just want to remove both leading and trailing SPACE characters from String1, you only need to write
Finally strip() is a function and thus returns something. To be exact, it'll return the string that was stripped off spaces. Either you need to provide a variable to hold the return value
NEWSTRING = STRIP(String1)
or use it in conjunction with another operation like SAY that simply displays the result like in
And to show how this was meant to be used in last months example, here we go with version 1 that makes use of 'intermediate' variables:
greeting = choice.Item( choice.Select() ) greetname = strip( input.Text() ) call output.text(greeting || " " || greetname || ".")
greeting = choice.Item( choice.Select() ) greetname = input.Text() call output.text(greeting || " " || strip( greetname ) || ".")
And finally (if you prefer this one) the second version which makes use of the 'spectacular' one-line statement...:
call output.text( choice.Item( choice.Select() ) || " " || strip( input.text() ) || "."
Okay for that. Once you'll start increasing you rexx programming skills you'll deal with STRIP() on a more frequently basis. But for now, let's concentrate on what we were about to discuss today
- 1 Basic GUI components.
- 2 The "dos" and "don'ts" of GUI programming:
- 3 PUSHBUTTON - Appearance and behaviour
- 4 PUSHBUTTON - Events and Methods
- 5 CHECKBOXES - Appearance and behaviour
- 6 CHECKBOXES - Events and Methods
- 7 RADIO BUTTONS - Appearance and behaviour
- 8 RADIO BUTTONS - Events and Methods
- 9 TEXTBOX - Appearance and behaviour
- 10 TEXTBOX - Events and Methods
- 11 ENTRY FIELD - Appearance and behaviour
- 12 ENTRY FIELD - Events and Methods
- 13 MLE - Appearance and behaviour
- 14 MLE - Events and Methods
- 15 LISTBOX - Appearance and behaviour
- 16 LISTBOX - Events and Methods
- 17 COMBO BOX - Appearance and behaviour
- 18 COMBO BOX - Events and Methods
- 19 GROUP - Appearance and behaviour
- 20 GROUP - Events and Methods
- 21 (some) COMMON FUNCTIONS
Basic GUI components.
As I mentioned last month, their appearance might vary depending on the platform. But in most cases, you'll always recognise them due to the way appearance and behaviour are implemented into them... they are:
- [#PUSHBUTTON pushbutton]
- [#CHECKBOXES checkbox]
- [#RADIO_BUTTONS radiobutton]
- [#TEXTBOX textbox]
- [#ENTRY_FIELD entryfield]
- [#MLE mle (MultiLine Entry field)]
- [#LISTBOX listbox]
- [#COMBO_BOX combo box]
- [#GROUP group]
Of course, there are quite a lot more, but those mentioned above are the most basic "common ground" when taking into consideration OS/2 Warp, Windows (3.x to 2K) and Mac. I can't tell for the Linux GUI or BeOS as I never dared to look close enough <g>, but if it has a GUI, you'll find them too, I'm sure. Even when looking at Java or your webbrowser's 'form' components: Here they are again! And back in the DOS days, when character-oriented user interfaces were starting to use kind-of GUI-like graphical components they were already present in programs like Norton Utilities or PCTools
The "dos" and "don'ts" of GUI programming:
Well, most of us are almost used to interact with these components without thinking a lot about it, so you might already have an idea about what kind of user guidance task can be accomplished with specific components. Let me tell you that the world is full of funny guys who prefer to do funny things with GUI components, not taking care of 'GUI ethics'. A standard example that comes to mind is 'Optionbutton vs. Checkbox'.
Actually, option buttons are used to specify options that are mutually exclusive - that's to say you can always use only ONE of them. This is why they sometimes are called RADIO BUTTONS too; thinking of those frequency or station selector keys on old radios: Once you push one of them in a lowered position, the one that was previously selected pops up back. A typical example for radio buttons would be the image on the right.
What makes some guys funny is the fact that they absolutely don't care about self-contained logic in behaviour of controls and user guidance. Of course you are free to use all the means that you are provided with by such components. You can make a radio button group out of pushbuttons or checkboxes if you want to make life a little more complicated, but some things are better left undone like...
left: Obviously the programmer prefers to do strict input validation instead of simply using the means of the appropriate GUI �to control the input process. Using two radio buttons with one being enabled by default would have saved 'code work'...
PUSHBUTTON - Appearance and behaviour
They are quite uncomplicated to work with - the Default option in the Style dialog of a pushbutton control will make the button 'capture' the ENTER key on a dialog, even if the push button is not the currently active control. No pointer focus will disable drawing of the 'focus' square around the buttons text when it is clicked upon with the mouse. However tabbing onto the pushbutton will still show the focus square:
No border will make the pushbutton appear as almost a textbox. The 'shifting' effect of the text upon clicking the button however will remain.
PUSHBUTTON - Events and Methods
Well believe it or not: There's a click event for a push button! ;) Besides, there's the INIT event we already know from our textbox sample and a DROP event which occurs, when another DrDialog object was dropped onto the pushbutton at run time. Drag-and-Drop require additional things and although DnD is very useful and quite easy to do with DrDialog, we'll take care of it later.
CHECKBOXES - Appearance and behaviour
They're quite easy to use with DrDialog - actually a checkbox can have 3 states (unchecked, checked and 'undetermined' which will show some gray shade) but in most cases, the 2 states of checked/unchecked will do. If you want to make use of the third state in your program, invoke the Style dialog of the checkbox and watch for the 3state option. Anyway, you don't need to take a lot care of the processing behind it, if you're using its default Auto option enabled in the Style dialog.
This will automatically make the box state shift from one to the other (or next) each time the checkbox is clicked. If you deselect Auto , you'll have to provide the logic on your own by using the click event that is triggered each time the checkbox is clicked. Notice that you can't manually set the undetermined state for a box, if you disabled 3state - instead the box will be simply checked. The text that is displayed on the right of the checkbox is specified by the TEXT entry of its context menu or by calling the TEXT() function/statement in the same way we did for our textbox last month.
CHECKBOXES - Events and Methods
Like all types of controls, the CHECKBOXES generate a DROP event, if they were enabled to do so and if some other control was dragged to and dropped on them. We'll discuss Drag-and-Drop stuff later in this series, so there's two events left: INIT (we know that, don't we?) and CLICK. The CLICK event might be useful to visually clarify dependencies of options in somewhat more complex situations - I'll try to show that with an animated GIF:
For both getting and setting the state of a checkbox, you have to use the SELECT method/property. For reading the state of the checkbox you simply use SELECT in the 'function' notation:
myState = myCheckBox.select()
and it will return 0 (zero) if the box is unchecked, 1 (one) if it is checked or 2 if it is in 'undetermined' state (only available if 3state was enabled in the box Style dialog). If you want to immediately process the state - e.g. by doing something special if it is checked - you might do this by specifying an IF statement like:
if myCheckBox.select() = 1 then say 'Yes - Checked!'
If you need to set the checkbox state according to e.g. saved options in an .INI file, you simply use SELECT with its CALL-type notation:
call myCheckBox.select 1
...which checks the box. According to the states returned by the function call, you use 0 (zero) instead of 1 (one) to uncheck the box or 2 if you want to make it appear in undetermined state (again, this is only available if you enabled '3state' in the checkbox Style dialog). And that's it about checkboxes. Of course, there's a lot of stuff left like hiding the control through the VISIBLE function or enabling/disabling it by using ENABLE/DISABLE or the ENABLED function, but this applies to all types of window controls and thus will be discussed later.
RADIO BUTTONS - Appearance and behaviour
DrDialog makes designing Radio Buttons fun. All you need to create a group of radio buttons that are mutually exclusive is to put them in line (preferably vertically to provide better readability). At run time, DrDialog uses their ID to determine sequence.
If you happen to have two independent groups of radio buttons in sequence, DrDialog will recognise them as one group, as long as you don't tell him to treat them otherwise. This can be accomplished by either:
|putting any type of different control between the two groups (like a simple label)||or by drawing a group frame around them if this is 'visually preferable' in the dialog that you're intending to create:|
Again, the Auto option in the radio button Style dialog will determine whether you prefer to do the dirty work of state control for the whole group on your own. Thus, if Auto is disabled, you'll have to take care of each CLICK event that appears for any radio button of the group and need to reflect the mutually exclusiveness manually. Good luck, then.
RADIO BUTTONS - Events and Methods
It's the same as with the checkboxes. Click, Init and Drop. Period. The 'states' are even more simple than with checkboxes, as radio buttons don't come with an 'undetermined' state. Fortunately - I wonder what funny guys might be capable of creating with that... So to determine the state of an option button, you need to specify
state = myRadio1.select()
Setting a specific radio button to checked will automatically uncheck all other radio buttons within the same group. Appears to be logical. But setting a specific button to UNchecked will NOT automatically check any other button in that group - this might seem to be logical as well, because how is DrDialog supposed to know which one to check instead... but even if the group is only made of two radio buttons, this will not automatically check the other one... okay: To set the sate of a radio button, use SELECT like with the checkbox stuff (the same for the states: 0 = unchecked, 1 = checked):
call myRadio1.select 1
This would check myRadio1 and automatically uncheck all other radio buttons that are grouped together with myRadio1. Actually, most of the time you don't care about the state of a radio button but you preferably want to know WHICH ONE of a group is checked, right? Well, there is no built-in property or function in DrDialog for this, but you can accomplish it by reacting to the click events of the group radio buttons and memorize the current button into a variable. The variables contents always reflects the radio button that was just checked. Another smart way is making use of the focus upon click events, but we'll talk about that at some later time...
TEXTBOX - Appearance and behaviour
Well, we already know something about the textbox, don't we? By looking at the textbox Style dialog window, one might not think of any special clues regarding text alignment, but... there is something to mention about the Word break option in conjunction with the text alignment. If you happen to create a textbox with multiple lines of text, you MUST use a vertical alignment set to TOP or it won't work, because the text will be put on a single line. Take a look at the screenshots to figure out what I'm talking about:
This is okay - text appears entirely in textbox � / �
Text is written on a single line due to 'Vertical alignment' setting...
The horizontal alignment option will not interfere with word break and works just as expected.
To make a control appear in 'disabled' state, you actually only need to activate its Style option Disabled, which will make the control not respond to user interaction anymore and make it appear in a shaded/faded manner. However you're free to simply ignore all concepts of GUI ;) and select the Halftone option, which will make the textboxes text ALWAYS display in a 'disabled' style. This might be useful if you want to show a 'disabled' state but still want the control to be enabled to react upon user interaction. For a textbox however, there is only one event it reacts to: Dropping an object. I'm not very fond of creating such program behaviour (dropping an object on a disabled control to do something), but you might not share my ethical point of view in GUI basics. Or maybe you'll get along a programming task where you just want exactly this to be feasible, so it's good to know that this effects are available at least.
TEXTBOX - Events and Methods
Contrary to similar controls in other development tools, the text box in DrDialog does not trigger a click event... anyway: Why should it? What should be the sense in clicking on a written text? Okay, one might simulate an URL link by having an underlined text that will fire up the webbrowser if it's clicked onto, but this can surely be accomplished in other ways. So there's just the INIT event left (we already know) and the DROP event we'll discuss later.
ENTRY FIELD - Appearance and behaviour
We don't need to discuss alignment, I think. So let's take a look at the funny other things we can do with entry field behaviour: The Auto scroll option in its Style dialog should better not be unchecked in my mind - normally, when your text inputs become larger than the entry fields display size, it'll start scrolling the contents to make you see what you're typing. Disabling Auto Scroll will disable just this behaviour, requiring you to "blind type" your input. Funny. ;)
The read only option is quite self-explanatory but it's useful in some cases, as simply disabling an entry field will make its contents appear in 'halftone' which in most cases is quite difficult to read. So if you prefer an entry field to only display text (instead of using a textbox) you might use a read only entry field.
Margin simply specifies whether a border is drawn around the entry field. It has nothing to do with text margins one might know from text processing - this is why I think it was a bad idea to name it 'margin' instead of 'border', but now you know what it's about, right?
Unreadable will make asterisks appear instead of the characters you typed in your entry field. This is the 'password' effect, if you want to put it that way. But that's not all it does: Did you ever try to cut a 'password' entry fields content and paste it into - let's say - an editor? It won't work. Fortunately. I know of some 'hand-written' dialogs that didn't take care of this possibility, thus providing only a ridiculous kind of security effect... fortunately DrDialog (as all other development tools I know) takes care of this effect and disables text cut or copy from within an entry field that was set 'unreadable'. On the other hand, it still enables you to paste text into the field.
Auto tab and Max length do interact in a certain way: Max length specifies the maximum length of an input. If you set it to 5 for example, users can't type anything longer than 5 characters (space characters included). If Auto tab is specified too, it'll make the next control become active automatically, once the maximum amount of input was reached. Example:
You're having an automatic order form. There's a 5-digit part number, a quantity and a unit price to be entered. Setting the auto tab option for the part number entry field will result in the user not being forced to press the TAB key or click the mouse to change from the part number entry field to the quantity entry field. Typing the fifth digit in the part number entry field will make the cursor move automatically into the next field (determined by the controls ID). A very useful function for data input forms!
DBCS means 'double byte character set' and refers to codepages that require two bytes to store a single character, like Chinese for example. SBCS (single byte character set) is what we're used to; it requires only 1 Byte to hold a character. The SBCS/DBCS options will be discussed later - if ever I find someone that explains me what these options are about - sorry.
ENTRY FIELD - Events and Methods
Besides the INIT and DROP event, there are some interesting events that can be used with entry fields: OVERFLOW for example is triggered at each time that the user pressed a key and made the entry field contents being longer than allowed by the 'Max length' option we've just discussed above.
Changed is triggered on every change of the entry field's TEXT content. It won't be triggered if you simply select a range of characters for example.
Scrolling is quite funny: This event is triggered each time that the contents of the entry field needed to be scrolled to enable the user see what he's typing once the text becomes larger than the entry fields display size. What makes it funny is the fact, that scrolling is not by one character each time continuously but rather in chunks of three characters at once. I have no idea at the moment, why this could be useful to know. Hm.
GetFocus and LoseFocus require a little explanation first: The focus is a kind of system internal identifier that tells what CONTROL is currently the active one and thus 'attracts' the user interaction. If you ever noticed a small dotted line around a Pushbuttons text... that's indicating that the Pushbutton is the active control ("has the focus"). Now, the GetFocus event occurs if your entry field has just become the active control, that's to say the user either pressed the tab key to move into the entry field or pointed the mouse on it and clicked. This event is often used to entirely select the entry fields contents (a single keystroke will then delete the contents before new text is typed). The LoseFocus event on the other hand occurs as soon as your entry field is no longer the active control because the user clicked somewhere else or because he tabbed to the next field. Usage of this event mostly consists of data input validation (e.g. format check for dates).
Using the entry field by code is nothing extremely complicated, as you'll only use the text() function most of the time. The RANGE function can be used to control the Max length setting at run time, because changing the according bits of the Style by using the STYLE() function at run time would be a little tedious. Setting max length to 12 at run time for example is done by:
call myEntryField.RANGE 12
There is however one more function to be mentioned: Select. It deals with the selected part of the entry fields content. Users can use the shift key in combination with either mouse or cursor movements to select all or parts of the text in an entry field. And this is where SELECT comes in - it enables the programmer to detect what parts are selected by returning two values: The index of the first selected character (1 equals first character in string) and the total number of selected characters.
If for example the user selected 'ell' from the text 'Hello' the SELECT function would return '2 3' (without the quotes).
Again, you can use SELECT in its CALL type notation to SET the selected area. All you need to supply is starting character number and length. If you supply a zero for the length parameter, it'll unselect the entire text. To select the entire contents of an entry field named 'myEntryField', just issue
call myEntryField.SELECT 0, 9999
Notice that a comma is needed to separate both parameters while NO comma is contained in the return value of SELECT (when used to GET the selected area). The '0,9999' parameter is taken from DrDialog's online help. Yep, it works, but ACTUALLY one should use another call to select the entire contents, making use of rexx LENGTH() function:
call myEntryField.SELECT 1, length( myEntryField.text() )
This uses the actual length of the text contained in myEntryField as the length parameter for the SELECT function and will always start at the first position and select the entire contents based on their actual current length.
MLE - Appearance and behaviour
MLE's are actually entry fields that contain special additions to handle line breaks and multiple lines of text.
- First: They can have scrollbars to enable the user to scroll through the text.
- Second: Pressing ENTER will generate a line break (use ctrl + ENTER if a Pushbutton is having the DEFAULT style).
- Third: They recognise spaces and use them to determine word wrap for doing line breaks (if you told them so).
Notice that some combinations don't quite make sense: Activating word wrap will make sure that text is wrapped to fit to the MLEs width - no need for a horizontal scroll bar in this case. ;) Anyway - there's more important things to mention on MLE's: The option ignore tab . The MLE is capable of inserting tab characters if pressed by the user for text formatting purposes. Activation of this option will make the MLE ignore the 'formatting' function and pass the tab key on to the window system which then uses it to enable the next control (change the 'focus').
MLE - Events and Methods
As you don't have a max length option for MLEs, there's no OVERFLOW event as well. And because MLEs are made to take up multiple lines of text and usually bring their scroll bars with them, there's no need for a SCROLL event either. All that's left is the usual INIT, CHANGED, GetFocus, LoseFocus and DROP . Regarding functions, it's the same as with entry fields, except for RANGE and SELECT: They do not exist for MLEs.
LISTBOX - Appearance and behaviour
On of the most important aspects of list boxes to be taken into consideration at design time is the SELECTION Style: By default, you can only select one entry of the list. Specifying multiple will enable the user to select more than one entry by either mouse-clicking on the entries or pressing the space bar to select / unselect them. The extended selection enables the selection of a whole range of entries by using the shift key (or single entries without losing the previous selection via the ctrl key). Note that both options can be used either on their own or altogether.
Owner draw will turn off DrDialog's standard display mode for adding entries, leaving an empty list even if entries were added. I think this is intended to be used for special purposes available with other development tools or programming languages, as DrDialog can also be used to 'only' generate Dialog definitions which then can be used from other development tools. Let's not take care of this option... ;)
A horizontal scroll bar is quite useful in case that the free space on your dialog still doesn't allow you to size your listbox sufficiently to display the full length of its entries. Vertical scroll bars are always provided by the system and will be enabled as soon as there are more entries in your list than can be displayed at once.
LISTBOX - Events and Methods
Besides INIT, the FOCUS stuff and DROP, there are three events that can be used with list boxes:
- SCROLL is triggered when the list box was scrolled horizontally (!) not, if it was scrolled vertically.
- SELECT takes place each time the user (un)selected an entry that was in a different state before and
- ENTER occurs if the user double-clicked an entry or pressed the ENTER key.
On the function side, there is ADD and DELETE that can be used to control the listbox contents. Note that there is no automatic sorting of the entries when they are added to the box. You have to specifically use the appropriate parameters if you want a sorted list. If no sort parameter was specified, the Items are stuffed into the listbox in the same order as they were added.
|No sort:||call myList.ADD newitem|
|Ascending:||call myList.ADD newitem, 'A'|
|or:||call myList.ADD newitem, 'Ascending'|
|Descending:||call myList.ADD newitem, 'D'|
|or:||call myList.ADD newitem, 'Descending'|
In addition, items can be insert into the list in a particular position, (e.g. 17th place) regardless of sort order if any by specifying the desired index:
call myList.add newitem, 17
Or, to make sure the newly added entry is the last in the list:
|call myList.ADD newitem, 'L'|
|or||call myList.ADD newitem, 'LAST'|
The SELECT function/call can be used to SET or GET the selection state of a single item in the list. This looks quite difficult at first sight when taking into consideration a list that uses multiple selection, but it's quite simple. In a single selection type listbox, there is only one item that can be selected so we just need to issue
number = myList.select()
and that's it. Either number holds the list index of the selected item (1 being the first entry and so on) or it holds 0 (zero) if there ain't. In multiple selection list boxes, this function will return the index of the FIRST selected entry (if any). To get to know the other selected entries, you actually loop through all entries of the list starting with the one that follows the FIRST selected.
number = myList.select(number + 1, 'NEXT')
which will again search for the first selected entry (if any) but STARTING with the entry following the last returned one. The advantage of this way is that it speeds up processing compared to do a manual check of each entry 1 by 1 and that it works regardless whether you know the total amount of entries. To select a certain entry, you simply
call myList.select number
to select the number th entry of the list. Okay, but talking about the amount of entries... how do we get to know it? By using the listbox ITEMfunction:
It can be used to either query information about a single item or - if no parameters are passed - to return the number of items in the list:
itemcounter = myList.item()
If you need to know the actual value of the first selected entry of a list, you just combine SELECT() and ITEM() in the following way:
number = myList.SELECT() thename = myList.ITEM( number)
or in a single line:
thename = myList.ITEM( myList.SELECT() )
A very useful addition to list boxes is the VALUE that can be stored together with the actual list entry. Just imagine this to work like a second, invisible column that holds additional data. When adding an item, you can do a subsequent call that will provide the additional data to be stored along with the entry. This is useful for doing cross-references of indexes for example. We'll check this feature in a later series, let me just tell you that the VALUE is retrieved with the ITEM function as well - by specifying an additional parameter.
COMBO BOX - Appearance and behaviour
Well, those combo boxes are nothing more than a combination of an entry field along with a list box, but... that's not really all of course. an open list or to contain a droppable list - at run time you'll simply notice an entry field with a 'drop down button' attached to it. While sizing the 'open list' type at design time will actually make it look the same at run time, this is different for the 'droppable' list types: At run time, they initially appear as an entry field, but the amount of list that will be dropped by clicking the button is determined from the size you gave the drop down list at design time. Okay? Well, just take a look here:
combo box sizing (for a drop down list) at design time
this is how it'll be at run time
If you take a look at the combo box Style dialog, you'll notice three different types: Simple, Drop down and Drop down list. But what is actually the difference between the types? Behaviour of course. Simple Combobox is an entry field with a list attached to it. You can either type whatever you want or use the text to preposition the list index for further scrolling by arrow keys. This type is mostly used in cases where a user is given the choice between selecting from a list or typing his own choice. This is the same with the second type Drop down, except that it appears as an entry field that can be 'expanded' upon user request which initially saves space on your dialog screen. Still the user is allowed to type in or select.
In some cases however you might want to make sure that the user is ONLY allowed to chose from a preconfigured selection. This is where the the third type comes in: Drop down list. Although it appears just to be an entry field initially, you're not allowed to type in anything. Instead, the list is searched for the first entry whose starting character matches the one you just typed and it will be copied into the entry field part. Okay, now don't ask me what to do if you want a 'select only' combo that contains an open list part... because the answer will be: That's a listbox, man! ;)
We won't talk about the horizontal scroll bar again - it's just the same as with list boxes.
COMBO BOX - Events and Methods
While ENTER and SELECT are the same as with the listbox and INIT and DROP are the same as with all others, there's the CHANGED event we already know from the entry field. Like the entry fields SCROLL event, the combo box provides us with a SCROLLENTRY event which equally occurs when the entry field was scrolled horizontally. The reason for the different naming is, that there is another scroll event that occurs for a combo box: SCROLLLIST takes place whenever the list part of the combo box was scrolled. Finally, there's the SHOWLIST event, that is triggered upon the users request for dropping the list (when the button was clicked). Notice that the SHOWLIST event only takes place when the list is about to be shown and not, when the button might have been clicked again to make the list disappear.
Nothing exciting can be said about the FUNCTIONs available for a combo box, as they are all the same as with list boxes and entry fields, except for the fact that there is no SELECT function for the entry field part. There indeed is a SELECT function, but it deals with the list part entries, just like in the LISTBOX control. On the other hand here is something that works although it's not mentioned in the online help: As I said, a combo box is made of an entry field and a list box. But although the TEXT() function is missing from the combo box manual, it works. ;) That's good to know: You might setup a 'selection only' list, then issue
call myList.TEXT '- Select your operating system -'
and you're done with a fine GUI effect: Referencing the selected item of your list will return zero as long as the user did not select an entry. and once he did, he won't be able to reselect the headline entry '- select your...' because it has vanished since. Now, that's smart programming, isn't it? ;)
GROUP - Appearance and behaviour
Nothing much to say except for what we were talking about in the radio button part: It can be used to group controls. At design time, dragging a group frame will move all contained controls accordingly. Setting position and size of the same group frame at run time will only apply to the frame, not its contents. Halftone seems to not work - at least on my system, but selecting DISABLED of course will do... except for the fact that it only disables the group frame, not the controls contained in it - I just mentioned it for you to be aware, okay? ;)
GROUP - Events and Methods
Well, INIT and DROP again of course, but ShowMenu is quite new to us: This is triggered if the user requested a context-sensitive menu (by clicking mouse button 2). Most of the time this event is used in conjunction with the MenuPopup command of DrDialog which can be used to display self-defined context menus at run time. Again, I'll disappoint you by telling that we'll deal with menus later in the series...
(some) COMMON FUNCTIONS
Nothing magic: Used to enable or disable controls at run time like in
No to be messed up with ENABLE, because this one is able to also GET only the current state of a control, whereas the above ones are only capable of SETting the state. To know the state of a control, use
thestate = myList.ENABLED()
The return codes are 1 (enabled) or 0 (zero; disabled). They are used to set the state in the same way - to disable a control using ENABLED() type:
call myList.ENABLED 0
makes a control being shown or hidden at run time and can be equally used to only check if a control is visible or not. Quite useful if you're limited in space at run time - just hide the parts you don't need and show the ones you require. But don't abuse this too much ;) The visibility states are quite simple to memorize: 0=invisible, 1=visible To hide a listbox at run time for example, use
call myList.visible 0
And to query if a listbox is visible use
thestate = myList.visible()
When dealing with fancy effects like having buttons embedded into a picture or having multiple pictures arranged together with other controls, they sometimes are not having the right "z-order", making one control being shown 'above' another in the wrong order. To correct the "z-order" (derived from the three- dimensional scale model x-axis, y-axis and (3rd dimension:) z-axis) you can tell each control to become either the topmost or the bottommost one in that order. This is done by calling
Yeah, those ones are cute: One might simply think that they're just used to show or hide controls at run time, just like VISIBLE does, but although this is true, there's a lot more under the hood! HIDE can be used in a special way to 'turn off' the update process of a window. This is extremely useful when you want to fill a list with a lot of entries that require sorting as well. Each ADD will result in an update process of the list window, making it flash and bump its entries. If you turn off the list update, add the entries, then turn back the update on, you'll notice significant increase in speed.
Note, that the control itself will not be hidden, but only the display updates are suppressed. To make control being invisible, just like the VISIBLE function does, use
In order to simply make it suppress screen updates temporarily, use
call myControl.HIDE 'Noupdate'
instead (or use 'N' instead of 'Noupdate' to shorten it). For reactivation of the screen updates or to SHOW the control again, use
Phew! Actually this months part was meant to be rather short, but there's so much to discover, to tell, explain and take care of... and I even just mentioned the most common ones. Well, time to leave again, folks.
See you next month!