OML for the complete beginner, #12

Dialog Boxes

Now that you've had the opportunity to use the InputBox command on occasion, have you ever looked at the screen display of an InputBox and wished you could change the size of the window, the location of the window, the location of the buttons inside the window, the size and number of the data entry fields, and so forth? Or just wished you could design an input window so that users could type in information and the macro could then use and play with what was typed in? There is a way to do this using dialog boxes--but be warned, the concepts are easy but the actual implementation can be extremely intimidating and aggravating.

(This is not always the case with certain other Visual Basic-based macro languages, as other macro editors often include the ability to change the size and contents of a window using mouse and menus, while the computer takes care of figuring out the programming commands needed to achieve the look you want. You may find it easier--if you have access to one of those other programs--to create a dialog box using that program, then copy it over into the PfW macro editor and make the few changes necessary to make the resulting commands compatible with OML.)

Here is the program code for a sample dialog box along the lines of what is used by the InputBox command. Note that this is completely non-functional as is, in order to better explain the various parts. Elements in angle brackets represent strings that can be included as a string or as plain text in quotation marks; square brackets designate optional elements.

  Begin Dialog <name> [x, y,] dx, dy, [<caption>]
    Text x, y, dx, dy, <text>
    TextBox x, y, dx, dy, .<func1>
    OkButton x, y, dx, dy
    CancelButton x, y, dx, dy
  End Dialog
  Dim <name2> As <name>
  [Dialog <name2>]  [z = Dialog(<name2>)]

As you can see by comparing the first line to the second to last line, the <name> of the dialog is used later on to define the way the elements in the dialog box are referenced by the rest of the macro.

The <caption> is the title (if any) you want to appear in the blue bar at the top of the window; if this is left out, the default is "Softbridge Basic Language", as you've probably seen on message boxes.

X = across, y = down. X = 1 is 1/4 the average width of a letter; since the font used does not have uniform-width letters, x = 2 is roughly the width of the letter "i", and x = 6 is roughly the width of the letter "m". Y = 1 is 1/8 of the height of a normal capital letter; y = 12 will give enough room to display the entirety of any capital letter or a letter with a tail. Dx and dy are the total width and height of the box/window being defined. In the Begin Dialog statement, x and y are optional; they define where on the screen to place the box. If they are left out, the default is a central location.

<Name2> is defined to be the results of dialog <name>; because of this, <name2>, rather than <name>, is used by the rest of the macro to refer to the various elements of the dialog box. That is, <name2>.<func1> (for example, SampleDialog.Button1) is a variable containing whatever was typed in the textbox.

For the Dialog statement, one or the other form must be used, but not both at the same time, as here. The latter method works best if the only controls you have in the box are buttons; it equates to -1 if the Ok button is pressed, 0 if the Cancel button is pressed, and 1 and higher for any user-defined buttons, in the order of the Buttons commands in the macro. The former method seems to work best when there are a lot of boxes rather than buttons. However, it requires the use of an error handling routine if you want to continue or don't want an error box to pop up, as pressing the Cancel button causes in the macro to generate a "Command failed" error.


A dialog box with some plain text and an "Ok" and a "Cancel" button is the equivalent of a MsgBox. For fancier applications, there are several commands that can be included between the Begin Dialog and End Dialog statements in order to get various "controls" (like the control knobs and buttons on a radio): boxes, buttons, text, and the like.

Button/PushButton x, y, dx, dy, "Text", [.identifier]
Button and PushButton are synonymous. X, y are coordinates relative to the dialog window (0,0 is the upper left corner of the dialog window); dx, dy are the width and height of the button. Otherwise, the four sizing controls work the same as they do for the Begin Dialog statement. "Text" is the word(s) that appear on the button, and .identifier (or any other unique word or combination of characters you can think of; always preceded by a dot) is an optional identifier you can use later on in the macro to reference whether this button was pushed or not. Clicking on a button, any button, automatically closes the dialog window and sends any results to the macro. Every dialog box must contain at least one button, be it an OkButton, a CancelButton, or a user-defined Button or PushButton; otherwise there is no way for the user to exit the dialog box and have the macro continue!

