Special Edition Using Visual FoxPro 6
Special Edition Using Visual FoxPro 6
- Anatomy of a Form
- Creating Forms
- Working with Properties, Events, and Methods
- Working with Controls on a Form
- The Data Connection
- Running a Form
- Other Features of Forms
- Using Form Wizards and Builders
- Some Brand-New Form Options
- The Last Word
Nearly every application or user utility that you write in Visual FoxPro will include at least one form (and probably quite a few). Forms are the powerful descendants of pre-Visual FoxPro screens, and they serve as the primary points of user interaction with both the underlying data and business logic in most applications. The days of simple, two-dimensional, programmer-directed dialog boxes are over. User expectations have changed dramatically in recent years, and odds are you'll be expected to provide your customers with event-driven, user-controllable, Windows-standard graphical user interfaces (GUIs). The most thorough database design and most powerful programming paradigm in the world probably won't stand a chance of winning over clients if the application interface consists of white-on-blue modal screens in a Courier 12 font. Luckily, Visual FoxPro 6 includes a powerful and flexible Form Designer to assist developers in the creation of slick, flexible, fully object-oriented forms for any size application. And, as you'll see, creating and maintaining forms can be remarkably simple and straightforward.
The Visual FoxPro form is a container class, capable of holding any number of other controls or containers such as text boxes, command buttons, check boxes, pageframes, or grids. Because the form is simply a specialized container class, it supports every aspect of Visual FoxPro's powerful and thorough object-oriented programming paradigm. Forms have over 100 base properties and 60 base methods and support the addition of an unlimited number of user-defined properties or methods to augment their functionality. Forms can be inherited from specialized form subclasses or can serve as a superclass of other forms. In fact, you'll find only two major differences between forms and most other container classes: Forms can assume their own visual presence on the user desktop, and forms (like toolbars) can draw their information from a private data session.
Despite all this power, basic forms are remarkably easy to create, edit, and run. Figure 9.1 shows a basic sample form, consisting of two general sets of visual components:
- The form itself
- Controls on the form
The form itself consists of the background, on which most of the
functional contents of the form will sit. I say "most"
because it is important to remember that the form itself responds
to a set of Windows events: mouse clicks, activation, resizing,
and moving. But, in most cases, the core user functionality will
be provided by the controls within forms. Back in FoxPro 2.6 and
earlier versions, controls were placed within user-defined windows
with @SAY and GET style commands and were generally
quite limited in their capability to respond to user events. Starting
with Version 3, Visual FoxPro extended its set of native controls
and even allowed support for ActiveX components. Table 9.1 includes
a listing of native Visual FoxPro controls that are used in forms,
along with brief descriptions.
|Check box||A control that shows an On/Off state.|
|Combo box||A control that presents a list. Only the currently selected value is shown, but the rest of the list can be expanded by the user.|
|Command button||A button that the user can click to make something happen.|
|Command button group||A group of command buttons that work together.|
|Edit box||A box that enables the user to enter long strings of information.|
|Grid||A control that browses a table on a form.|
|Image||A control that shows a picture on a form.|
|Label||A control that displays text.|
|Line||A line drawn on a form.|
|List box||A box that shows a list of items.|
|OLE bound control||A control that has as its source a general field in a table.|
|OLE container control||A control for OLE objects and controls.|
|Option group||A series of options, from which the user can select only one.|
|Page frame||A control that enables the user to pick one of some number of tabs, each of which has a different set of controls.|
|Shape||A drawn shape.|
|Spinner||A combination of a text box and up and down controls, enabling the user to increment numeric data.|
|Text box||A control that enables the user to enter information, usually to be saved to a character, numeric, or date field.|
|Timer||A control that runs a command or series of commands at predetermined intervals.|
Forms are stored in .SCX and .SCT files, which are identical in structure to the class library's .VCX and .VCT files. A form, in fact, is simply a class library with only one class-the form itself. And, unlike its pre-Visual FoxPro cousin, the screen, the form doesn't need to be generated into code in order to be run. A form is a full-fledged Visual FoxPro object.
The simplest and most common way to create a form is with one of the following commands:
CREATE FORM file name
CREATE FORM file name AS superclass name FROM base library name
However, you can use one of several additional ways to create a form in Visual FoxPro. Here are just a few:
- Select File, New, Form from the system menu.
- Enter the command MODIFY FORM formname, or enter MODIFY FORM followed by an entry in the File, Open dialog box.
- Select the New button from the toolbar, and select Form in the resulting dialog box.
- Select the Docs tab of the Project Manager, click on Forms, and select New (you will be asked whether you want to use a Form Wizard or go right to creating a new form).
- Use the Component Gallery or the Class Browser.
- Enter the command
MyForm = CREATEOBJECT(<form subclass name or "Form" for base class>)
- followed by
MODIFY FORM "MyForm"
- Use one of the Visual FoxPro Form Wizards or a developer-defined Form Wizard.
The approach you use for creating new forms will depend on your own personal preference, as well as that of your fellow developers if you work in a team programming environment. You will examine the Form Wizard in the section titled "Using Form Wizards and Builders" later in this chapter. In the meantime, let's explore Visual FoxPro's Form Designer.
Many of the approaches specified use the default setting to determine the class on which the form should be based. If you do not want to use the Visual FoxPro base class, you will need to set your default by first choosing Tools, Options. Click on the Forms tab, and then check the Form check box in the Template classes area. You will be prompted to select your preferred template class. You can change this setting at any time by returning to this screen and clicking the ellipsis next to the filename (see Figure 9.2).
After you have created a new form, FoxPro will launch the Form Designer (see Figure 9.3). The most crucial elements of the Form Designer are the Form Canvas, the visual representation of the form container; the Properties Window, which shows all available property, event, and method (PEM) settings for the form and its controls; and the Form Controls toolbar, which makes available various controls that can be dropped onto the canvas. Each of these elements is covered in greater detail in this section. However, note that you can also add the following windows and toolbars to the Form Designer to assist in your design and development:
- The Color Palette toolbar-This toolbar enables you to easily set the colors on a form and any of its controls.
- The Layout toolbar-This toolbar provides the tools for properly aligning and sizing controls on the form, modifying the relative stacking order of overlapping objects, and resizing controls. (You can find more details about this toolbar in the section "Aligning Controls" later in this chapter.)
- The Form Designer toolbar-This toolbar operates at the control center, or meta-toolbar, and dictates which other Form Designer bars are shown. You can also control which toolbars are shown by selecting them from the View menu or by double-clicking their close boxes to release them.
- The Data Environment window-This window shows the specified elements of the Form's Data Environment. (You can find more details about this subject in the section titled "Setting the Form's Data Environment" later in this chapter.)
- The Code window-This window shows the code that has been added to any of the methods of the form or its controls.
Because the Form Designer enables you to view so many different components at once, you might want to consider increasing your resolution to maximize the available area. You will be shocked how much more screen real estate you gain by switching from 640 × 480, or even 800 × 600, to a 1024 × 768 resolution. And, luckily, FoxPro includes the capability to define the resolution for which you are developing, so you can see how much "real" space you have for your lower-resolution viewers (refer to Figure 9.2). One point of caution, however: When Visual FoxPro determines lower-resolution borders, it does not take into account any toolbars a user might have docked along some edge of the screen. Always leave a suitable margin, and if necessary, during your final screen testing, change your monitor's resolution to the desired settings to be sure that everything fits as you expected.
Because forms are actually classes, you might not be surprised to learn that the Form Designer and Class Designer are quite similar. You cannot modify forms in the Class Designer, though you can view and modify forms through the Class Browser. See Chapters 15, "Creating Classes with Visual FoxPro," and 16, "Managing Classes with Visual FoxPro," for more information on using the Class Designer and Class Browser.
You can add controls to a form by clicking on the desired control and then clicking on the spot on the form canvas where you want the control to reside (more specifically, click the spot where you want the top-left corner of the control to start). Visual FoxPro gives the control a default size, which you can then change by clicking on one of the corner or side placeholders and dragging to the desired boundary. Or, if you prefer to add a control and resize it in one step, you can vary these steps slightly. Click on the control you want, as usual, but instead of clicking on the form canvas, drag the mouse to create a dotted area of the desired size. Then release the mouse button to drop the resized control into this area.
Figure 9.4 shows the Form Controls toolbar, which, like the Control Palette toolbar, consists of several sections. The top two buttons are not controls, but instead are tools to control the settings for the rest of the toolbar.
The Select Objects Button The Select Objects button (with the arrow icon), at the top left of the Form Controls toolbar, indicates whether a control is currently selected and ready to be dropped. If no control is selected, the arrow button is in the down, or on, position, indicating that your mouse serves as a pointer on the form canvas. After you select a control, and while you are still deciding where to drop the control, the arrow button is in the up, or off, position. This position indicates that the mouse is currently in the drop-control mode. If you decide you don't want to drop a control you have just selected, click on the arrow button to end the process and restore your mouse to a pointing device.
The View Classes Button The View Classes button (with the bookshelf/library icon), at the top right of the Form Controls toolbar, enables you to toggle among any number of class libraries. The currently selected class library determines which controls are shown in the middle section of the toolbar. Three options are always available when you click on this button. Standard includes applicable controls from the FoxPro base classes, Active X includes Visual FoxPro's default Active X controls (such as the calendar control and the Microsoft progress bar), and Add enables you to add additional class libraries to the list. You can also add libraries to the list and assign your own names to them by selecting Tools, Options and clicking the Controls tab.
Available Controls The middle section of the Form
Controls toolbar includes all available classes from the currently
selected class library. The controls show up under the icons assigned
to them by Visual FoxPro (or by the developer during class design
of a specialized control). The standard buttons (in the order
they are shown in Figure 9.4) are as shown in Table 9.2.
|Command Button||Command Group||Option Group|
|Check Box||Combo Box||List Box|
|Timer||Page Frame||OLE Container Control|
|OLE Bound Control||Line||Shape|
The Builder Lock The Builder Lock button (with the wand icon), at the bottom of the Form Controls toolbar, controls whether adding a control should automatically launch an associated builder. You can always call any available builders after dropping a control by right-clicking and selecting Builder. The Builder Lock simply makes this a one-step process. (You'll find more details on builders in the section titled "Using Form Wizards and Builders.")
The Button Lock The default Visual FoxPro behavior is to enable you to choose and drop one instance of a control at a time. When the Button Lock button (with the padlock icon) is set on, you can click and add any number of the same controls to a form without having to return to the Form Controls Toolbar and click the control again. This capability can prove useful when you know you need 10 text boxes on a form; unfortunately, it can also prove quite irritating when you accidentally drop 17 pageframes onto the same form.
Table Part 4 discusses Visual FoxPro's properties, events, and methods (PEM) model in some detail, but to take full advantage of the Form Designer, you need to have some understanding of these concepts. What follows is a brief discussion of objects, properties, events, and methods as they apply to form design.
A form, as I've mentioned, is a container object; it is a visible
window that holds other controls. The form, like any object, is
a distinct unit with attributes and behaviors-that is, with properties,
events, and methods. The different objects available in Visual
FoxPro have a range of properties, events, and methods. Some of
them are particular to one type of object, some are available
for many objects, and others are available to all types of objects.
Table 9.3 presents the behaviors that Microsoft considers the
"core events" of Visual FoxPro.
|Init||An object is created.|
|Destroy||An object is released from memory.|
|Error||An error occurs in an event or method of the object.|
|Click||The user clicks the object using the primary mouse button.|
|DblClick||The user double-clicks the object using the primary mouse button.|
|RightClick||The user clicks the object using the secondary mouse button.|
|GotFocus||The object receives focus through a user-initiated event or through code.|
|LostFocus||The object loses focus through a user-initiated event or through code.|
|KeyPress||The user presses and releases any key.|
|MouseDown||The user presses a mouse button while the mouse pointer is over the object.|
|MouseMove||The user moves the mouse over the object.|
|MouseUp||The user releases a mouse button while the mouse pointer is over the object.|
|InteractiveChange||The value of the object is changed by the user.|
|ProgrammaticChange||The value of the object is changed in a program.|
With a firm understanding of these core events, you'll be well on your way to designing fully object-oriented Visual FoxPro forms. Of course, most Visual FoxPro objects offer you greater flexibility through additional events and methods, but these core events will give you the running start you need to begin working with forms.
As you might suspect, Visual FoxPro also has a number of common
properties (see Table 9.4). The supported values and default values
will differ by the type of object you are modifying.
|Alignment||Specifies how text is aligned in a control.|
|AutoSize||Specifies whether the control is automatically sized to fit its caption.|
|BackColor||Indicates the background color of an object.|
|BackStyle||Specifies whether the background of an object is opaque or transparent.|
|BorderColor||Specifies the color of the border around an object.|
|Caption||Specifies the text displayed within an object.|
|Comment||Provides a comment about the object. Visual FoxPro doesn't use this property; it is a freebie for developers, and might be used to describe to other programmers the purpose of the object.|
|ControlSource||Indicates the source for the control's value. Can be a field or a memory variable.|
|Enabled||Determines whether a control is enabled or disabled.|
|Height||Specifies the height of the object.|
|Left||Specifies the leftmost coordinate of the object.|
|Name||Indicates the name of the object. This value determines how the object will be referenced by other object's methods or external code.|
|Tag||Provides an extra base property to hold any additional information about the property. Can be used at developers' discretion.|
|ToolTipTest||Holds the text that will be shown as a Windows ToolTip when the mouse cursor hovers over an object. Note that ToolTips are shown only when the ShowTips property is set to .T..|
|Top||Specifies the top coordinate of the object, relative to the top of the form.|
|Value||Indicates the value for the control. If ControlSource is populated, these two properties are always equal.|
|Visible||Specifies whether an object can be seen by users.|
|Width||Specifies the width of an object.|
You can edit the properties of a form or its controls via the Properties window, which is shown in Figure 9.5. You can access the Properties window by selecting View, Properties from the system menu, or right-clicking and selecting Properties from the shortcut menu.
The Properties window consists of two parts: the Controls section and the PEM section. The Controls section, at the top of the window, consists of several important elements. The Object drop-down shows objects on the form in a hierarchical format and enables you to toggle easily to the properties, events, and methods of a particular control. The push pin enables you to force the Properties window to remain on top of any windows or toolbars in the Form Designer. The Builder Button activates the Builder for the currently selected object. (You'll learn more about Builders in the section titled "Using Form Wizards and Builders.")
The PEM section lists the properties, events, and methods of the selected object and has five tabs: All, Data, Methods, Layout, and Other. Each tab includes only those properties, events, and methods that fall under the category specified in the heading. (As you might suspect, the All tab includes all properties, events, and methods.) Each of these tabs is reviewed in more detail later in this chapter.
Each tab consists of two columns: The left side (shown with a gray background) holds the name of the property, event, or method. The right side (in white) holds the value for properties, and the words Default or User Procedure for events and methods. Note that some properties, events, and methods are read-only during design time. They have values represented in italic text and, for properties, a disabled text box on the top of the tab.
Generally speaking, changing a property is as simple as clicking the property and typing the value into the text box at the top of the tab. However, some native Visual FoxPro properties must evaluate to a particular data type, or a range of values. For instance, a logical property, such as the form's Visible setting, must be set to either .T. or .F. (and, in fact, double-clicking this property will toggle the value of such a property). Properties with a strict range of values, such as the form's WindowState property, can be entered using a combo box that will appear on top of the tab.
Does this mean that Visual FoxPro is now a strictly typed language? No, not really. You'll note that I specified that "some native Visual FoxPro properties" limit the user to a series of choices or a particular data type. User-defined properties and many native properties cannot be set up with such limitations. Keep in mind that the values for these less strictly typed properties can be entered as text (MyName), as a variable (=glMySetting), or as an expression (=3+4, or =MyFunction()). Expressions can be entered directly or can be created with some assistance from Visual FoxPro by clicking on the formula button on top of the Form Controls toolbar tab (the button marked fx). For user-defined properties, as well as some native properties, .T., .F., and .NULL. are acceptable entries. (These values must include periods on both sides to indicate to Visual FoxPro that you are referring to a value and not a variable.)
You can enter a character value for, say, a label in the PEM window in several different ways. Any of the following entries will result in a label of Last Name:
To edit the code behind a method, double-click the method name in the Properties window. When the Code window appears, you can type any code that should fire when the event occurs or the method is called. Note that you can also edit methods and events by choosing the desired object and method directly from the Code window; to do so, use the Object and Procedure pull-downs (see Figure 9.6).
After you've changed a property or a method from its default, it will appear in the Form Controls toolbar tab in bold type. To restore a property or a method to its default, right-click and select Reset To Default.
Suppose you change a label's FontName property from the Arial default to Courier, and then you change your mind and restore the property to Arial. You think it's once again set to the default, but the property value is still listed in bold. Manually resetting the original value is not the same as right-clicking and selecting Reset To Default.
Reset To Default tells FoxPro to once again accept the property's value from the object's parent. A manual resetting of FontName tells FoxPro that you want the Font property to be Arial, even if the parent class FontName is one day set to, let's say, Times Roman. Inheritance is discussed in greater detail in Part 4 of this book, but for now, remember that if you want to restore a property to the default value, the safest approach is right-clicking and selecting Reset to Default.
The Properties window includes a pageframe that lets you limit the number of properties, events, and methods that you view at one time.
The All Tab The All tab includes all PEM settings for the object specified, including user-defined properties and objects. Figure 9.7 shows the All tab for a form.
The Data Tab The Data tab shows only those properties related to the data for the control (see Figure 9.8). These properties vary according to the control being modified, but this tab might include the data control source, the control value, the input mask and format commands, and which columns of combo boxes or list boxes are bound to the underlying data. The form's Data tab includes information on the data session and buffering (see the section "Understanding Private Data Sessions" later in this chapter).
The Data tab also includes a control's Tag property and Comment property (where applicable), which serve as areas for the developer to include any additional data relating to the object that might need to be accessed. The developer can also add his or her own properties when designing a control subclass. The Tag and Comment properties have been included to provide at least one extra property on every single class, thereby adding a degree of flexibility to most controls, even those subclasses as high up in the class hierarchy as the FoxPro base classes.
The Methods Tab The Methods tab shows all methods and events, including user-defined methods. Figure 9.9 shows the Methods tab for a form object.
The Layout Tab The Layout tab shows all the native Visual FoxPro properties related to the physical appearance of the object. Figure 9.10 shows the Layout tab for a form object.
The Other Tab The Other tab shows all the native Visual FoxPro properties that do not fit logically into the Data or Layout categories. Figure 9.11 shows the Other tab for a form object.
The sheer number of properties, events, and methods in Visual FoxPro might seem daunting to you, particularly when compared with software products with fewer PEM options. Don't feel overwhelmed just yet. You will soon find that the bulk of your coding will occur in a relatively small number of methods and that you will usually change only a limited number of properties.
To find a property, event, or method in a Properties window list, you don't have to scroll through the entire list. If you know the name of the property you are looking for (or have an idea of the name), you can press Ctrl+Alt and the first letter of the name while the list has focus. The list will automatically reposition itself to the first property, event, or method starting with that letter. For example, to find the ControlSource property, press Ctrl+Alt+C when in either the All or Data tab, and the list will position to the first entry starting with the letter C.
Visual FoxPro's wide range of methods and properties allows for very precise fine-tuning (and in some cases, they have been retained for backward compatibility). Such flexibility has been a hallmark of FoxPro since its earliest incarnations, and Visual FoxPro's object model has greatly increased the number of available points of access and code execution. Enjoy the control you have as a programmer, and don't become overly entangled too quickly in the subtle differences between Valid, InteractiveChange, and LostFocus events. Use what you can (or what you already know), until you brush up against limitations and need to move on.
For instance, let's look for a moment at validation information entered in a text box. Pre-Visual FoxPro users will recognize the Valid event, but it has since been fully incorporated into the Visual FoxPro object-oriented model.
Validation of the data entered in a text box is accomplished by placing code in the Valid event. Figure 9.12 shows how to trap an invalid entry in a text box.
You might notice that the Valid event contains no code for displaying an error message. The actual text to be returned goes in the text box's ErrorMessage method. This method is automatically triggered whenever the Valid method returns False. The code for ErrorMessage is shown in Figure 9.13.
By the way, if you do not place code in the ErrorMessage method, the default error message of Invalid Input will appear (assuming that Set Notify is On).
To add a new property or method to a form, select Form, New Property or Form, New Method. A modal dialog box appears, into which you can enter the property or method name and description (optional), and click the Add button. The default value for a new property is a logical false (.F.). A new method defaults to an empty procedure; nothing will occur when this method is called until you actually add some code.
When you're adding a new property, you can tell Visual FoxPro to automatically create a new Access and/or Assign method corresponding to the new property (see Figure 9.14). You can also create an Access or Assign method at any time the same way as you would create any other new method. (For more details on Access and Assign methods, see the section titled "Access and Assign Methods.")
If you want to add a new array property, include array dimensions in the property name, even if you will later change these dimensions. Doing so automatically initializes the property as an array, which also makes the values read-only during development. You will need to write code (quite likely in your form's Init event) to fill this array property.
Visual FoxPro assumes that you will want to add more than one property or method. In fact, after you have added a new property or method, Visual FoxPro keeps providing the same dialog box. To end this cycle and save the new properties or methods you have already added, just click Close or press Escape when you are shown the new dialog box.
Properties or methods added by the user appear in the Properties window in alphabetical order after all the native Visual FoxPro properties, events, and methods. User-defined property and method names always appear in lowercase (even hacking the underlying table doesn't help).
You cannot add new properties or methods to controls from the Form Designer. Instead, you must subclass the control and add your new class. (You'll find more details on subclassing in Part 4.) Remember, though, that every control has a Tag property that you can use. Think of it as a single-property freebie. n
Access and Assign Methods Beginning with version 6, Visual FoxPro's object model has been expanded through the addition of Access and Assign methods. These methods enable you to track every time a particular property is viewed, touched, or changed in any way. Let's say that your form includes a text box that is bound to a property on the form called .cLastName, and you want a certain action to occur whenever the property is changed. You can do just that by creating a method called cLastName_Assign. cLastName_Access would be even more thorough in its tracking; every time a piece of code "looked" at the property, this method would fire.
Confused yet? Don't be. You can accomplish a good deal of programming without ever using the Access or Assign methods. In fact, that's exactly what Visual FoxPro 5 developers have been doing all along! But if you do need greater protection against outside influence on your form, Visual FoxPro 6 now provides you with that flexibility.
The Properties Window shortcut menu is among the most useful right-click menus in the entire product. Six options are available to you (seven if you count Help) and can prove quite useful when you're navigating the maze of properties, events, and methods (see Figure 9.15).
Property Descriptions Property Descriptions, the first choice in this shortcut menu, indicates whether you want to view the property descriptions at the bottom of the window. Turning this feature off saves screen space, but turning it on can greatly ease development, especially if you are new to Visual FoxPro or if you are modifying a form originally designed by someone else (and containing a number of user-defined properties and methods).
Always on Top Always on Top works just as it does throughout most of Visual FoxPro: Selecting this option guarantees that the Properties window will always be in the forefront of the screen while you are developing rather than lost beneath a maze of toolbars and other windows.
Non-Default Properties Only Selecting Non-Default Properties Only limits what is shown in the Properties window to those properties and methods that have been changed for this form. This option can help you tell at a glance what has been changed on a given form, without fishing through the dozens of default PEM settings.
Font Settings The Small Font, Medium Font, and Large Font selections enable you to choose the size of the font you want for the Properties window. The default is Small, and it's likely that you'll want to fit as many PEM settings as possible in the Properties window by keeping it that way. On a smaller monitor or a larger monitor with greater resolution, however, telling your MaxLeft from your MaxTop can be hard.
Visual FoxPro provides a full range of tools and properties for formatting controls, and you definitely should make them a part of your programming life. It's true that most programmers are not expected to also act as graphic designers. However, you should still strive for a professional and slick look and feel, especially because creating it is so easy in Visual FoxPro. Remember that forms are the primary point of user interaction with your application, and to the user, running those first forms can be like checking out a used car. We all know that a tiny dent in the fender has no firm connection to engine performance, but what if the mirrors are cracked, the doors are different colors, and the gear settings are painted over? Well, you start wondering pretty quickly about what oddities lurk beneath the hood as well, no matter how many reassurances the salesman offers you.
Take pride in how your forms look and feel, and remember that to the many users, your forms are your application. Neatness counts!
Every control has a series of format properties to assist you in fine-tuning its location on the form. Visual FoxPro also provides a series of menu options under Format to ease this process. To align a series of text boxes, for instance, start by multi-selecting the text boxes (you can do so by holding down the Ctrl key as you click or holding down the mouse button and drawing a rectangular area around the controls you want to select). Then, while the controls are still selected, select Format, Align. You can choose how you want to align the select controls: left, right, top, bottom, centered vertically, or centered horizontally. This alignment process has no effect on the alignment of text within each control. Instead, it determines how the controls sit in reference to each other.
Visual FoxPro tries to take its best guess at exactly where you want the newly aligned group of controls to reside, but if you align controls that start out quite far apart, FoxPro might end up placing them a few pixels away from where you want them to be. In that case, while the controls are still multi-selected, you can move them together by using either the mouse or the arrow keys.
The Format menu also includes a number of Size options, which enable the developer to easily size multiple controls to each other or to the gridline settings in the Form Designer. Choosing Format, Size, To Fit makes multiple controls the same height and width. Choosing Format, Size, To Grid snaps one or more controls to the same dimensions as the nearest Form Designer gridlines. The other options determine the size of multiple controls based on the tallest, shortest, widest, or most narrow selected control.
Notice that the Properties window changes slightly when you multi-select controls. The object pull-down contains the words Multiple Selection, and the window includes only properties common to all the selected controls. Changing a PEM setting changes the settings in all the selected controls.
The Spacing options in the Format menu enable you to space three or more controls equal distances apart, either vertically or horizontally. You might not notice if a series of text boxes are a few pixels more or less apart from each other. On the other hand, a data entry clerk who stares at the screen all day certainly will.
The View menu includes two options that might prove quite useful for creating an elegant form. The Grid Lines option fills in the form canvas with horizontal and vertical grid lines, enabling you to better gauge distances, as well as snap or size controls to the nearest gridlines. The Show Position option will show the exact size and location of the selected objects.
Even in our mouse-centric computer age, people still use keyboards. Personally, nothing ruffles my feathers more than opening a data entry form and trying to tab through the controls, only to find that focus jumps all over the page. Trust me: Your users will notice when this happens, and it will cost you more than a few points of credibility.
You can set tab order for controls in two ways, and the one you use will depend on your setting on the Forms tab of the Options dialog box (choose Tools, Options). The Tab Ordering pull-down includes two possible options: Interactive (the default) and By List. Selecting the Interactive option means that your controls will receive Tab focus in the order you specify in their TabOrder properties (in fact, choosing the View, Tab Order option will make the tab order visible right on the form). Selecting the By List option means that the View, Tab Order menu selection will present you with a dialog box. There, you'll see a list of controls and can manipulate the tab order as you want. Figure 9.16 shows the Tab Order dialog box.
Visual FoxPro enables you to switch to any font currently on your system. Keep in mind that not all users' PCs will have the same fonts loaded as your own PC. You can include these fonts as long as you own royalty-free copies. Sticking to the most common typefaces-Arial, Courier or Courier New, and Times Roman-is probably safer unless you are certain of all your customers' configurations.
When you drop a control onto the form canvas, Visual FoxPro automatically assigns the control a unique name, consisting of the control class and a numeric suffix (Command1, Label6, and so on). Most likely, the first property you will want to change is the control name. Many developers find it helpful to name controls in such a way that the control type and purpose are readily apparent: txtLastName, cmdProcess, chkSendMail, and so on.
Visual FoxPro does not enforce a naming scheme, outside of requiring
unique names within a container and not allowing certain characters
(spaces, slashes, hyphens, and punctuation). The naming convention
you use will depend on your own preferences or, if you work in
a team environment, existing standards. However, Microsoft does
suggest the naming convention listed in Table 9.5. Many FoxPro
developers use this scheme or one very similar to it.
Now that you've learned about designing the visual and code pieces of forms, you're ready to take a look at how FoxPro makes data available in the Form Designer. As is so often the case with Visual FoxPro, flexibility is the name of the game: Visual FoxPro enables you to access data as directly or indirectly as you want, and the Form Designer includes all the tools you need to follow your preferred approach.
Perhaps the most radical enhancement to screen development (starting with Visual FoxPro 3) has been the inclusion of a flexible and visual Data Environment to each form you design. You are free to make as much or as little use of this Data Environment as you might like, though I think you'll find too many advantages to ignore it altogether.
Every form has a built-in Data Environment that exists as a child object of the form container. You won't be able to access this special object in the ways discussed here, though; the Data Environment cannot be selected through the Properties or Code windows and it cannot be clicked and selected from anywhere on the form canvas. Instead, you can access the Data Environment by selecting View, Data Environment or by right-clicking and selecting Data Environment from the shortcut menu.
Either way, you will be shown a visual representation of the Data Environment for the form, as shown in Figure 9.17, and you can choose to add tables, cursors, or views as you like. Each is added as a Cursor object, complete with its own set of properties, events, and methods. You can visually set relations between cursor objects or access the properties, events, and methods of tables, cursors, or relations via the Properties and Code windows.
To add tables or views to the Data Environment, select Data Environment, Add, or right-click on the Data Environment designer and select Add. If a database is already open, that database and its tables or views will appear in the Add Table or View dialog box (see Figure 9.18). If no database is currently opened, or if you choose Other, a GetFile dialog box will appear for you to choose a table. If you select a table that is part of a database that is not yet open, Visual FoxPro backlinks the table to the database and opens the database automatically.
If you want to work against a view instead of a table, select the Views option button, and the list of tables will be replaced by a list of views in the database.
After you add the table or view to the Data Environment, you can browse it by right-clicking on the table or view and selecting Browse from the shortcut menu. You can also select Data Environment, Browse from the system menu, but only if the table or view has already been selected (you select it by clicking it).
Cursor objects include a logical property called .NoDataOnLoad. Setting this property to True for a cursor with an updateable view as its source will cause the cursor to start out empty. In forms designed to query specific data sets, this feature can be quite useful because it greatly enhances form loading performance. This property has no effect on local tables.
You can easily create a relationship between two cursor objects in the Data Environment. To do so, select the relation field from the parent data source, and drag it onto the child cursor. The child table must have an index on this field. If it doesn't, FoxPro offers to create one for you (see Figure 9.19).
You can switch back and forth in your form between the Data Environment and the form canvas by clicking on either. Any tables you add to a form's Data Environment will be automatically opened whenever you run the form and automatically closed after the form is destroyed. If you have set relations between several tables or cursors, these relations are reset for you each time you run an instance of the form. Gone are the days of Open_File and Close_File style functions, with file alias assignments and tag order settings and those seemingly endless strings of Set Relation To childtable Additive commands. Now, you set your Data Environment at the same time as you design your form and then (practically) never worry about it again.
In addition to filling your Data Environment with visual cursor and relation objects, you can also enter code in any of the DE events, including BeforeOpenTables, Init, and AfterCloseTables. Be careful, though, about mixing and matching visual objects and code in this case. Stumbling into a web of cyclical relations and hard-to-debug anomalies is very frustrating. FoxPro attempts to undertake a certain set of low-level events when you enter objects visually into the Data Environment (and in fact, they fire more quickly than your code will). As you become comfortable with using Data Environments, you might want to augment their functionality. Until then, try using the visual Data Environment tools for all that you can.
The Data Environment would be a helpful feature of Visual FoxPro's Form Designer even if its functionality stopped there. But it doesn't. Perhaps best of all, Visual FoxPro enables you to drag and drop data controls from the Data Environment directly onto your form, where they are instantiated as text boxes, spinners, or check boxes, along with field descriptions or names as corresponding labels. To move a field onto a form, add a table to the Data Environment, and click on the field you want to add. Drag and drop the control onto the form, and you'll notice that a label and a control appear. The label is the field description, or the field name if there is no description, and the control is precoded to be bound to the field you specified. The type of control that is created during drag-and-drop depends on the DisplayClass and DisplayLibrary settings in the Field tab of the Table Designer. (See Part 2 for more information on working with data.)
To drag multiple fields onto a form, just multi-select them by holding down the Ctrl key while clicking. To select all the fields in a view or table as individual fields, click on the word Fields on top of the table representation. To select all fields into a grid on the form, grab the title bar of the cursor object and drag and drop.
Adding controls to the form by dragging them from the Data Environment results in controls with ControlSource properties pointing to field references. That is, they are bound controls; they are directly tied to underlying tables or views, and changing the value of the control results in a corresponding change in the relevant field. Visual FoxPro makes it very easy to create forms with bound controls, and most developers choose to do so. However, Visual FoxPro also supports data manipulation through unbound controls. In other words, FoxPro lets you manipulate controls with no ControlSource, or with variables or properties as the ControlSource, and then programmatically change your data based on the control properties.
Many developers and OOP aficionados feel quite strongly one way or the other. My advice is to use what works for you: Bound controls offer many advantages, including the wonders of drag-and-drop. Unbound controls can provide you greater flexibility when you're dealing with a multitier environment, where you keep special business rules or validation methods in a separate layer of code, and let those objects take care of actually writing down data.
When you're deciding whether to bind your controls, keep in mind your current framework (if any) and your fellow developers (if any). Nothing gets muddier more quickly than a set of forms with varying approaches to the binding and writing of data. Remember that any code that relies on GetNextModifed() or other commands that read from the underlying data source will not be privy to changes in unbound controls.
One of the issues to deal with when you're working with forms that modify data is the issue of data sessions. In days gone by, FoxPro programmers jumped through a lot of hoops to guarantee that changes made to record pointers, relations, and so on, in one form did not change the settings in any other forms. Virtually anyone who programmed in FoxPro during the pre-3.0 days knows what I am talking about: macro-expansion aliases, saved and restored memory variables with every setting, and any number of less elegant and less efficient approaches.
We can be thankful that all those approaches changed with the advent of the Visual FoxPro data session. A data session is an environment of work areas and data settings. Each data session has 32,767 available work areas and a number of FoxPro settings particular to its own area of your application. In other words, a data session is a small, relatively well-protected area of your application, enabling a form to change record pointers, index orders, relations, or any other setting without affecting other forms.
Private data sessions are a very powerful feature. Basically, private data sessions enable the developer to encapsulate a form's Data Environment within itself.
You can easily assign a form its own data session. Just set the DataSession property of the form to 2 - Private Data Session.
A good way to view private data sessions in action is to run a form with the DataSession property set to 2 and then access the View window, by selecting Windows, View or typing Set in the command window. Expand the Current Session drop-down list (as shown in Figure 9.20). Note that you now have two sessions that are independent of each other. Opening or closing tables in one session will have no effect on any other data session.
With all this talk of Data Environments, bound controls, and private data sessions, you might be wondering how it all fits in with the settings in the database container. The answer is actually quite simple: After you've set up your underlying database, the form's Data Environment enables you to maintain any relevant pieces of the database within the form's own private data session. At the form level, you can change certain general data properties, such as the level of data buffering. At any point in the form code, you can change a particular data-related setting, such as Set Century On, and it will affect all data accessed in the form's session.
You'll find that the database, the Data Environment, and the form itself can each be put to use to fine-tune your data access on each form. And it doesn't stop there! You can even drag tables from the Project Manager into your Data Environment or form. Just remember, whatever exists in the Data Environment, whether visually or through code in the Data Environment Init method, will be opened every time the form is run and closed each time the form is destroyed.
Now that's you've created a form, using it is quite easy. Just type the following command in the command window, or include it in your code:
DO FORM MyForm
Is running the form really that easy? Well, yes and no. As is so often the case, Visual FoxPro offers a good deal of flexibility in referencing and releasing forms. The Name keyword enables the user to specify an alternative name for a form:
Do Form MyForm Name MyGreatForm
A form created in this manner can be manipulated by calls to MyGreatForm. You'll soon notice, though, that a Release MyGreatForm command will have no effect on the form. It's almost as if the Name clause creates a form alias but doesn't bind the form entirely to the object reference. Fortunately, the Linked clause does just that: It strengthens the form's bind to the named object reference, above and beyond simple naming and reference. Instead, the form is represented by the variable and shares its scope:
Do Form MyForm Name MyGreatForm Linked
A form created in this manner can be released by setting MyGreatForm to .Null. or by releasing the variable.
Suppose, however, that you run an instance of a form named MyMainForm by using Do Form MyMainForm Name MyForm. Then you release the MyForm variable and even set it to .NULL., but the screen doesn't close. The problem is that you must include the Linked keyword to bind a form to its object reference. Keep in mind that binding a form to a variable in this way introduces a pitfall: You must use caution when creating a form that is linked to a local (or private) variable. As soon as the variable goes out of scope, the form will be released.
By now, you should have a pretty good idea of the power (and relative ease) of the Form Designer. Now, let's turn our attention to a few important additional notes on designing and running forms, including details of some features that are brand-new to Visual FoxPro 6.
Visual FoxPro enables you to run multiple instances of forms at the same time. This feature might be needed in an application for many reasons. For instance, a phone operator might be entering information for one customer when he or she is interrupted with a request to look up data for a second customer. You don't need to adjust any special settings for FoxPro to enable multiple instances of the same form; in fact, it's the default behavior. You'll want to be sure to use private data sessions for those forms, though. Otherwise, changes to the environment made by one form will be reflected in the other (record pointers, most notably). Then you'll have to write code to deal with potential record pointer changes in your Activate() and Deactivate() commands. And no VFP programmer I know ever wants to deal with all that again.
Visual FoxPro's support of multiple form instances presents an often-overlooked fringe benefit. Programmers and developers can use this feature, along with private data sessions, to test for multiuser contention right on their own PCs. Multiple data sessions basically imitate multiple user behavior, and by firing up a few copies of your form, you can easily do what used to be so difficult: test the exact behavior your user will encounter during most cases of multiuser contention.
Form sets were included in Visual FoxPro mainly for backward compatibility issues (they are very similar to pre-3.0 screen sets), but they have since proven useful to many programmers. Form sets have several advantages over individual forms:
- Developers can show or hide multiple forms at once. Of course, you could also write a little loop to scan through active forms, but if you'll be calling such code often, why not let Visual FoxPro do the work for you?
- Forms in a form set can share the same private data session, which can be quite useful when multiple forms need to keep record pointers in sync.
- If you want a group of forms to show up in a particular arrangement, form sets enable you to make such an arrangement much more quickly than you could if you were developing each form one-by-one.
So what's the downside? Well, some programmers feel that form sets muddy the water by adding an extra level of control and removing control of some properties from our friend, the form, into its bullying higher-level cousin. But, once again, you can turn FoxPro's flexibility to your advantage. Use form sets if you find a need, and keep using them if you find them useful. Or ignore them altogether, and dive right into the single-form development paradigm.
If you have a control-laden form running against a large data source, you might notice a quick flicker across the form when the screen refreshes. Visual FoxPro forms include a special logical property, called LockScreen, that indicates whether the user's changes to the form are visible to the user. Typically, developers take advantage of this property as follows:
THISFORM.LockScreen = .T. * -- a series of checks, refreshes, and data queries THISFORM.LockScreen = .F.
Be careful when using this property. If you leave a form's LockScreen property set to True and do not include code to set it back to False, the form will remain locked and no subsequent changes will show. Also, be careful when using the LockScreen property when you're working within embedded methods. A calling procedure might have set LockScreen on or off and will expect it to return to that state when your code returns control. Follow the cardinal rule of programming: Restore anything in the environment that you have changed. The following code is a vast improvement on the preceding code:
Local llOldLockScreen llOldLockScreen = THISFORM.LockScreen THISFORM.LockScreen = .T. * -- a series of checks, refreshes, and data queries THISFORM.LockScreen = llOldLockScreen
As much as we strive to give users control over their environment, sometimes a crucial question still must be asked or a key piece of information must be entered or verified before any application functions can continue. At those moments, you can make use of Visual FoxPro modal forms.
Even younger and/or less-experienced computer users have grown used to the distinction between forms that let you "leave" or switch to another form, and those that stop you dead in your tracks and demand an answer. Modal forms are still an accepted application tool, in moderation. When you do need to develop a modal form, you can do so quite easily. Just set the form's WindowType property from 0 - Modeless (the default) to 1 - Modal. Voilà! You've created a modal form.
Another way of making a form modal is by calling its Show method with an optional parameter of 0 for Modeless or 1 for Modal. The parameter overrides the WindowType setting. The only hitch, as shown next, is that you must first hide the form to override the property. Consider this code:
Modal forms are often called in circumstances in which the programmer needs some sort of response from the user. Calling the forms is quite easy in Visual FoxPro. You can use a special version of the DO FORM command that looks like this:
Do FORM frmname to varname
The return statement, specifying the value to return, should be placed in the modal form's Unload method.
Visual FoxPro includes two sets of powerful tools for facilitating Rapid Application Development of forms. The Form Wizards create a form for you, complete with fully functional pushbutton controls for editing and navigation. The builders help you quickly design and format a particular object through a series of wizard-like questions.
Like other FoxPro wizards, the Form Wizards step you through the process of form creation by asking a series of questions about the desired form. The Form Wizards were designed to be quite easy to use and require little in the way of formal offline instruction. Let's take a few moments now to detail the process.
From the Tools menu option, select Wizards, Form. Visual FoxPro ships with two available types of Form Wizards: a basic one-record form and a one-to-many form. They are shown in the dialog box featured in Figure 9.21.
Let's assume that you want a form that is based on a single table, query, or view. Choose Form Wizard from the dialog box and click OK. You then see the first of the Form Wizard dialog boxes, as shown in Figure 9.22.
Select the desired database and associated table under the Databases and Tables options on the left. You will then see a list of available fields. You can click on the right-arrow command button to move the fields you want into the Selected Fields list, in any order you like. The double right-arrow button will move all available fields into the Selected Fields list.
The next dialog box presented by the Form Wizards asks which style you want for the form (see Figure 9.23). Your choices are Standard, Chiseled, Shadowed, Boxed, or Embossed. The magnifying glass view at the top left of the screen will change with each selection to show you an example of the style you have just selected.
In this screen, you also choose which style navigation buttons you prefer or whether you would like to use scrolling grid to navigate through your table.
The next dialog box will ask you for the sort order of the data. You can add up to three fields on which to sort by clicking each desired field in the Available Fields list and then clicking the Add button (see Figure 9.24). You can choose from fields or from any existing index tags.
The last dialog box requests whether you want to save the form, save the form and immediately run it, or save the form and immediately begin modifying the form (see Figure 9.25). You can also decide whether you would like a pageframe form if the number of fields selected cannot fit on the main form canvas. Creating forms is that simple.
The Form Wizard can be a useful tool for creating a simple form, prototyping a form, or just learning more about controls and how they work. The ease of use, however, carries with it an associated loss of control. After you become more comfortable with the Form Designer, you might begin to steer clear of the Form Wizards altogether. The choice is up to you.
Whether you've started your form design from scratch or used a wizard to get a running start, you will probably want to take advantage of Visual FoxPro's builders. Simply put, a builder is kind of like a wizard: It's a dialog box that enables you to quickly and easily define some of the basic behaviors and formats of a form and its controls. Unlike wizards, though, builders can be run again and again against the same controls. You can use builders not just to create, but to edit.
You can use the following builders in the Form Designer:
Command Group Builder
Edit Box Builder
List Box Builder
Option Group Builder
Text Box Builder
You can run the builder associated with an object in two ways:
- Select the Builder Lock button on the Form Controls toolbar. Every time you drop an object on the form canvas, the associated builder (if it exists) will run.
- Right-click the object you want to build, and select Builder from the shortcut menu.
The Text Box Builder Builders range in complexity based on the object being built. The Text Box Builder, shown in Figures 9.26 through 9.28, has three tabs of information enabling you to define how the text box should behave, including how it should look and what field in a table the text box should be bound to.
The Grid Builder The Grid Builder, shown in Figures 9.29 through 9.32, makes the formatting and design of a grid a snap. The Grid Items tab, shown in Figure 9.29, like the Form Wizard, enables you to select the fields you want to include in the grid.
The Style tab, shown in Figure 9.30, enables you to select a particular style, including a "Ledger" style that alternates white and green rows.
On the Layout tab, shown in Figure 9.31, you can specify column captions, as well as the control that will be used within the grid to show the data. For instance, you can choose here to have a spinner or an edit box embedded inside the column to show numeric or memo field data.
Finally, the Relationship tab (see Figure 9.32) helps you to define the relationship the table in the grid has with a parent table on the form. This capability is very useful when you're creating one-to-many forms.
The AutoFormat Builder Most builders work on one object in the Form Designer, but the AutoFormat Builder enables you to apply a particular style to multiple controls. Just multi-select various controls, right-click, and select Builder. Figure 9.33 shows the resulting dialog box.
Visual FoxPro 6 offers a couple of brand-new form features, which are discussed in the following sections.
One of my favorite new Visual FoxPro 6 form features is the capability to create forms with scrollbars on the side or bottom, enabling users to scroll through your form just as they would scroll through a grid, a word processing document, or an HTML page. In earlier versions of Visual FoxPro, developers had just a few choices when a form grew too long for a certain screen resolution. You could move some of the controls out to a new form (and perhaps include these forms in one FormSet), use pageframes, or take advantage of the ActiveX slider that ships with FoxPro and roll your own scrollbar-forms. The third option was quite attractive but required some specialized coding, and more important, some problems were documented with the slider control on PCs using multiple Microsoft products (newly installed products often overwrote Registry entries for previously installed sliders).
Now, scrollable forms are a native Visual FoxPro feature. The default behavior of a form is to have no scrollbars, but you can choose to include vertical scrollbars, horizontal scrollbars, or both. The Scrolled event fires every time a scrollbar is used, and VscrollSmallChange and HscrollSmallChange let the user determine how much the form scrolls for each click. ContinuousScroll indicates whether the user sees the scroll commence as soon as the scroll cursor begins moving or whether the scrolling waits until the move is done to adjust the screen (this is analogous to the form's LockScreen properties).
If your form is Sizable, Visual FoxPro takes care of activating and deactivating the scrollbars as necessary. As soon as the user makes the screen too small to fit all the controls, the scrollbars become visible.
Visual FoxPro 6 includes a new property, TitleBar, that indicates whether the form includes a title bar. Savvy developers had managed to remove title bars in versions 3 and 5, but only by manipulating a particular sequence of properties and events (shades of 2.x). The TitleBar property simplifies matters a great deal.
On the downside, when you lose the title bar, you lose some of the built-in functionality users might have come to expect. They can't minimize, maximize, resize, or move the form with the mouse any longer.
If you're like most Visual FoxPro programmers and developers, you'll spend a remarkable amount of time working inside the Form Designer. Fortunately, VFP's object-oriented programming model makes it possible to create flexible, powerful, slick forms for your applications. The tools included in the designer-from toolbars to formatting options to wizards and builders-simplify your coding and help to make VFP a true RAD tool.
Keep in mind that no VFP tool is an island. Your forms and form development process will really begin to zing after you've become familiar with other facets of Visual FoxPro. The Form Designer enables you to set some data-related properties, but even the Data Environment is no substitute for the Database Designer. Your VFP 5 code might have been remarkably quick and flexible, but odds are that your various form methods will benefit from some of the new language extensions of VFP 6. The better grasp you have of Visual FoxPro's OOP implementation, the better use you'll make of the Form Designer.
Try to find time to really delve into the Form Designer. Microsoft has packed an awful lot into it, and the more you learn about it and experiment with it, the better your applications will become.
© Copyright, Sams Publishing. All rights reserved.