Practical Standards for Microsoft Visual Basic .NET (Pro-Developer)
[Previous] [ Next ]
12.1 Give forms a consistent appearance and behavior.
Forms are the building blocks of a program's interface; if an application has a user interface, it has at least one form. Although forms are very common, many developers design them poorly. When you add a new form to a project, Visual Basic creates an empty form from a template. Usually the properties of the new form are inappropriate for the type of form you want to create. By following the Practical Applications listed in this directive, you'll create better forms.
Practical Applications
12.1.1 Assign the proper border style to every form. When you add a new form to a project, Visual Basic automatically sets the form's BorderStyle property to Sizable. More often than not, this setting is inappropriate. If a form doesn't resize its contents when the form's size is changed, chances are the border should not be sizeable. Forms are regularly used to create dialog boxes ” windows that gather information from the user. Such dialog boxes aren't supposed to have resizeable borders. The following sections describe the possible values for BorderStyle and give recommendations for when to use each value.
Fixed Dialog When BorderStyle is set to Fixed Dialog, the form has a solid border that can't be resized. (See Figure 12-1.) This is the most common border style for forms. A form with fixed borders can (and should) have a title bar and can have a control-menu box. However, you cannot put a Minimize or Maximize button on such a form; it stands to reason that if a form can't be resized, you shouldn't be able to maximize it. If you want to include a Minimize button on such a form, which is a valid idea, you must use the Fixed Single style, which I'll discuss in a moment.
NOTE
When a form's BorderStyle is set to Fixed Dialog, you can set its MinButton and MaxButton properties to True, but the corresponding buttons won't appear on the form.
None In general, every form should have a border. When a form doesn't have a border, it also lacks a title bar and a control-menu box. As a result, a form without a border can't be resized or closed without special code. (See Figure 12-2.) Such deviation from standard behavior frustrates users. Most users run multiple applications at the same time ”after all, this is a big reason to use Windows in the first place ”and not having the ability to move a form out of the way of another program is more than a bit annoying. Unless you have an incredibly good reason to do otherwise , give all forms borders.
Figure 12-2. Forms without borders violate good design principles. The valid occasions for using such forms are rare.
Fixed Single A form with BorderStyle set to Fixed Single has the same border as forms with BorderStyle set to Fixed Dialog. (See Figure 12-3.) The only real difference is that you can place Minimize and Maximize buttons on a Fixed Single form but not on a Fixed Dialog form. The ability to put a Maximize button on a form with a fixed border is not all that important. If you're not letting the user manually resize the form, you wouldn't let them make the form larger by maximizing it. However, sometimes the Minimize button is desirable. For instance, you might want to create a palette dialog box from which users can select a color or create their own, and you might decide to let users minimize the dialog box when they're not using it. When the dialog box is minimized rather than closed, all selections in the dialog box persist. When users restore the dialog box, all changes made previously, such as defining a custom color , remain just as they were left.
Sizable Setting BorderStyle to Sizable creates a form with borders that the user can drag to change the size of the form. (See Figure 12-4.) This is the default style for new forms. In general, sizeable borders should be applied only to forms that resize their contents to match the new size designated by the user.
It might be argued that using sizeable borders even for a form that doesn't resize its contents is a good idea because it allows the user to force the form to take up less screen real estate, thereby letting the user get a better view of other screen elements. However, when you size a form smaller than the area needed to display its contents, you drastically reduce the form's effectiveness. (Likewise, if a user sizes a form larger than necessary and it doesn't resize its contents, you end up with a large gray area and a puzzled user. See Figure 12-5.) If you think a user will need to make a form smaller, consider making its border Fixed Single and giving the form a Minimize button.
Figure 12-5. If you let a user resize a form that doesn't adjust its contents accordingly , unpleasant results can occur.
Fixed ToolWindow and Sizable ToolWindow The Fixed ToolWindow and Sizable ToolWindow styles are unique, and you don't often run across forms that use these styles. Tool windows are generally small dialog boxes that float over main windows of a program. Tool windows usually host tools or actions that can be applied to the main window. For instance, CorelDraw allows you to open a number of tool windows that float over the program's main drawing surface. (See Figure 12-6.) Tool windows have thinner title bars and smaller title bar text than ordinary windows. The border of a tool window can be fixed or sizeable, and it always has a Close box.
NOTE
A form shouldn't be made a tool window arbitrarily, nor should a tool window be used to save screen real estate. The difference in height between a standard title bar and a tool window title bar is too small to make much of a difference.
Consider making a form a tool window if it meets the requirements below. (Note that a form meeting these requirements shouldn't necessarily be a tool window. And if a form doesn't meet these requirements, it's almost certainly not a good candidate for a tool window.)
- The form floats over a main form.
- The form is never displayed modally.
- The form contains tools or actions that affect the main form.
Incorrect:
Figure 12-7. This form doesn't resize its contents, so it should not have a sizeable border. Also, it's not a floating tool window and therefore should not have a tool window title bar.
Correct:
12.1.2 Give every form an intelligent and consistent startup position. The position you choose for your forms is important for many reasons. If a form doesn't appear in an expected position, the user might not even realize that it's displayed. This can easily occur if the user has multiple forms open. Also, if the user's display size is smaller than the display size of the computer used to create the project, it's possible that the form will appear off the screen!
When a form is first displayed, its position is determined by the value of its StartUpPosition property. The StartUpPosition property has four possible values:
- Manual
- Center Owner
- Center Screen
- Windows Default
Avoid setting StartUpPosition to Manual; unfortunately , it can be easy to inadvertently do this. If you are developing in Visual Basic's SDI (single-document interface) mode ”see Figure 12-9 ”simply moving a form around your screen changes its StartUpPosition property to Manual. When that form displays at run time, it appears in the same location it occupied when the form was last saved. You don't want to do this. When developing in MDI (multiple-document interface) mode, each form is edited in a form designer. (See Figure 12-10.) Moving a form designer does not affect the StartUpPosition property of the form it contains. If you develop in SDI mode (as I do), get in the habit of checking the StartUpPosition properties of forms after you've finished working with them to make sure they're as you want them.
The Windows Default value is actually a throwback to earlier days of Windows programming, and it's the default value of the StartUpPosition property of all new forms. Forms with this setting appear positioned in the upper left corner of the screen, as shown in Figure 12-11. This is an acceptable, but usually not ideal, location.
Figure 12-11. Forms with StartUpPosition set to Windows Default display in the upper left corner
The Center Owner and Center Screen values are usually your best choices. When a form's StartUpPosition property is set to Center Screen, the form is displayed dead center on the user's screen, regardless of the screen resolution in effect. When a form's StartUpPosition property is set to Center Owner, the form appears centered on top of its owner form. You designate a form's owner when invoking its show method ”the second parameter is the new owner:
frmMyForm.ShowvbModal,Me |
You can use any valid form reference in place of Me , or you can omit the owner assignment altogether. If you don't indicate a specific form as the owner, the desktop becomes the owner of the form and the new form is displayed centered on the desktop (just like with the Center Screen property value). The best approach is to set all of your form's StartUpPosition properties to Center Owner. That way forms that have no designated owner, such as the first form displayed by your program, appear centered on the user's screen and subsequent forms appear centered over their owner forms, regardless of where the owners are located. (See Figure 12-12.) Remember: users can drag your forms around ”even to different monitors !
When displaying a critical dialog box, such as a notification that the printer has run out of paper, display the dialog box centered on the screen so that the user will be more likely to notice it right away.
12.1.3 Correctly unload forms and free the resources that they consume . It's a common mistake to think that unloading a form completely destroys it. Actually, when a form is unloaded, only the displayed component is unloaded; the code associated with the form module remains in memory. This means that module-level variables are preserved and that reloading the form is not the same as reinitializing it. The only way to fully unload a form is to set it equal to Nothing:
Set frmMyForm= Nothing |
NOTE
On the companion CD you'll find a project titled Form Unload Example. This simple project illustrates how modules are preserved when a form is unloaded but not set equal to Nothing.
Since you can unload a form from many places, and because a user can unload a form by clicking its Close button, you should set the form equal to Nothing in its Unload event. If Set <form> = Nothing is the only statement in the Unload event, it's relatively safe to use On Error Resume Next for the error handler. If you need to put additional statements in the Unload event, use a more robust error handler.
Unless a form is specifically designed to retain its values, set the form equal to Nothing in its Unload event. Your code will consume fewer resources, and it might perform more reliably and consistently (because each time a form is loaded, a "clean" version of the form will be created).
12.1.4 Don't create morphing forms. Morphing forms are forms that drastically change their appearance in response to some condition. Usually, the condition that causes the change is not obvious to the user, who is left completely befuddled. Imagine sitting in your living room watching television. You pop into the kitchen to have a snack . When you come back, the living room is full of different furniture, has different carpeting, and is painted a different color. All because you grabbed a Twinkie instead of a healthful vegetable. You'd be confused , right? This is exactly how a user feels when you start mucking with the appearance of a form.
When you are presenting a lot of information (or sets of information) to the user, consider using multiple specialized forms. If you need to present the information on a single form, use an advanced interface technique. These techniques include
- Tab controls to present categorized information.
- Tree view controls to present hierarchical lists. When the user selects a node, you can change the contents of an associated container control, such as a frame.
- A Microsoft Outlook-style navigation bar to present icons representing distinct items to view. When the user clicks an icon, you can change the contents of an associated container control.
These are not the only ways of presenting complicated data, but they give you a starting point. A form should behave much like a room in a house. In your house, a bathroom has one purpose and the kitchen another. Don't create a form that attempts to perform multiple duties ; it will probably end up performing all of them less than adequately.
12.2 Present controls with a standard appearance.
Many programs are datacentric programs and therefore contain lots of text boxes, combo boxes, and label controls. You should follow a few guidelines when presenting these interface elements.
Practical Applications
12.2.1 Assign text boxes and other "single-line" controls the same height as a standard combo box. Since the height of a combo box can't be changed ”it's a read-only property ”you should always use it as your base height for other single-line controls, such as text boxes. At my company, we prefer to work in pixels, and as a rule we set the ScaleMode properties of all our forms to pixels. This makes it easier to remember common settings. For instance, the combo box control has a height of 21 pixels. The odd thing is, new text boxes placed on a form are given a height of 33 pixels ”go figure! I don't believe I've ever used a 33-pixel-high text box, nor have I seen one in a commercial program. If the Visual Basic gurus would grant me the one wish of defaulting text box heights to the same height as a combo box, it would save a lot of time for everyone involved. Until I find a bottle with a genie in it, however, you'll have to make this change to your text boxes manually. Here's a shortcut I've found that works well:
- Place all your text boxes and combo boxes on your form.
- Select a combo box, and then extend the selection to include all the text boxes. Make sure that all controls are selected together by holding down the Ctrl key while selecting them, and make sure that a combo box is the first control selected.
- Double-click the Height property in the Properties window. You'll receive the error shown in Figure 12-13, but that's OK. After you click OK, the selected controls will all have the same height as the combo box.
Figure 12-13. Don't let this error bother you. When changing a property for a number of controls, Visual Basic will change that property for all controls that allow it.
When you select a group of controls and double-click a property in the Properties window, that property's existing value in the first control you selected is copied to all the controls in the group. In this example, the first control selected was the combo box. When Visual Basic copies the property value to all controls in the group, it attempts to update the property for the combo box as well as for the text boxes. Since the combo box's Height property is read-only, the error occurs. This error is benign and only slows you down by a click ”definitely worth it!
Incorrect:
Figure 12-14. The three text boxes and the combo box all have their default heights. It's pretty hard not to notice the problem.
Correct:
Figure 12-15. Give text boxes the same height as the standard combo box to create a visually appealing interface that optimizes the use of space.
12.2.2 Place labels at the proper vertical location in relation to the controls with which they coincide. Watch out when you place label controls next to other controls such as text boxes and combo boxes. Often, the top of a label isn't properly set according to the top of the control to which it's related . In addition, label text is often given incorrect justification. Figure 12-16 shows a form with all of these problems. I'm sure you don't create forms as bad as this, but the form illustrates the problem.
Figure 12-16. Properly aligning a label next to its corresponding control and setting the justification to Left Justify makes for a cleaner interface.
Here are some guidelines to follow when using label controls:
- Set each label's Autosize property to True unless you have a specific reason to do otherwise.
- Set each label's BackStyle property to Transparent unless you have a specific reason to do otherwise.
- Set the Top property of the label to four pixels greater than the Top property of the label's related control. This can be inconvenient to set up because the Visual Basic alignment tools won't do this for you. However, your form will have a better and more consistent appearance.
- Label captions should end with a colon (:).
NOTE
Check boxes have captions, but don't confuse these with label controls. The text in the caption of a check box should never end with a colon (:).
12.2.3 Give all label controls a transparent background unless you have a specific reason to do otherwise. By default, label controls are created with their BackStyle properties set to Opaque . This means that the label has a background. Fortunately, this background is the same color as the form on which it is placed. However, to ensure an appearance that is consistent with any color scheme used on the target computer, set the BackStyle property of all label controls to Transparent. (See Figure 12-17.)
Figure 12-17. All of these label controls have their BackColor property set to the system color for ButtonFace, as they should. However, notice what happens when the frame controls have BackColor changed to a yellow. The label controls with a BackStyle of opaque don't look right; those with a BackStyle of transparent look fine.
12.2.4 Disable items when they aren't available rather than hiding them. Practical Application 12.1.4 discusses morphing forms. (A morphing form alters its appearance in a drastic and not obvious way in response to an often unknown event.) Even if you don't intentionally create morphing forms, it's possible to inadvertently create minor morphing forms. One way to do this is by hiding items when they're not available instead of disabling them.
Most controls that can be placed on a form, as well as individual menu items, have Enabled and Visible properties. When you create minor morphing forms by hiding controls (that is, by setting their Visible properties to False) rather than disabling them when they're unavailable, you create an environment that is difficult for users to handle. A user can't always relate to the fact that a minute ago a menu item existed but now it's gone, or that since yesterday a form's text box for addresses has disappeared.
Another serious offense is hiding command buttons when they're temporarily unavailable. For instance, say that you have a Print button and before a user can print he must specify a file name in a text box on the form. When the text box is empty, you don't want the user to be able to click the Print button. You could (and should) place code in the command button's Click event to display a message to the user if the user tries to print without specifying a valid file name. However, this should not be the first line of defense against such an action.
If the user is not supposed to click a button, the user shouldn't be allowed to click it. However, hiding a command button is the wrong means to this end. A user might not grasp the idea that the button will appear (magically, it seems) when he enters a file name. He'll only be confused by the seeming lack of a print option. Disabling the Print button is the preferred method. When a command button is disabled, users realize that the function is present but unavailable. Most users are able to further reason that the current environment is preventing them from printing for some reason and that most likely some action on their part will enable the functionality.
Incorrect:
Figure 12-18. Where, o where, have my little buttons gone?
Correct:
Figure 12-19. Instead of hiding the buttons from the user, simply disable them to show that they are not applicable at the moment.
12.2.5 Use Tag properties judiciously (if at all). Inexperienced programmers ”and experienced programmers looking for shortcuts ”often abuse the Tag property. (Warning: this particular item is one of my pet peeves.) Almost every control has a Tag property, which is nothing more than a String property that has no intrinsic functional link with the control to which it belongs. Rather, the Tag property is available for developers to use as an extra property in any way they see fit. Unfortunately, most uses of the Tag property would be better handled with variables in code.
Using Tag properties is often cumbersome for developers and almost always confusing to others reading the code. Tag properties don't allow for any validation, and because they're of type String they're poor places to keep numeric data. Some third-party controls require that you place specific information in a Tag property, and there's usually nothing you can do about this. However, if you're using the Tag property to store your own data and you want to use such a third-party control, you've got a problem.
A number of tricks-and-tips articles show nifty little routines that allow you to stuff delimited information into a Tag property, thereby allowing you to store multiple pieces of information in a single Tag . To extract a given piece of information, you must pass the value of a Tag property through a routine that parses the string and returns the desired piece of information. This is hardly intuitive. Another negative aspect of Tag properties is that they behave much like global variables in that they have global scope and can be changed by any piece of code within the application. Chapter 6, "Variables," discusses the evils of global variables, and many of the problems described there are inherent in the Tag property.
I wish I could tell you never to use the Tag property, but that just isn't practical. However, be judicious in your use of it. More than likely, there's a better approach to the problem. If you're going to let others see your code, consider the complexity involved with deciphering Tag -referenced code. Just because you can use a Tag property doesn't mean you should . If you must use this property, give a clear and concise comment on what you're doing at every reference to the Tag property. Never assume that a reader will know what your code is doing or what you're storing in a Tag property. If you're accomplishing something particularly complex with a Tag property (and you've chosen not to take a different approach), consider writing a few paragraphs of explanatory text in the Declarations section of a module. Then, at each Tag reference, point the user to the location of the information.
Incorrect:
PrivateSub cmdPrint_Click() '*Purpose:Printthecurrentpurchaseorder. OnErrorGoTo PROC_ERR '*Preventreentrancyduetoadouble-click. If cmdPrint.Tag="InClick" ThenGoTo PROC_EXIT cmdPrint.Tag="InClick" '*Printthepurchaseorder. Call PrintPurchaseOrder '*Cleartheflagthatindicateswe'reinhere. cmdPrint.Tag="" PROC_EXIT: ExitSub PROC_ERR: Call ShowError(Me.Name,"cmdPrint_Click",Err.Number,_ Err.Description) ResumeNext EndSub |
Correct:
PrivateSub cmdPrint_Click() '*Purpose:Printthecurrentpurchaseorder. OnErrorGoTo PROC_ERR Static blnInHere AsBoolean '*Preventreentrancyduetoadouble-click. If blnInHere ThenGoTo PROC_EXIT blnInHere= True '*Printthepurchaseorder. Call PrintPurchaseOrder '*Cleartheflagthatindicateswe'reinhere. blnInHere= False PROC_EXIT: ExitSub PROC_ERR: Call ShowError(Me.Name,"cmdPrint_Click",Err.Number,_ Err.Description) ResumeNext EndSub |
12.3 Use the best interface component for a given situation.
I know: that's a pretty obvious-sounding directive. Still, although selecting a component (a control) for use on a form seems easy or trivial, many developers choose poorly. Each of the standard controls in the Visual Basic toolbox is designed for a specific purpose. When you mistakenly use one control where you should use another, your interface becomes weak at its core . It's hard to build a solid house when the foundation is weak. Knowing which control works best in a particular situation is the first step to building a solid interface.
NOTE
In many situations, an ActiveX control (such as the tree view control) is a much better choice than a standard control. This chapter, however, focuses on the correct use of the standard controls. At times, I will mention a specific ActiveX control that might be appropriate, but I won't generally discuss the details of using ActiveX controls.
Practical Applications
12.3.1 Use a text box control to display editable text. The text box, perhaps the most common of all controls, excels at displaying text that the user can edit. The text box can display small amounts or large amounts of text. The text box even adds its own scroll bars when its MultiLine property is set to True and the text box contains more text than it can display at one time.
If you're displaying text that the user can't edit, the text box might not be the best choice. Text boxes have a fair number of features. In the world of controls, more features frequently means more overhead (resources consumed). Label controls, the sole purpose of which is to display text that can't be edited, don't have near the functionality of text boxes, and therefore they use fewer resources.
In complex situations in which you have a number of pieces of text that the user can edit (text boxes) and you have one or more pieces of text for display only, you might consider using text boxes for all the pieces of text. While you can set the properties of a label control so that it looks similar to a text box, the label control will never be a perfect match. Figure 12-20 shows a text box and two label controls. If you look closely, you'll notice that the label controls display their captions one more pixel up and to the left than the text box displays its text. Although this difference is small, it's a difference nonetheless. If you have a number of static pieces of text and can get away with making them all labels, do so. If you have to mix static and editable text and all the text must look the same, you're better off using all text boxes.
Figure 12-20. Labels and text boxes can be set to appear very similar but not exactly the same.
12.3.2 Use option buttons to display static lists of five or fewer items. Options buttons are good for letting a user select an item from a very small list. In the early days of Basic, option buttons were called radio buttons because their behavior closely mimics that of the buttons on old AM/FM radios. The buttons, usually located along the bottom of the frequency display, allowed the user to select a preset listed station by pushing its corresponding button. Only one button could be selected at a time, and pushing a button caused the previously selected button to pop out. Option buttons allow the user to see all available options at one time and quickly choose among them. (See Figure 12-21.)
Figure 12-21. Option buttons work well for letting a user select a single item from a small static list.
Option buttons work only with small lists because of the amount of screen real estate needed to display the options. Option buttons should be reserved for static lists, since dynamic lists have the effect of creating morphing forms when the option button captions (and thus the physical appearance of the form) change. If you need to display dynamic lists or lists with more than five items, use a combo box, a list box, or an ActiveX control (such as the list view).
When several option buttons are placed on a form, only one button can be selected at a time. (The buttons are said to be mutually exclusive .) If you place a container control on a form and then place several option buttons in the container, only one of the buttons in the container can be selected at a time. Two option buttons can be selected at the same time as long as they are in different containers. The frame control is the best choice of container when you want to create independent sets of option buttons because it uses fewer resources than other alternatives, such as the picture box control.
Since the option buttons in a given container are closely tied to one another, it's best to make them into a control array. This makes your code easier to read, and it helps facilitate determining which button is selected. When using a set of option buttons, you eventually have to determine which button is selected. Although you can do this many ways, the best approach I've found is to add the following procedure to your project:
PrivateFunction SelectedOptionIndex(vntOptionButtonArray_ As Variant ) AsInteger '*Purpose:Determinetheselectedoptionbuttoninan '*optionbuttonarray. '*Accepts:vntOptionButtonArray-anoptionbuttonarray. '*Returns:Theindexoftheselectedbuttoninthearray. OnErrorGoTo PROC_ERR Dim optOption As OptionButton '*Loopthroughtheoptionbuttonarraylooking '*forabuttonwithitsValuepropertysettoTrue. ForEach optOption In vntOptionButtonArray '*IftheValuepropertyofthecontrolisTrue,returnit's '*indexandgetout. If optOption.Value Then SelectedOptionIndex=optOption.Index GoTo PROC_EXIT EndIf Next optOption PROC_EXIT: ExitFunction PROC_ERR: Call ShowError(Me.Name,"cmdDisplaySelectedPrintMode_Click",_ Err.Number,Err.Description) GoTo PROC_EXIT EndFunction |
Once this procedure exists in your project, you determine the selected option button in any option button array simply by calling this function and passing it the name of the array. The function returns the index of the selected option button, which you can use any way you see fit. For instance, to print the index of the selected option button in the array optPrintMode ” optPrintMode(0) , optPrintMode(1) , and so forth ”you could use the following statement:
Debug.Print SelectedOptionIndex(optPrintMode) |
NOTE
A For Each loop is used rather than a For Next loop because control arrays can have index numbers missing in their sequence. For Each will test every control, regardless of any gaps in the sequence.
12.3.3 Use a list box to display dynamic lists and static lists with over five items when space is not a concern or the user needs to see many values quickly. The list box excels at displaying large lists, allowing the user to view many items simultaneously without user intervention (such as opening a drop-down combo box). When you want to let the user select multiple items at one time, the list box is really the only standard control you can use. (See Figure 12-22.)
Figure 12-22. Multiselection list boxes with check marks to denote selection are a great user interface tool.
12.3.4 Use a combo box to display dynamic lists and static lists with over five items. The combo box is perhaps the best all-around control for letting users select items from a list. Although the combo box allows the user to select an item from both short and long lists, the amount of screen real estate required remains the same (when using the standard combo box styles).
NOTE
The combo box can be displayed in one of two ways, depending on the value of its Style property. (See Figure 12-23.) The preferred way is achieved with a Style of Dropdown Combo or Dropdown List. Although the combo box still supports the Simple Combo style, this style is generally considered antiquated, and you should avoid using it in your interfaces.
Figure 12-23. Combo boxes can be either standard (dropdown style) or simple. You should avoid using the simple combo box in your programs.
Unless screen real estate is particularly sparse, consider using a set of option buttons for static lists of five items or less. For static lists of three items or less, it's definitely best to use a set of option buttons.
12.3.5 Use check boxes to let users toggle options in small, static lists. When allowing users to select and deselect items (such as program options), use check boxes whenever possible. (See Figure 12-24.) Note that unlike option buttons, several check boxes in a group can be selected at the same time. The multiselection list box now supports check boxes ”refer to Figure 12-22 ”but, in general, a set of dedicated check box controls is better, unless the list is quite large or is built from a dynamic list (such as being filled from a database table).
Figure 12-24. Use check boxes to let the user toggle options.
12.3.6 Use a picture box control only when absolutely necessary. Picture box controls consume more resources than most other standard controls, and they're often used unnecessarily. There's usually a control that is a better choice than the picture box. For instance, to display pictures loaded from a file ”and nothing more ”the image control is a far better choice than the picture box. The image control doesn't let you perform advanced actions, such as drawing shapes or printing text, but it does use considerably fewer resources (thus loading faster and using less memory) than the picture box.
Another common misuse of the picture box is as a parent or container control. To create independent sets of option buttons on a form, for example, you must place each set in a different container control. The picture box is usually the worst choice of container in these cases. If you don't need the unique functionality provided by the picture box control, such as the ability to draw or print on the control, you shouldn't consume the additional resources required by a picture box. Often, the simple frame control is the best choice as a parent control. (You can turn off the frame's border, if necessary.)
NOTE
The primary drawback of using frame controls as parent controls is that they don't have their own ScaleMode property, and therefore all coordinates in the frame are specified in twips, which are often harder to use than pixels. If you like to place controls by using pixels, add the controls to a picture box with its ScaleMode set to pixels. When you are happy with the arrangement, cut the controls from the picture box, paste them on a frame, and then delete the picture box control.
I blame the common misuse of the picture box on the way Visual Basic is taught in most classes and books. The picture box is used in most examples and lessons because of its amazing functionality and flexibility. Unfortunately, a caveat is rarely offered , and bad habits are born.
12.3.7 Use a scroll bar to indicate quantity or speed. Scroll bars are fairly common controls, but they usually appear as part of other controls, such as within combo boxes and list boxes. Rarely do you encounter a stand-alone scroll bar control. Scroll bars are good controls for indicating a speed or a quantity. To indicate speed, the value of the scroll bar is updated programmatically to keep it in sync with some time-related activity. More often, however, scroll bars are used to show quantity. The volume setting in a game is a good application of the scroll bar, as is allowing the user to scroll through a picture. (See Figure 12-25.) The scroll bar control can also be used to select from non-numeric yet sequential options. For instance, a game program might have a graphic detail option that can be set to Minimum, Sparse, Average, Busy, or Wow. Since these items form an increasing sequence, a scroll bar could be used to select among them. However, unless there are more than five such options, using option button controls is generally a better choice.
Figure 12-25. Using scroll bars in conjunction with a picture box, you can create image-view ports like the one shown here.
12.4 Provide comprehensive and sensible menus .
Although you might rely heavily on your mouse or another pointing device to perform design tasks while in Windows, many Windows users are keyboard users, using a mouse only when absolutely necessary. Data entry people, in particular, never take their hands off the keyboard. Many software companies receive support calls from angry customers because a commonly accessed function is accessible with a mouse only. Menus are the easiest way for a user who relies on the keyboard to navigate your program, and every program you create should make its features easily accessible through logical menus.
NOTE
New users of an application often scan the menus before opening a manual. (Heck, most users never open the manual!) When you provide comprehensive menus, you make your program more intuitive and easier to learn and use.
Practical Applications
12.4.1 Format and organize menus in a manner consistent with other popular Windows applications. When designing your menus, look at some of the many popular Windows applications available and consider the similarities and differences between their menus and yours. Although your application might be quite unique and therefore have very different menus than other applications, there are probably similarities as well. When possible, make items in your application follow the same structure and design as similar items in the other programs. For example, almost every Windows program has at least a File menu and a Help menu. The File menu is always the first drop-down menu on a menu bar, and the Help menu is the last ”you should never deviate from this organization.
Consistent menu organization goes much deeper than the order and presence of top-level menu items, however. If you take a look at a number of popular Windows programs (not just Microsoft's), you'll see many consistencies. For instance, if the program supports a New function, the corresponding menu item is always the first item on the File menu; you'll never see it on the Edit menu, for example.
When a menu command is used to display a dialog box in which the user must enter more information before the command can execute, the menu command is followed by an ellipsis (). Don't use ellipses for menu commands that execute functions directly. People are accustomed to this, and you should oblige them by providing them with this information. It's easy, and there's no reason not to do it.
The tables appearing throughout the remainder of this chapter show the common commands of the most widespread drop-down menus. These tables aren't all-inclusive, but they should help you design great menus. The underlined letter in some of the commands denotes the key that you should assign as the access key. You create access keys by prefacing the desired letter with an ampersand in the menu editor, as shown in Figure 12-26.
Figure 12-26. Access keys are assigned much like accelerator keys in a label's caption ”preface the letter with an ampersand.
A number of items in the lists are labeled Disable when appropriate . Most of these are menu commands that perform an action based on an active file (a file that is opened by the user). If the user doesn't have a file open, disable the menu commands by using the Enabled property. Do not hide the menu item by setting its Visible property to False. Also, the items are listed in each table in the order in which they should appear on the menu.
File Menu: The Common Commands
Command | Description |
---|---|
N ew | Creates a new file. (The type of file ”that is, document, database and so on ”is determined by the application.) |
O pen | Displays the Open Dialog box from which the user can select a file to open. |
C lose | Closes the active window. (Disable when appropriate.) |
S ave | Save changes to the current (active file). (Disable when appropriate.) |
Save A s | Displays the Save As dialog box so that the user can specify a file name, and then saves the current file under that name. (Disable when appropriate.) |
Save A l l | Saves all the currently opened files. (Disable when appropriate.) |
F ind File | Displays the Find File dialog box with which the user can locate a file. |
Page Set u p | Displays the Page Setup dialog box. (Disable when appropriate.) |
Print Pre v iew | Displays the current file as it will look when printed. (Disable when appropriate.) |
Most Recently Used List | Lists the most frequently accessed files in the order in which they were opened (newest to oldest). Selecting one of these items opens the corresponding file. |
E x it | Terminates the application, closing all windows and files. Prompts the user to save changes when appropriate. |
End Menu: Common Commands
Command | Description |
---|---|
U ndo | Nullifies the last command performed by the user, restoring the document to the state it was in before the action was performed. |
R epeat | Repeats the last command executed by the user. |
Cu t | Deletes the current selection and moves a copy of it to the Clipboard. |
C opy | Copies the current selection to the Clipboard but leaves the selection unaffected. |
P aste | Inserts a copy of the contents of the Clipboard at the current insertion point. |
Cle a r | Deletes the current selection but does not move a copy to the Clipboard. |
Select A l l | Selects the entire contents of the active file. This is most applicable in documentcentric programs. |
F ind | Displays the Find dialog box, which the user can use to locate information (traditionally, text). |
R e place | Displays the Replace dialog box. The Replace dialog box is often the Find dialog box with a replace feature activated. |
View Menu: Common Commands
Command | Description |
---|---|
F u ll Screen | Changes the view to fill the entire screen. |
T oolbars | Displays the Toolbars submenu, allowing the user to choose which toolbars to display. |
Z oom | Displays the Zoom dialog box. (This is mostly applicable to documentcentric programs.) |
Insert Menu: Common Commands
Command | Description |
---|---|
General application items | Commands specific to the program should be placed at the top of the menu. |
Fi l e | Displays a variation of the Open dialog box from which the user can select a file to insert at the current insertion point. |
P icture | Displays a variation of the Open dialog box from which the user can select a picture file to insert at the current insertion point. Consider having this dialog box contain a clipart viewer. |
Tools Menu: Common Commands
Command | Description |
---|---|
General application tools | Commands specific to the program should be placed at the top of the menu. |
M acro | Displays the Macro dialog box from which users can create and manage macros. |
O ptions | Displays the Options dialog box for the entire program. |
Window Menu: Common Commands (Mostly Applicable to MDI Applications)
Command | Description |
---|---|
N ew Window | Opens a new window, displaying the current file within it. |
A rrange All | Arranges all currently opened windows in some predetermined format. |
S plit | Lets the user split the window into two parts . |
Window list | Displays a numbered list of all currently opened files. Selecting an item in the list activates the window containing the file. |
Help Menu: Common Commands
Command | Description |
---|---|
Product Name H elp | Displays the Windows Help program for the current application. |
(Separator bar) | Used to separate the application Help from the rest of the Help commands. |
Application-specific entries | Includes items such as tutorials, Web links, and customer support information. |
A bout product name | Displays a standard About dialog box containing information about the program. |
12.4.2 Assign shortcut keys to frequently used menu items. A shortcut key (also referred to as an accelerator key or a hot key) is a keyboard combination that causes a menu command to be invoked without the user having to access the menu. Never underestimate the importance that users place on shortcut keys. Chances are you're using some shortcut keys while developing with Visual Basic, and you'd probably be pretty unhappy to find them removed in a future version. I, for one, would be lost without the ability to press F5 to compile and run or Ctrl+F5 to start with a full compile.
Shortcut keys appear on drop-down menus to the right of menu items' captions. (See Figure 12-27.) Shortcut keys are defined using the Menu Editor dialog box. It's beyond the scope of this book to teach you how to build menus, so I won't go into details on creating shortcut keys. The important thing here is understanding the idea behind them and their importance so that you will use them constructively in your programs.
Figure 12-27. Shortcut keys are usually displayed to the right of menu commands. Pressing the key combination triggers the command, and the menu doesn't even have to be opened.
NOTE
Although Visual Basic provides you with the Menu Editor dialog box to create menus, the tool is pretty weak. Each menu item must be defined as a single entity, menu items can't be automatically placed on toolbars, each uniquely named menu item fires its own event, and you can't even put pictures on the menus without resorting to some complicated API calls. This might be the first time I've mentioned a third-party product in one of my books, but I have to say that I use ActiveBar from Data Dynamics in all my applications. I won't say much more than that it allows you to create powerful menus and toolbars without touching Visual Basic's menu editor and that if you're interested in a seriously cool tool for building powerful menus and toolbars, you should check it out for yourself.
Shortcut keys are key combinations generally consisting of a Ctrl, Shift, or Alt key or some combination thereof being held while pressing a letter or a function key. Shortcut keys can also be function keys without modifiers (such as the shortcut key F7 in Microsoft Word used to run the spelling checker). Of course, the variations are finite, and you'll have to carefully consider how to assign them in your program. First consider the basic shortcut keys listed in the Basic Shortcut Keys table in this section, and apply them to your menu items if applicable. Next list the functions accessed by your menu items in the order that you expect them to be most frequently used, and start assigning shortcut keys to the items at the top of the list. Avoid using common shortcut keys found in the following table for uses different than those listed ”users are probably accustomed to those keys having meanings other than yours.
Although it's not always possible, try to assign logical key combinations. Obviously, the meaning of, say, F6 is hardly logical, but when assigning modifiers such as Alt with another character you have some flexibility. For instance, the key combination of Ctrl+Q might be a more intuitive shortcut key for Quit Payroll than Ctrl+T.
There are essentially two types of shortcut keys: basic and extended. Basic shortcut keys are suitable in most applications, and you're encouraged to implement as many of them as possible in your programs. If you don't implement a particular basic shortcut key as defined in the coming table, don't use the shortcut key for something else in your program; most users are accustomed to these shortcut keys performing these functions.
The extended shortcut keys are completely optional, and they correspond to features that you might or might not have in your program. If your program supports a listed feature, you're strongly encouraged to use the associated shortcut key. If not, feel free to use the extended shortcut keys in your application as you see fit.
Basic Shortcut Keys
Shortcut | Menu/Command |
---|---|
Ctrl+N | FileNew or its equivalent |
Ctrl+O | FileOpen |
Ctrl+S | FileSave |
Ctrl+P | FilePrint |
Ctrl+Z | EditUndo |
Ctrl+Y | EditRepeat |
Ctrl+X | EditCut |
Ctrl+C | EditCopy |
Ctrl+V | EditPaste |
Delete | EditClear |
Ctrl+A | EditSelect All |
F1 | Context Help (Note: this is not displayed on the menu.) |
Extended Shortcut Keys
Shortcut | Menu/Command |
---|---|
Ctrl+W | FileClose (Note: displaying this on the menu is optional.) |
Ctrl+Alt+O | ViewOutline |
Ctrl+D | FormatFont |
Ctrl+E | FormatCenter align |
Ctrl+J | FormatJustify align |
Ctrl+L | FormatLeft align |
Ctrl+R | FormatRight align |
Shift+F7 | ToolsThesaurus (Note: displaying this on the menu is optional.) |
Ctrl+Alt+S | Window/Split (Note: do not display this on the menu.) |
Shift+F1 | Context-sensitive Help (Note: do not display this on the menu.) |
12.4.3 Every toolbar button should have a corresponding menu item. If a program has a menu (as most programs should), it should also have a toolbar. Visual Basic includes a toolbar ActiveX control, but it's fairly limited and you might want to consider a third-party tool. The actual toolbar items in your program will, of course, depend on the features supported.
The following list shows the standard toolbar items found in most Windows programs in the order they should appear from left to right. If you include any of these buttons on your toolbar, display them in this order.
New FileOpen File
Save File
Print Preview
Check Spelling
Cut
Copy
Paste
Paint Format
Undo
Redo
Help
Most likely, your program will have other buttons in addition to some or all of these. The place to put these application-specific buttons is to the left of the Help button, which is always the rightmost button on the toolbar, if provided.
12.5 Use system colors wherever possible.
If you've ever changed any of your Windows system colors, such as the active window or inactive title bar colors, you might have been pleasantly surprised to find that certain programs altered their display to match the new color settings. If a program didn't, it should have. You change your system colors by using the Display Properties dialog box accessed by right-clicking the desktop and selecting Properties. (See Figure 12-28.) Windows maintains a set of values for the user-selected colors or chosen color scheme. These values are available to you as a Visual Basic programmer, and you should use them.
Figure 12-28. Users can change their various system colors to any colors they see fit by using the Display Properties dialog box.
Each Windows system color has a specific constant in Visual Basic. Although the color referenced by a given constant might change, the value of the constant always remains the same. (Hence, it's a constant, not a variable.) When you assign a system color constant to a color property of an object, the current system color assigned to that constant is used. Visual Basic makes it easy to reference system colors by providing you a system color palette in the Properties window. This color palette is accessible from any color property of a selected object. (See Figure 12-29.)
If your program doesn't use system colors, it will stick out like a sore thumb when the user modifies her colors. It's also important to note that users don't just change their color settings for aesthetic reasons. I work with a programmer who's color-blind (or so he claims ”there's a rumor floating around that this has been a running gag on us for about 10 years ). He's modified his system colors (and the colors of his Visual Basic code editor as well) so that he can better see things. As I understand it, being color-blind does not necessarily mean that you don't see colors, just that you don't see or distinguish them the same way as a person who is not color-blind. Certain colors can appear to be the same color, which can make it difficult or impossible to read text or see other information. If you cleverly hard-code color values where system colors would do, you can actually make using your program difficult or impossible ! Using system colors is playing well with others.
Figure 12-29. You don't have to memorize color values or even constant names because you can select a system constant from the color palette.
The system colors are defined using rather cryptic hexadecimal numbers, making it pretty much impossible to memorize their numeric values. For instance, the system color for the face of buttons (battleship gray, in most cases) is &H8000000F&. I don't know about you, but I can't keep a dozen numbers like this organized in my head in any useful manner. Fortunately, Visual Basic has a set of constants for these system colors. Use them in your code whenever possible. The following table lists the system color constants, their values, and their basic descriptions.
System Color Constants
Constant | Value | Description |
---|---|---|
vbScrollBars | 0x80000000 | Scroll bar color |
vbDesktop | 0x80000001 | Desktop color |
vbActiveTitleBar | 0x80000002 | Color of the title bar for the active window |
vbInactiveTitleBar | 0x80000003 | Color of the title bar for the inactive window |
vbMenuBar | 0x80000004 | Menu background color |
vbWindowBackground | 0x80000005 | Window background color |
vbWindowFrame | 0x80000006 | Window frame color |
vbMenuText | 0x80000007 | Color of text on menus |
vbWindowText | 0x80000008 | Color of text in windows |
vbTitleBarText | 0x80000009 | Color of text in caption, size box, and scroll arrow |
vbActiveBorder | 0x8000000A | Border color of active window |
vbInactiveBorder | 0x8000000B | Border color of inactive window |
vbApplicationWorkspace | 0x8000000C | Background color of MDI applications |
vbHighlight | 0x8000000D | Background color of items selected in a control |
vbHighlightText | 0x8000000E | Text color of items selected in a control |
vbButtonFace | 0x8000000F | Color of shading on the face of command buttons |
vbButtonShadow | 0x80000010 | Color of shading on the edge of command buttons |
vbGrayText | 0x80000011 | Grayed (disabled) text |
vbButtonText | 0x80000012 | Text color on push buttons |
vbInactiveCaptionText | 0x80000013 | Color of text in an inactive caption |
vb3Dhighlight | 0x80000014 | Highlight color for 3-D display elements |
vb3DDKShadow | 0x80000015 | Darkest shadow color for 3-D display elements |
vb3Dlight | 0x80000016 | Second lightest 3-D color after vb3Dhighlight |
vbInfoText | 0x80000017 | Color of text in ToolTips |
vbInfoBackground | 0x80000018 | Background color of ToolTips |
It's impossible to fully discuss interface design in a single chapter. However, the principles covered here are probably applicable to 99 percent of the applications you'll create. When you follow these guidelines, your programs won't suffer the fate of so many others. You'll have a cleaner, more intuitive, and more efficient interface that allows the user to work in harmony with your application and leverage skills already developed and nurtured.