Command buttons are controls provided to users so they can execute an action. In the labels example, my analysis went from general to specific and back again. In the command button example, I’ll start with a list of specific items and work back toward a general parent common to all buttons. After reaching the general class, I’ll reverse the process and work from the general to specific.
Here is a list of typical specific actions:
• Delete
• Edit
• New
• Undo
• Save
• Find
• FindFile
• GoBottom
• GoTop
• Next
• Previous
• Close
What are the requirements for the command buttons in MyFrame? You should expect that each button will invoke form methods in a uniform manner. Ideally, you should be able to specify which control should receive focus after the button’s Click() event fires. Finally, each button should be able to display a picture, text, or both.
First pass
Keep in mind, this is the first pass, and you’re not looking to define or implement code that interacts with other classes. With that in mind, ask yourself, “Are there any attributes (properties) shared by these buttons that could be ‘moved up’ the class hierarchy?” At this time the answer is “No.”
Categorizing similar classes provides a single point of access to subsequent classes. You can categorize the buttons based on the functionality they’ll provide. New, Undo, Delete, Edit, and Save (NUDES) are all data-manipulation functions. Similarly, GoTop, GoBottom, Next, and Previous are record-based navigation functions. The Close button does not have any commonalities of function with the other buttons. Leave it. Similarly, the Find and FindFile buttons do not have anything in common with the other classes. Leave them alone as well.
Although I may be getting a bit ahead of myself, each of these buttons, with the lone exception of MyGetFileCmd, calls methods on a form. However, that is not true of all command buttons. Adding an abstract class to handle the code associated with calling a form
64 Build Your Own Framework with Visual FoxPro
method gives you one place to concentrate your code for calling form methods. The name of this class is aFormCmd. The new structure is shown in Figure 4.
Figure 4. The completed Command Button hierarchy.
Second pass
Evaluate the class structure from general to specific. Beginning with aCommandButton, ask yourself, “Is there any behavior all command buttons should have?” In this case, the answer is yes. One of the requirements states that all command buttons should be able to display a picture, a caption, or both. Ideally, the user would have the ability to specify which “mode” is used on each form. Because you have not defined how the user can set personal preferences or create the classes that implement this behavior, the best you can do at this point is to define the method that implements this behavior, ConfigureDisplay(), and implement a simplified version of the code that will later comprise this method. Later, you’ll come back to this class and enable users to customize their display settings.
For now, the nDisplayType property controls whether the command button displays the caption or picture, or both the caption and the picture. The default setting is to display the command button caption. To implement this, call the ConfigureDisplay() method from the Init() method.
The programmatic class definition of aCommandButton appears as follows:
DEFINE CLASS acommandbutton AS commandbutton
*-- 1 = Text, 2 = Picture, 3 = Both nDisplayType = 1
Caption = "Command"
Name = "acommandbutton"
Chapter 6: Creating a Class Library 65
The only thing you’re going to implement at this time is the ability to configure the button display. Continue applying the question “Is there any behavior all command buttons should have?” to each button as you work toward the top of the hierarchy.
The next class in the hierarchy is aFormCmd, in which you should implement behavior that is common to all form command buttons. In this case, that is a common way to call form methods and to set focus to a control after the click.
To accomplish this, I have added the following properties to the aFormCmd class:
DEFINE CLASS aformcmd AS acommandbutton cSetFocusTo = ""
Let’s take a look at these properties, and the behaviors they control, in order.
The cSetFocusTo property and the SetFocusTo() method manage which control receives focus after the button is clicked. The SetFocusTo() method is a custom method that grabs the value in the cSetFocusTo property and uses macro substitution to get a reference to the specified control. If the control has a SetFocus() method, a call is made to set focus to that control. Here’s the code for SetFocusTo():
PROCEDURE setfocusto
66 Build Your Own Framework with Visual FoxPro
loControl.SETFOCUS() ENDIF
ENDIF ENDPROC
The next properties are cMethod, Parm1, Parm2, and Parm3. The cMethod property allows you to standardize the way in which form methods are called. The Parm properties hold parameters that can be passed to a form method. Here’s the Click() method that calls the form method.
This may seem like a lot of work just to call form methods in a uniform way. One benefit to this approach, however, is that you can also control when the button is enabled or disabled.
The following code in the Refresh() method enables or disables the button depending on whether the ACTIVEFORM has the method defined in the cMethod property.
PROCEDURE Refresh
IF TYPE('_screen.activeform')='O' AND ; ! ISNULL(_SCREEN.ACTIVEFORM) AND ;
PemStatus(_SCREEN.ACTIVEFORM,'cMethod',5)
Chapter 6: Creating a Class Library 67
IF ! EMPTY(THIS.cMethod) AND ;
PemStatus(_SCREEN.ACTIVEFORM,THIS.cMethod,5) DODEFAULT()
ELSE
THIS.ENABLED=.F.
ENDIF ENDIF ENDPROC
Note that _SCREEN.ACTIVEFORM is used rather than THISFORM. Using
_SCREEN.ACTIVEFORM allows the code to work, without change, whether the button is located in a toolbar or placed directly on a form.
The remaining controls have no additional code associated with them. You can implement all the required behavior by setting a few properties. Rather than list the class definition for all the controls, I’ll just present the Delete button class.
DEFINE CLASS mydeletecmd AS adataentrycmd
Picture = "..\images\delete.bmp"
Caption = "\<Delete"
ToolTipText = "Delete"
cmethod = "Delete"
Name = "mydeletecmd"
ENDDEFINE
One final point to note is that the hot keys and captions for each command button have been set. Working with the entire group helps you ensure that each button receives a unique hot key.
Developers often build their names from the common to the specific—for example, myCmdEdit, myCmdNew, and so on. If you are one of these developers, you may want to reconsider this convention. IntelliSense has made me much more aware of how many letters must be typed to reach a point of differentiation. For example, when typing “MyCmd_” the sixth character is the point of differentiation vs. “My_” where the third character is the point of differentiation.