ButtonGroup .bg
ButtonGroup defines a set of buttons for use by the dialog. Later on the macro, DialogName.GroupName (in this case .bg) will identify with a number which button in the group was pushed. The first button in the group is identified as "1", the second as "2", and so forth.

CancelButton x, y, dx, dy
This creates a "Cancel" button. x, y, dx, and dy work the same as for Button (and, for that matter, all commands that use such location and sizing controls inside of a Begin Dialog...End Dialog block.) As mentioned in the discussion of the Dialog statement above, clicking the Cancel button either returns a -1 or an error, depending on which format of the Dialog command is used.

Caption "text"
Caption text$
If you didn't specify one in the Begin Dialog statement, Caption allows you to set the text in the blue bar at the very top of your dialog box. As with most instances of strings in commands, you can use plain text in quotes or use a string which was given a value earlier in the macro. Thus, the two above forms of the command are equivalent.

CheckBox x, y, dx, dy, "text", .id
This command creates a box which can be checked and un-checked. Unlike OptionButtons, checking one CheckBox has no effect on any other checkboxes in the dialog window. DialogName.id will equal 0 if the box is unchecked and 1 if it is checked.
Apples

ComboBox x, y, dx, dy text$, .id
DropComboBox x, y, dx, dy, text$, .id
These two commands are synonymous. A ComboBox combines a TextBox with a DropListBox to create a list of choices from which the user can choose or type in their own; text$ must be defined earlier in the macro, exactly the way a ListBox works. If the user clicks in the box, a cursor appears and the user can type anything, just as for a TextBox. [Note: Due to the limitations of HTML, it is not possible to type anything in the following box.]

If the user clicks the down arrow, the box drops down. Selecting an item closes the box back down to normal, with the newly selected item appearning in the box. The user may then click in the box and edit the selection as desired. After the dialog window has been closed, DialogName.id will be a string containing the selection or whatever the user typed.

DropListBox x, y, dx, dy, text$, .id
This is virtually identical to a normal ListBox, except that, unless the user is active in selecting something from the box, only the selected item is shown (the first item is the default selection). Note that text$ must be defined earlier, exactly as for a ListBox.

If the user clicks anywhere in the box or on the down arrow, the box drops down. Selecting a different item or clicking on the arrow box closes the box back down to normal, with whichever item was highlighted appearning in the box. Also, if the box is "active", pressing the first letter of an item brings that item directly into the box. After the dialog window has been closed, DialogName.id will reflect the choice made--choosing the first returns a "0", choosing the second returns a "1", and so forth.

GroupBox x, y, dx, dy, text$
This command allows you to draw a line around a section of your dialog window. If text$ is null (""), then it is a solid line all the way around; otherwise, the contents of text$ are displayed as part of the top border of the box formed by the line.

ListBox x, y, dx, dy, text$, .id
A ListBox gives the user a selection of choices, which looks something like this:

In this case, "apples", being the first item in the list, is pre-selected. If the user clicks on another selection or uses the down arrow on the keyboard to highlight a different one, then the selection box highlights the new selection. Also, if the box is "active", pressing the first letter of an item highlights that item.

The text$ element must be defined earlier in the program, and is usually made up of each element you wish to list, separated by a tab--that is, chr(9)--or in an array explicitly made up of strings. For the above example, a line would be needed before the ListBox command along the lines of one of the following lines (the second syntax below may be written on three lines, if desired):

  text$ = "apples" + chr(9) + "oranges" + chr(9) + "pears"
  text$(0) = "apples" : text$(1) = "oranges" : text$(2) = "pears"

After the dialog box has been closed, DialogName.id will reflect the choice made--if the first is chosen, DialogName.id equals 0, if the second is chosen, it equals 2, and so forth.

OkButton x, y, dx, dy
This command creates an Ok Button. Otherwise, it is functionally identical to the CancelButton command, except that it does not automatically generate an error.

OptionButton x, y, dx, dy, text$, .id
Both ListBoxes and OptionButtons allow users to select between a limited number of choices. Where ListBox does so via a single command, in which the selected choice is highlighted, OptionButtons are "radio" buttons, which fill in when they are selected, making all other OptionButtons blank. OptionButton can only be used after the OptionGroup command. Each choice requires its own OptionButton command, and if you are using OptionButtons, at least two must be used. If you want a user to be able to select an option by typing a letter, put an ampersand before that letter in text$. For example, the code fragment
  OptionGroup .id
    OptionButton 16, 12, 46, 12, "&Grapes"
    OptionButton 16, 28, 67, 8, "Grape&fruit"

