Establishing a Dialog28 Feb, 1999 By: Bill Kramer
There are several phases that one goes through when learning to program a computer. Initially, it's enough to get a handle on variables and how they can be manipulated through conditionals and loops. When learning AutoLISP, there are gradual improvements in coding style as one learns about lists and how entities are manipulated. But eventually, one reaches a difficult conceptual wall-learning how to program dialog boxes. Dialog boxes are not difficult, but they are different and do require a basic understanding of how they work. This month, we are going to explore dialog boxes in general by looking at them from the viewpoints of the AutoLISP, Visual BASIC and Visual C++ languages. Each of these languages differs in how dialog boxes are addressed; however, the concept remains the same between each of them.
Getting user input one variable at a time is how most people learn computer languages such as C++ and AutoLISP; a prompt is issued and the user can enter an answer to that prompt. Keyboard edit of the input is permitted so that mistakes made in key punching can be corrected as they are typed in.
But suppose you don't find a mistake in an entry until after the entry is complete? The only way to correct it is to restart the input sequence. Programs can use a looping structure based on verification of the input steps that allow the user to go back and start a sequence of input over again. Using default values for the input fields that are remembered from the previous iteration of the input loop will help the user. But this is still not as nice as using dialog boxes.
Why Use Dialog Boxes?
Dialog boxes are neat. They are considered modern and users generally like them more than command-line input based applications. That is not to say that command-line input is not useful. There are many applications where it makes no sense to use a dialog box and directly asking for the input is the best way. As an example, suppose you have an application that generates a complex sequence of graphics on the screen. Putting a dialog box in the way and asking the user if the screen display looks okay is not the best way to handle this situation. Instead, a command-line prompt with the option to zoom and pan is far more desirable. Another case where dialog boxes get in the way is when asking for point input. In that case, it's significantly easier to ask the operator to locate the point(s) required directly at the command line. But these input values could then be displayed in a dialog box for user verification.
Dialog boxes also reduce the time it takes to teach a user about a new application. In the "olden days," we called them input forms-sheets of paper with graphics and descriptions as needed to explain the input desired. After the user had completed the input form, it was passed on to someone to enter into the computer. This "keypunch artist" then processed the input forms into the computer to get the results for the user. Input forms can help the user by telling them more about the kind of input desired. Single-line prompts don't always work that well when you need to explain the input options as typically found in most engineering and scientific applications. Thus, dialog boxes are similar to input forms-they combine graphics and text fields to explain the input.
Dialog boxes are much better than input forms because dialog boxes are interactive. Suppose an application needs to adjust other input fields based on the result of input, as in the selection of a particular item from a list of items that have a variable number of parameters. A group of input forms might reference a separate input form, making for a larger input-form set to work with. However, a dialog box can actually change right in front of you, reflecting the type of input required as a result of the selection.
Another feature of dialog boxes is that an application can check the input as it is entered and compare it with other data fields or show the programmer how that input changes the other fields as it is entered. This sort of interaction makes for cleaner input and provides the programmer with an isolated system for handling the input to an application. When the application is finished with the dialog boxes, the input can be trusted (provided the dialog box has been programmed and tested properly). Because dialog-box components are isolated, they can be tested with smaller routines that are easy to program.
Figure 1. The path of communication when an application calls a dialog box.
Figure 2. The steps that must be performed when using a dialog box for user input.
How a Dialog Box Works
From a simplified point of view, the dialog-box system manager is a separate program. It acts as an interface between an application program and the operating system, as shown in Figure 1. An application communicates with the dialog-box manager program through a series of functions available in the language being used. For C++, these functions are part of a library that is linked when the program is compiled. For VBA, the functions are part of VBA's standard run-time library. In AutoLISP, the functions that are referenced exist inside the AutoLISP evaluator.
In the case of AutoLISP, the dialog-box manager is actually a part of AutoCAD that our programs talk to through a specific set of functions. Figure 2 shows the basic activities involved in using a dialog box inside AutoLISP. The subr (LOAD_DIALOG) is used to establish an initial link with a dialog-box source file (commonly called DCL files). The (NEW_DIALOG) subr is then used to select a specific dialog box for display on the screen. There are several subrs that are then available for setting the values in the dialog-box fields, to enable or disable them and to tell the dialog-box manager what AutoLISP functions are to be run when the dialog box fields are changed.
After our application has prepared the dialog-box details, the dialog-box manager takes over with a call to the (START_DIALOG) subr. As the user does things with the dialog box, like changing a text box or selecting a radio button, the AutoLISP functions that were linked to the dialog box are run. Things that happen in the dialog box as a result of the user are called events. These events include changing the contents of a text field or selecting a radio button. When an event occurs, the AutoLISP function linked to that dialog-box element is run so that the data can be checked and any other actions that are required as a result of the dialog-box element being selected can be done. When the user is finished with the dialog box, control is returned to the application.
From a programmer's point of view, dialog-box programming is event-driven programming. In event-driven programming, one writes small modules of code that respond to events. This is a different form of programming than most programmers are taught initially. Most programmers learn how to program in a linear fashion. In a linear program, there is some input, some processing and then some output. In an event-driven programming environment, linear-style program modules are run based on the event sequences. Another way of looking at this is that one develops a series of smaller programs that all share the same data. Some programs cannot run until others have already completed. For example, you might want to have a GO button on the screen, but the GO button should not be enabled until all the input fields are completed. Another example of an event-driven programming environment would be a process-control system that responds to events, such as a change in temperature, by running the modules that start a cooling or heating system. Dialog box programming is one of the most common forms of event-driven programming environments; this may be a difficult concept for most beginning programmers.
One negative aspect of dialog-box programming is that it does require more coding for C++ or AutoLISP programmers. For VBA programmers, dialog boxes are a natural part of the development system. However, when compared with earlier versions of BASIC, dialog-box programming tends to require a bit more code than the most basic interfaces. The reason is that dialog boxes need to be set up and the event routines written. This situation is not as bad as it may sound; the amount of code is really not that extensive.
Not only does the code need to be defined for the dialog-box interface, but the dialog box itself must be defined. For VBA and Visual C++, graphical-editing tools are part of the development environment. AutoLISP (and Visual LISP) uses a simple dialog-box language stored in ASCII text files. AutoLISP's dialog-box language contains the primary items needed for constructing simple interfaces. They are not as robust as the features (called controls) that are available in VBA and Visual C++, but most applications do not need much more than edit fields, radio buttons, toggles and images-all of which are found inside the dialog-box language of AutoLISP.
How AutoLISP Connects to a Dialog Box
The common elements that tie an AutoLISP function to a dialog box are dialog identifications and key names. Dialog identifications are established when the dialog box manager is contacted via the (LOAD_DIALOG) subr. This subr loads a dialog definition file that may contain multiple dialog-box definitions. The key name is a string defined inside the dialog-box definition file. The key name is then used in the AutoLISP function to communicate with the dialog-box element. In AutoLISP language terminology, these elements are called tiles.
Once the dialog box has been loaded and displayed using the (NEW_DIALOG) subr, a series of subrs can be employed to set up the dialog box. Many of the properties of the dialog box can also be established in the dialog-control language (DCL) source file. Essentially, there are two steps that should be performed for each dialog-box tile. First, establish the default value in the display, if applicable. (Some tiles such as push buttons do not need to have a default value established.) The second step is to establish the link between the tile and an AutoLISP expression. The expression can be a basic (SETQ) subr, or it can be a call to invoke another function that is more elaborate.
In the call-back function or expression that is linked with a tile, an application checks and saves the input values. These functions should be short and focused only on the input and related information because they will run while the user is working with the dialog box. During a call-back function, you want to save the data entered in a symbol that you can retrieve again after the dialog box is finished. Once the dialog box is finished, you can no longer access the dialog-box tile contents.
Call-back functions have certain restrictions in what they can do while the dialog box is displayed-they cannot call any command-line functions of AutoCAD nor can they do command-line input or output. This is logical when one considers that the dialog box is supposed to have control, and you would not want to be asking for point input when you can't even select items on the graphics screen.
Dialog boxes finish when a retirement button is selected or one of the call-back functions issues a (DONE_DIALOG) subr call. The most common retirement buttons are OK and CANCEL. These buttons result in the (START_DIALOG) subr returning a value of 1 or 0. The value 1 means that the OK button was pressed while 0 is used to signify the CANCEL button. An application assigns other possible return values for the (START_DIALOG) subr using (DONE_DIALOG). Only integers can be used for possible return values via a call to (DONE_DIALOG).
When the dialog box finishes, the (START_DIALOG) subr returns. A program should then test the result of the (START_DIALOG) to see what action is required next. Most of the time, an application will test for at least the OK and CANCEL options. If the result is OK, the typical dialog-box function then prepares to send the input values back to the calling program. This is accomplished by setting global (within the scope of the dialog-box function) symbols or by building a list containing the inputs to send back as the result of the function.
Figure 3. The specific functions that must be called when using a dialog box for user input through AutoLISP.
Figure 4. When the user is given the option of selecting a point in a dialog box, these specific AutoLISP functions and flow must be used.
Sometimes we need to ask for graphical input in the middle of a dialog box. To do this, the dialog box must "go away" for the input to take place. This means that the dialog-box function must loop through the steps of displaying the dialog box, filling in the tiles with values, establishing call-back functions and then starting the dialog again. This is where the (DONE_DIALOG) function is generally used the most. Suppose a button is on the dialog box that allows the operator to select a point. The call-back expression associated with the button will simply call (DONE_DIALOG 100) with the variable 100 signifying that we want point input. (The value 100 was selected as a random choice; in reality, we just don't want to use 0 and 1 as these are for CANCEL and OKAY.) When the button is pressed, the dialog box "goes away" and the result 100 is sent back for the (START_DIALOG) call. A test is then made that looks for a value of 100 (amongst other possible settings as needed by the program). If a match is found, the operator is prompted to supply a point. At this point, the program loops back to the (NEW_DIALOG) step and redisplays the dialog box. None of the tiles will have any values in them, so they must be reset with the variables the input is manipulating and the actions or call backs set up once again before (START_DIALOG) is called. Figures 3 and 4 show the difference between a function that brings up a dialog box and exits when the input is done, versus one that has an option for user-point input.
How VBA and Visual C++ Connect to Dialog Boxes
Basically, the concept behind VBA and Visual C++ are the same in regards to dialog boxes. But instead of a key name to connect the program code and dialog-box definition, an object definition is used. In other words, a dialog box and its components are classes. A feature of classes is that they have methods or functions associated with them. Thus, if you create a button control, you are really defining a new class object. This object has certain functions that need to be defined in VBA (overridden in C++) so that the button behaves as desired.
VBA's programming environment allows for easy development of dialog-based applications. A graphical editor is used to place the dialog-box components. Various properties associated with the dialog-box control can be changed, such as the name and the caption that appears. Other properties are used to define the various aspects of the control such as color, font, visibility and so forth. Double clicking the mouse on the control in the dialog editor moves the programmer to a text window for entry of the code associated with the control. VBA has the list of controls for each of the dialog-box components and a list of the functions you will most likely want to define. Actually, there are a lot of possible call-back functions that can be associated with a control in VBA, but most applications only need to use the clicked or changed call-back methods.
Looking at it from an AutoLISP programmer's perspective, the VBA editor environment for dialog boxes is tremendous. All properties are shown with a list of possible input values allowing for quick selection and edits. Unlike DCL-where the properties must be defined in advance and not changed during run time-many of the properties in a VBA dialog box can be adjusted at runtime allowing for dynamic dialog boxes to be created.
VBA falls behind AutoLISP in what can be done once the dialog box is completed. In AutoLISP, command-line commands can be issued or the entity database manipulated directly. VBA only lets the programmer manipulate the database. But the trade off is that there is a greatly expanded set of tools for manipulation of the graphical database. There are functions for computing intersections and points on objects and other advanced features not found in the AutoLISP environment.
Visual C++ is capable of issuing command-line sequences as well as direct-object manipulations in the AutoCAD drawing database. In fact, of all the choices, it is the most superior in the options it provides to the programmer. The problem with Visual C++ is the amount of programming expertise and maintenance that is required. The ObjectARX library interface for Visual C++ is quite robust and still undergoing continuous expansions. As such, the libraries change from one release of AutoCAD to the next. A greater amount of coding effort is involved in ObjectARX compared to VBA or AutoLISP-so much so that novice programmers are advised to steer away from ObjectARX until they are more comfortable with the AutoLISP and AutoCAD environments. The main reasons that ObjectARX exists are for speed and depth of access into AutoCAD. In these aspects, ObjectARX is greatly ahead of VBA and AutoLISP (and VisualLISP).
Dialog boxes are not complex to program, but they do require more coding than simple sequential input. As such, dialog boxes should be developed as separate modules in an application and tested independent of the application before being integrated into the program. This way the input from the dialog-box function can be trusted, and the programmer can concentrate on other aspects of the program.
Dialog boxes make input easier for users and can provide online help when learning the application. When users like the interface, they tend to use the software more. For programmers, there is no greater satisfaction than watching someone use the program they have written with success. If it takes a dialog box to make the user happy, then so be it!
Until next time, keep on programmin'.