will display something roughly like this:

Grapes
Grapefruit

In this case, when the macro is running, pressing "f" will change the selection to "Grapefruit". [Note: Due to the limitations of HTML, this ability is not possible here.]

OptionGroup .id
OptionGroup defines a group of OptionButton statements; it tells the computer can tell which radio buttons are linked together, so that it is possible to have multiple sets of radio buttons in the same window. DialogName.id will equal 0 if the selection defined by the first OptionButton statement is selected, 1 if the second is selected, and so forth.

StaticComboBox x, y, dx, dy, text$, .id
This command is identical to a DropComboBox, except that the list of choices is always visible.

Text x, y, dx, dy, "text"
The indicated text is printed in the dialog box, beginning at the point indicated by x & y. Dx and dy are the width and height of the text to be inserted, and work the same as other dialog statements do.

TextBox x, y, dx, dy, .id
Creates a box in which users can type in whatever they want. Later statements in the macro can reference it using MacroName.id, where .id is whatever idenfier you chose for the TextBox. There is no way to use the TextBox command itself to limit the number of characters typed in, or the type of letters (such as letters versus numbers), but applying Left$, Right$, and the like to the inputted text may achieve this effect. The inputted text is always a string, even if numbers are typed, so the Val command may be required to change an inputted number from a string value to a numerical value.


Here is a macro that creates and handles a sample dialog box:

  sub main
  StartDialog:
    Begin Dialog GetInfo 130, 60, "Name Request"
      Text 4, 4, 84, 12, "Please enter a name:"
      TextBox 4, 20, 45, 12, .UserName
      OkButton 4, 34, 40, 20
      CancelButton 45, 34, 40, 20
      PushButton 86, 34, 40, 20, "Reset"
      OptionGroup .NameOrder
        OptionButton 86, 4, 42, 12, "First Last"
        OptionButton 86, 16, 42, 12, "Last, First"
    End Dialog
    Dim NameInfo As GetInfo
    z = Dialog(NameInfo)

    If z = -1 Then
      Goto Done
    ElseIf z = 1 Then
      Goto StartDialog
    Else
      If NameInfo.UserName = "" Then
        MsgBox "'Name' is a required field."
        Goto StartDialog
      End If
    End If

    If NameInfo.NameOrder = 0 Then
      MsgBox "The name you typed was:" & NameInfo.NameOrder
    Else
      LaName$ = Trim(GetField(a$, 1, ","))
      FirName$ = Trim(GetField, a$, 2, ","))
      MsgBox "The name you typed was:" & FirName$ & " " & LaName$
    End If

  done:
  end sub

As you can see, right away the total size of the window is established, as is the title of the window. Since there are only two numbers included, the window will be automatically centered on the screen. Then comes a Text command, which simply writes the indicated text in the window you've created (in this case, instructions for what to type in the box), and a TextBox command, in which the user can type some data. After that are three button commands: an Ok button, a Cancel button, and a custom button called "Reset". The last statements before the "End Dialog" are an OptionGroup that creates two radio buttons that will dictate how the macro handles the data the user enters.

The command "z = Dialog(NameInfo)" actually displays the window on the screen, and then waits for one of the three buttons to be clicked. Once that happens, an If...Then statement block routes the program flow appropriately, depending on which button was clicked. Assuming the user typed in data and clicked the Ok button, a second If...Then statement block manipulates the entered name--if necessary, as determined by the radio buttons--so that it is in the order "first-name last-name", and displays the name in a MsgBox.


Users of a dialog box which utilizes several of the above commands will be happy to note that it is possible to jump from any control to the next one by using the Tab key, and from any control to the previous one by using the Shift-Tab key combination. This can aid users who get confused when using a mouse or who often accidentally miss a control, as repeatedly pressing Tab or Shift-Tab will cycle through all of the controls, making each "active" in turn.

And that's that. The end...?


Return to Lesson #11.
Return to Main page.