In this chapter, you'll start looking at Visual Basic for Applications' tools for creating custom dialog boxes that interact with the user. The terms dialog box and form (or user form) are generally used interchangeably. Technically, a dialog box is a quite simple, small window, such as a message box or input box. Forms, generally, are larger windows featuring more rich and complex interaction with the user. These terms, though, are equivalent in common usage.
Dialog boxes and forms are among the most powerful and feature-packed elements of VBA. We will spend quite a bit of time exploring their uses as the primary communication path between users and procedures.
This chapter covers the most straightforward form components and how to manipulate them. The next chapter shows you how to create more elaborate forms, such as those with tabbed pages and those that update themselves when the user clicks a control.
In this chapter you will learn to do the following:
You'll often want to use a form (another word for dialog box or window) when simpler methods of interacting with the user fall short. Sometimes, because of the limited selection, the buttons provided in message boxes are insufficient for getting needed information from the user. Similarly, the single text field available in an input box would be inadequate if you need the user to provide multiple data (name, address, phone number, and so on). In other words, sometimes you need the user to fill in a form.
You'll also want to use a custom dialog box for specialized input: when you need the user to choose nonexclusive options by selecting or clearing check boxes, to choose from among mutually exclusive choices via option buttons (also called radio buttons), or to select an item within a list displayed in a list box. Or perhaps you need to show users a picture. In other words, simple message boxes or input boxes cannot handle complex user input.
Custom dialog boxes can include the full range of interface elements the user is probably familiar with from working with Windows applications. You can create custom dialog boxes that look and function almost exactly like the dialog boxes built into applications (such as the File Save dialog box). Or you can create even larger constructions that approach the sophistication of typical application windows.
You'll use forms often in your more sophisticated macros. For example, when the user starts a procedure, you can have the procedure display a form presenting options—such as choosing the files for the procedure to manipulate. The user's choices determine what the procedure will then do.
You can also create dialog boxes that VBA triggers in response to events in the computer system: for example, an event that runs at a specific time or runs when the user takes a specific action (such as creating, opening, or closing a document).
Making your own dialog boxes is not that hard, but it can be time-consuming if you're building a complicated form. Because creating forms is not the fastest programming job, you might want to consider any practical alternatives to using them.
You've already looked at message boxes and input boxes, which provide a simple alternative for some of the relatively easy tasks for which you might want to create a custom dialog box.
Also, some applications, such as Word and Excel, even let you use their built-in dialog boxes for your own purposes. If users are familiar with the application, they're probably familiar with these built-in dialog boxes and can immediately use them to perform standard actions—for example, to open or save files. These are called common dialog boxes. How to use common dialog boxes in your macros is demonstrated briefly in the Real World Scenario titled “Control a For…Next Loop with User Input via a Dialog Box” in Chapter 12, “Using Loops to Repeat Actions,” and more fully later in this chapter in the section titled “Using an Application's Built-in Dialog Boxes from VBA.”
If you want to employ a custom dialog box or window in VBA, you use a visual object called a user form. A user form (also sometimes just referred to as a form) is a blank sheet on which you can place controls (such as check boxes, buttons, and text boxes) to create a made-to-order dialog box.
As you'll see, a user form contains its own code page where you, the programmer, write code to manage the various controls in the form. You can attach code to any of the controls, or to the user form itself, and that code is stored in the user form's code sheet. You can display the user form's code sheet in the Code window of the Visual Basic Editor and work with it as you would any other code. You can also run and test a user form as you would any other procedure (for example, by pressing F5 with the user form selected), and the VBA Editor will execute the code behind the form.
You can display a user form (a dialog box) for the user to interact with, and you can then retrieve information from the user form and manipulate it with VBA code. It's in this sense that code supporting a form is said to be behind a form. The user sees and interacts with a form, but behind the scenes you have written code to intelligently react to whatever the user might input.
USER FORMS AREN'T ALWAYS DIALOG BOXES
You can also create user forms that aren't dialog boxes. The distinction between a dialog box and a full window is imprecise, but it's usually easiest to define a resizable form as a window (you can resize it by dragging its borders or by clicking its Maximize button), while a dialog box has a fixed size. Some dialog boxes, such as the Find And Replace dialog box in Word, have an initially hidden part that the user can display (in the case of the Find And Replace dialog box, by clicking a More button).
But apart from this simple resizing, the bounds of the dialog box are fixed—you can't grab the corner of the dialog box with the mouse and drag it to enlarge it. But remember that you, the programmer, can create very large user forms that have the complexity and dimensions of a typical application window.
Each user form is itself an object and can contain a number of other objects that you can manipulate individually.
For example, you could create a simple dialog box with two option buttons, an OK button, and a Cancel button. Each option button would be an object, the OK button would be a third object, and the Cancel button would be a fourth object. You could set properties individually for each object—such as the action to take when the Cancel button was clicked or the ScreenTip (also called a ToolTip) to display when the user moved the mouse pointer over each of the option buttons. (ToolTips help make the components of your form understandable for the user.) The point is to consider the components of a form—the controls you place on the form—as objects. This is another use of the concept of objects. Controls are visual objects, but like purely programmatic objects, controls have members such as properties.
You can specify most properties of an object either at design time (when you're creating the user form) or at runtime (while the code is executing, either before or after you display the user form). For example, you can set the Value property of a check-box control to True to display the check box in its selected state or to False to display the check box in its cleared state. You can set the Value property three different ways:
The next sections explain the process of creating a dialog box. Later in this chapter, you'll find examples that step through creating a procedure and adding a dialog box to it.
It's possible to whip together a half-decent dialog box without much planning. Some programmers like to just “sketch” the user interface in a dialog box by dragging and dropping controls onto it, then positioning them so they look good and modifying their properties.
Other programmers prefer to adopt a more methodical approach and plan what they need to include in the dialog box before they start creating it. If you fall into this latter category, consider the intended purpose of the dialog box and list the elements it will need in order to achieve this goal. Then sketch on paper a rough diagram of the dialog box to get an approximate idea of where you'll want to locate each of the elements (the controls you place on the form).
TRY BASING CUSTOM DIALOG-BOX DESIGNS ON EXISTING DIALOG BOXES
Another option is to base the design for your custom dialog box on an existing dialog box—either a dialog box built into an application (called a common dialog box) or a custom dialog box that your company or organization has already implemented. Leveraging previous development efforts can not only help you avoid reinventing the wheel, but also produce a custom dialog box that users find familiar and intuitive.
Once you have a design in mind, the first step in creating a custom dialog box is to insert a user form in the appropriate template or document:
OTHER WAYS TO ADD A USER FORM
You can also insert a user form by clicking the Insert UserForm button on the far left of the Editor's Standard toolbar.
The Visual Basic Editor opens a new user form like that shown in Figure 14.1, named UserForm1 (or the next available number if the project already contains other user forms).
The Visual Basic Editor also displays the Toolbox. (If you've previously hidden the Toolbox while working on a user form, the Visual Basic Editor doesn't display it. Choose View Toolbox or click the Toolbox button on the far right of the Standard toolbar.)
VBA automatically inserts the user form in the Forms object (the collection of forms) for the project. If the project you chose didn't already contain a Forms collection, VBA adds one to contain the new user form. You'll see the Forms object displayed in the Project Explorer.
The Visual Basic Editor displays a grid in each user form to help you place controls relative to the dialog box and to align controls relative to each other so they look neat instead of random.
I don't know why you would want to do this, but to switch off the display of this grid or to switch off the Visual Basic Editor's automatic alignment of controls to the grid, follow these steps:
NAMING CONVENTIONS IN VISUAL BASIC FOR APPLICATIONS
Naming controls in VBA is similar to naming variables. Names for controls can be up to 40 characters long, must begin with a letter, and after that can be any combination of letters, numbers, and underscores. You can't use spaces or symbols in the names, and each name must be unique in its context—for example, each user form must have a unique name within a project, but within any user form or dialog box, a control can have the same name as another control in a different form.
Those are the rules; you can also use conventions to make the names of your VBA objects as consistent and easy to understand as possible. Recall the conventions you've used in previous chapters for identifying the variable type with a prefix: str, bng, int, and so on. The prefixes widely used when naming controls identify the control. For example, by using the convention of prefixing a text box control's name with txt, you can be sure that anyone else reading your code will immediately identify the name as belonging to a text box—and that you yourself will easily identify the name when you revisit your old code.
Here's an example showing conventional prefixes for several controls:
Private Sub cmbSelectEmployee_Change() lblEmployeeName = cmbSelectEmployee.Text fraStep2.Enabled = True lblInstructions = "Enter text in the Step 2 text box. " & _ "For example, you might include brief biographical " & _ "information on the employee, details of their position, " & _ "or your hopes for their contribution to the company." cmdClearEmployeeName.Enabled = True End Sub
Some popular naming conventions for the most-used VBA objects are shown in the following list. You'll encounter the naming conventions for other VBA objects later in the book. This list includes the control's name, the standard prefix, and finally an example showing how the control can be named in code:
Check box The standard prefix is chk, as in chkReturnToPreviousPosition.
Command button The standard prefix is cmd, as in cmdOK.
Form (user form) The standard prefix is frm, as in frmMoveParagraph.
Frame The standard prefix is fra, as in fraMovement.
List box The standard prefix is lst, as in lstConferenceAttendees.
Combo box The standard prefix is cmb, as in cmbColor.
Menu The standard prefix is mnu, as in mnuProcedures.
Option button The standard prefix is opt, as in optSpecialDelivery.
Label The standard prefix is lbl, as in lblUserName.
Text box The standard prefix is txt, as in txtUserDescription.
Just as with variable names, the naming convention for controls begins with three lowercase letters and then starts the rest of the object's name with an uppercase letter to make it a little easier to read. For example, a text box in which the users are to type their last names might be named txtLastName.
Naming conventions tend to seem awkwardly formal at first, and there's a strong temptation to avoid them. But if you plan to distribute your macros or expect others to work with them, it's usually worth the trouble to follow the naming conventions. Plus they help you when debugging. It's just another way to make reading code easier for everybody.
Next, change the user form's name property from the default (UserForm1) to a more descriptive name. The following steps show how to do this. (For advice on choosing names, refer to the sidebar “Naming Conventions in Visual Basic for Applications” in this chapter.)
The Categorized option is not, in my view, very helpful because many of the properties are simply too difficult to fit into categories that make any sense. The Caption property, for example, is assigned to the Appearance category, but the (Name) property is contained in the Misc. collection. The very existence of a “miscellaneous” category demonstrates that the categorization effort has broken down. I suggest you stick with the default Alphabetic option instead.
DEALING WITH THE “NAME CONFLICTS WITH EXISTING MODULE” ERROR
If you run into the “Name name conflicts with existing module, project, or object library” error (shown here), chances are you've just tried to give a user form the same name already assigned to something else.
You've tried to reuse the name of a VBA project or object library.
Now that you've renamed the user form, you're ready to add controls to it from the Toolbox, shown in Figure 14.4. VBA automatically displays the Toolbox when a user form is active, but you can also display the Toolbox when no user form is active by choosing View Toolbox.
REMOVING THE “ROAMING OFFICE” CONTROL
Obviously an oversight on Microsoft's part, they've included in the VBA 2013 Toolbox an obscure and—even in MSDN—essentially ignored control called the RoamingOffice control (not shown in Figure 14.4). Its use is beyond the scope of this book, not to mention beyond the scope of the VBA Help system and even Google. Perhaps Microsoft intends to make it useful in the future. For now, though, it clearly doesn't belong among the default controls on the Toolbox. It's the small gray crosshatched square icon next to the Image control. If you wish, you can remove the RoamingOffice control from your Toolbox by right-clicking its crosshatched icon, then choosing Delete RoamingOffice from the context menu.
Here's what the buttons on the Toolbox do:
Select Objects This first control has a very specialized purpose, and you might never need to use it. First, it's not an ordinary control (it doesn't appear on a form; you can't drag and drop it onto a form). Its job is to restore the mouse pointer to selection mode. However, the mouse pointer automatically returns to selection mode after you've dropped a control onto a form. So usually you'll need to click the Select Objects button only when you've selected another control and then changed your mind and decided not to use it. So you need to restore the pointer to its normal state. Alternatively, if you double-click a control (such as the check box), you trigger a technique that allows you to quickly add multiple versions of the same control repeatedly. (Every time you click in the form, a new check box is added to it, for example, while the Editor is in this state. To stop this repetitive behavior, you click the Select Objects button.
Label Creates a label, which is text used to identify a part of the dialog box or to explain information the user needs to know in order to use the dialog box effectively.
TextBox Creates a text box (also sometimes called an edit box), a field into which the user can type text. You can also use a text box to display text to the user or to provide text for the user to copy and paste elsewhere. A text box can contain either one line (the default) or multiple lines and can display a horizontal scroll bar, a vertical scroll bar, or both.
ComboBox Creates a combo box, a control that combines a text box with a list box. The user can either choose a value from the list box or enter a new value in the text box.
ListBox Creates a list box, a control that lists a number of values. Users can pick one value from the list but can't enter a new value of their own (unlike with a combo box). The list box is good for presenting closed sets of data.
CheckBox Creates a check box and an accompanying label. The user can select or clear the check box to turn the associated action on or off.
OptionButton Creates an option button (also known as a radio button) and an accompanying label to identify the purpose of the button. This button is usually a circle that contains a black dot when selected. The user can select only one option button out of any group of option buttons. (The name radio button comes from radios with push buttons for stations; you can select only one button at a time. Push one, and the others pop out.)
ToggleButton Creates a toggle button, a button that shows whether or not an item is selected. A toggle button can be defined with any two settings, such as On/Off or Yes/No. You can add a picture to a toggle button, which provides a graphical way of letting a user choose between options.
Frame Creates a frame, an area of a user form or dialog box surrounded by a thin line and an accompanying label. You can use frames (also known as group boxes) to group related elements in your forms. As well as cordoning off elements visually, frames can separate elements logically. For example, VBA treats a group of option buttons contained within a frame as separate from option buttons in other frames or option buttons loose in the dialog box. This separation makes it easier to use multiple sets of option buttons in a form.
CommandButton Creates a command button. This is the typical, ordinary Windows button that users click to communicate their wishes. Most dialog boxes contain command buttons such as OK and Cancel, or Open and Cancel, or Save, or Apply and Close.
TabStrip Creates a tab strip for displaying multiple sets of data in the same set of controls. Tab strips are especially useful for presenting records in a database for review or modification: Each record in the database contains the same fields for information, so they can be displayed in the same group of controls. The tab strip provides an easy way of navigating between records.
MultiPage Creates a multipage control for displaying multipage dialog boxes that have different layouts on each of their tabs. An example of a multipage dialog box is the Options dialog box (Tools Options), which has multiple pages (often referred to incorrectly as tabs) in most of the Office applications.
ScrollBar Creates a stand-alone scroll bar. Stand-alone scroll bars are of relatively little use in dialog boxes. Combo boxes and list boxes have built-in scroll bars.
SpinButton Creates a spin-button control for attaching to another control. Spin buttons (also known as spinners) are typically small, rectangular buttons with one arrow pointing up and one down (or one arrow pointing left and the other pointing right). Spin buttons are useful for presenting sequential values with consistent intervals within an understood range, such as times or dates. For example, if you want the user to increment or decrement a price in a text box in 25-cent steps, you could use a spinner to adjust the price rather than letting the user type directly into the text box.
Image Creates an image control for displaying a picture within a form. For example, you might use an image control to show a corporate logo or a picture of some sort. (If you want to display a photo, texture, or other graphic on the background of the form itself, set the form's Picture property.)
ADDING CONTROLS TO THE VISUAL BASIC EDITOR TOOLBOX
The Toolbox shown in Figure 14.4 contains the basic set of tools provided by VBA. As discussed in “Customizing the Toolbox” in Chapter 2, “Getting Started with the Visual Basic Editor,” you can customize the Toolbox in various ways: by adding other controls to it, creating additional pages for the controls, moving controls from page to page, and creating customized controls of your own making so that you can avoid having to repeatedly adjust properties each time you add those controls.
Click one of the controls in the Toolbox to select it. Then click in the user form to insert the control on the form, as illustrated in Figure 14.5. VBA places the top-left corner of the control where you click. As you place a control, it snaps to the grid on the user form (unless you've turned off the Align Controls To Grid feature as described in “Choosing User-Form Grid Settings,” earlier in this chapter).
You can resize the control as desired by selecting it and then clicking and dragging one of the selection handles (the white squares) that appear around it, as shown in Figure 14.6. The mouse pointer changes to a double-arrow icon when you've correctly positioned it to drag. When you drag a corner handle, VBA resizes the control on both sides of the corner; when you drag the handle at the midpoint of one of the control's sides, VBA resizes the control only in that dimension. In either case, VBA displays a dotted outline indicating the size that the control will be when you release the mouse button.
To resize the user form itself, click its title bar, or click in any blank space in the form (anywhere outside a control). This selects the user form. Then click and drag one of the selection handles that appear around the form.
To delete a control, right-click it in the user form and choose Delete from the context menu. Alternatively, click it to select it and then press the Delete key or choose Edit Delete. Restore it by pressing Ctrl+Z.
RANDOM ADDITIONAL DEFAULT TOOLBOX CONTROLS
Now and then Microsoft adds application-specific or novel controls to the default Toolbox. This not only causes confusion, but it also means that the VBA Editor's Toolboxes are not standardized across the Office applications. This is a recent development, and unwelcome. Word 2013 arbitrarily includes a “Roaming Office” control. For more on this peculiar feature, see the sidebar “Removing the ‘Roaming Office’ Control” earlier in this chapter.
Excel's VBA Editor includes a RefEdit control that mimics Excel's reference-edit boxes.
Nobody objects to Microsoft providing additional controls to we programmers. (You can easily add controls to the Toolbox by right-clicking within the Toolbox and choosing Additional Controls from the context menu.) What's problematic is the randomness of what's now being included in the default Toolboxes.
Sometimes it's quite efficient to temporarily select several controls as a group in the Editor. This allows you to manipulate all the grouped controls as a unit. For example, if you want to change the font size of three text boxes, two option buttons, and four labels, just group them and change the font-size property in the Properties window only once. The whole group will have all their font sizes changed automatically. (This trick is not related to grouping controls within a Frame control as described earlier in this chapter.)
We'll explore this useful grouping technique later in this chapter in the section titled “Working with Groups of Controls.” For now, I'll just briefly introduce the concept.
To delete, move, resize, or change the properties of multiple controls at once, first select them into a group. You can then delete them all at once by using the methods just described. Or you can move, resize, or modify the properties of the group as a whole.
Here's how to group controls:
As with user forms, VBA automatically gives each control that you add to a form a default name consisting of the type of control plus a sequential number. When you add the first text box in a user form, VBA names it TextBox1; when you add another text box, VBA names it TextBox2; and so on. (Each control in a dialog box must have a unique name so that you can refer to it specifically in code.)
You'll usually want to change the controls' default names to names that describe their purpose so you can remember what they do for the macro.
For example, if TextBox2 is used for entering the user's organization name, you might want to rename it txtOrganizationName, txtOrgName, txtO_Name, or something similar.
To rename a control, follow these steps:
IF YOU RENAME A CONTROL, YOU MAY HAVE TO MODIFY YOUR CODE
You can rename a control anytime. But if you do, you must also change any existing references to it in the code that drives the user form. This gives you a strong incentive to choose suitable names for your controls before you write the code.
To move a control, click anywhere in it to select it, and then drag it to where you want it to appear, as shown in Figure 14.7.
To move a selected control, move the mouse pointer over the selection border around it so that the mouse pointer turns into a four-headed arrow (as shown in Figure 14.8), and then click and drag the control to where you want it to appear.
Real World Scenario
USEFUL COPY-AND-PASTE TECHNIQUES WITH CONTROLS
You can use the Copy and Paste commands (from the Standard toolbar, the Edit menu, or the context menu or by using the easiest approach, the keyboard, such as pressing Ctrl+X and Ctrl+V) to move a control.
Copy and Paste isn't that efficient when moving a single control; the Paste command places the control right in the middle of the user form, so you have to drag it to its new position anyway.
However, when creating multiple, similar control sets—such as a group of text boxes with accompanying labels—copying and pasting can be quite useful. It's a quick way to build a whole set of fields for the user to fill in, for example. This way, you don't have to position and align each label/text box pair. Nor do you have to adjust each control's properties, because they are copied too. Align the first label/text pair, set the Font property the way you want it (usually larger, changing it from the default 8 pt. size to 11), resize the controls as you want them, change any other properties to suit yourself, and then copy and paste (clone) the pair as often as necessary by repeatedly pressing Ctrl+V.
Be aware, though, that the VBA Editor unfortunately places each new clone directly on the center of the form, thereby hiding any other clones you've just added. In other words, when you paste, you can't actually see the new clone—it's in a pile on the center of the form. So you have to drag the clones away from the center to reveal the others beneath.
Here's a related technique: Sometimes you want to copy the entire set of controls from one form to another. Select all the controls on Forml, then press Ctrl+C to copy them, then click Form2 to select it, and press Ctrl+V to paste the entire set of controls into the new form.
The advantage of using Copy and Paste for creating new controls is that the new controls inherit all the characteristics of the original controls, so you can save time by creating a control, setting its properties, and then cloning it.
You don't even need to change the names of the copies you paste to another user form—they just need to be named suitably for the code with which they work.
As an alternative to using the Copy and Paste commands, you can also copy a control by holding down the Ctrl key as you click and drag the control. VBA displays a + sign attached to the mouse pointer to indicate that you're copying the control rather than moving it. Drop the copy where you want it to appear on the user form.
Some controls—such as option buttons and check boxes—have built-in text captions to let the user understand their purpose. You can change these captions like this:
DOUBLE-CLICKING OPENS THE CODE WINDOW RATHER THAN SELECTS A CONTROL
When you click a label to select it and click again to position the insertion point to change the caption, make sure you click slowly enough that Windows doesn't interpret this as a double-click. A double-click displays the code sheet for the user form and automatically adds a procedure for the Click event of the control. If this happens, you can easily get back to viewing the form (it's called Design view, as opposed to Code view). Just press Shift+F7, double-click the module's name in the Project Explorer, or choose View Object to view the form again.
WHEN SHOULD YOU SET PROPERTIES OF A CONTROL?
You can set (specify) many properties of a control either at design time (while you're creating the user form) or at runtime (while the form's code is executing). There's a time and a place for each approach, a time when either is a reasonable course of action.
Generally speaking, the more static the property, the more likely you'll want to set it at design time. Some properties, such as the Name property of a user form, have to be set at design time—you can't change such properties at runtime for a user form. You'll also usually want to name your controls at design time, though you can add controls at runtime and set their Name properties during execution.
In most cases, you'll want to set the properties that govern the position and size of the user form itself and its controls at design time. The advantages are clear: you can make sure that the user form looks as you intend it to, that it's legible, and so on.
Occasionally, you may want to change the properties of a user form or the size or position of some of the controls on it at runtime. For example, you might need to add a couple of option buttons to the form to take care of eventualities not included in the basic design of the form. Alternatively, you might create a form that had two groups of option buttons sharing the same space—one group, in effect, positioned on top of the other. At runtime, you could modify their Visible properties in your code and thus display one group and hide the other group. If each group contained the same number of option buttons, you could even make do with only one group of option buttons, assigning the appropriate properties to each at runtime. However, there's no particular advantage in trying to simultaneously make just the one group do double duty like that. It can make your code more confusing.
Given the flexibility that many properties of controls provide, you can often design your user forms to handle several circumstances by displaying and hiding different groups of controls at runtime rather than having to add or remove controls at runtime. Creating the complete set of controls for a user form at design time avoids most of the difficulties that can arise from adding extra controls at runtime. That said, you may sometimes need to create a user form on the fly to present information about the situation in which users have placed themselves.
As you'll see as you continue to work with controls, you have to set values for some controls at runtime. For example, you sometimes can't assign the list of items to a list box or combo box at design time. If a list displays items from a database, the list can vary depending on which data set the user selects. So you would have to write code that fills the list box during execution. (Often, you'll fill a list box during a UserForm_Initialize procedure that runs as the user form is being initialized for display.) The set of items in some lists can be known in advance and specified in your code during design time, such as a list box displaying all the countries in the world, from which the user selects the country of residence.
The following sections discuss the key properties of the controls in the default Toolbox.
First, I'll explain the common properties used to manipulate many of the controls effectively. After that, I'll go through the controls one by one, listing the properties particular to each control.
If you're new to VBA and find this section heavy going, just skip it for the time being and return to it when you're creating code and need to reference information about the properties of the controls.
Table 14.1 lists the properties shared by all or most controls, grouped by category.
The Label control simply displays text on the screen. It's most often used to identify the purpose of another control, so you frequently see a Label control placed on a form to the left of a textbox whose purpose the label describes. Use the Caption property to type in the text that you want the label to display. Use the TextAlign property as shown in Table 14.2 to align the text of the label with the borders of the Label control.
The TextBox is one of the most common controls. Recall that it can be a single-line control (often employed to display a field the user must fill in) or a multiline control, for displaying lots of text, as in a diary program where the user determines how much they want to write. Adjust this feature with the MultiLine property. Also, the defaults for a TextBox are a size of 8 pt. (too small usually) and a sans-serif font called Tahoma (sans-serif type is generally thought more appropriate for headlines than body text). So you'll usually find yourself employing the Font property to choose a larger font size and more readable font (such as Times New Roman).
Table 14.3 lists the key properties of the TextBox control.
From the user's point of view, a key distinction is that a list box simply provides a list of options the user can choose from, whereas a combo box offers that list and also includes a field where the user can type in items.
Table 14.4 shows the key properties of the ComboBox control and the ListBox control. These two controls are similar and share many properties. They do, however, differ somewhat in behavior and features; these differences are described in the entries marked “List box only” and “Combo box only” in the table.
PROPERTY | DESCRIPTION |
AutoTab | See Table 14.3. |
AutoWordSelect | See Table 14.3. |
BoundColumn | A Variant property that determines the source of data in a combo box or a list box that has multiple columns. The default setting is 1 (the first column). To assign another column, specify the number of the column (columns are numbered from 1, the leftmost column). To assign the value of ListIndex to BoundColumn, use 0. |
ColumnCount | A Long (data type) property that sets or returns the number of columns displayed in the combo box or list box. If the data source is unbound, you can specify up to 10 columns. To display all available columns in the data source, set ColumnCount to −1. |
ColumnHeads | A Boolean property that determines whether the combo box or list box displays headings on the columns (True) or not (False). |
ColumnWidths | A String (data type) property that sets or returns the width of each column in a multicolumn combo box or list box. |
ListRows | (Combo box only.) A Long (data type) property that sets or returns the number of rows displayed in the combo box. If the number of items in the list is greater than the value of ListRows, the combo box displays a scroll bar so that the user can scroll to the unseen items. |
ListStyle | Determines the visual effect the list uses. For both a combo box and a list box, fmListStylePlain displays a regular, unadorned list. For a combo box, fmListStyleOption displays an option button to the left of each entry, allowing the user to select one item from the list. For a list box, fmListStyle-Option displays option buttons for a single-select list and check boxes for a multiselect list. |
ListWidth | (Combo box only.) A Variant property that sets or returns the width of the list in a combo box. The default value is 0, which makes the list the same width as the text area of the combo box. |
MatchEntry | Determines which type of matching the combo box or list box uses when the user types characters with the focus on the combo box or list box. fmMatchEntry-FirstLetter (0) matches the next entry that starts with the letter or character typed: if the user types t twice, VBA selects the first entry beginning with t and then the second entry beginning with t. fmMatchEntryComplete (1) matches each letter the user types: if the user types te, VBA selects the entry that starts with te. fmEntryMatchNone (2) specifies no matching: the user can't select an item by typing in the list box or combo box but must use the mouse or the arrow keys instead. The default MatchEntry setting for a combo box is fmMatchEntryComplete. The default setting for a list box is fmMatchEntryFirstLetter. |
MatchRequired | (Combo box only.) A Boolean property determining whether the user must select an entry from the combo box before leaving the control (True) or not (False). This property is useful for making sure that if the user types a partial entry into the text-box area of the combo box, they don't forget to complete the selection in the drop-down list area. |
If MatchRequired is True and the user tries to leave the combo box without making a selection, VBA displays an “Invalid Property Value” message box. | |
MultiSelect | (List box only.) Controls whether the user can make a single selection in the list or multiple selections. fmMultiSelectSingle (0) lets the user select only one item. fmMultiSelectMulti (1) lets the user select multiple items by clicking with the mouse or by pressing the spacebar. fmMultiSelectExtended (2) lets the user use Shift+click, Ctrl+click, and Shift with the arrow keys to extend or reduce the selection. |
RowSource | A String property that specifies the source of a list to be displayed in a combo box or a list box. |
SelectionMargin | See Table 14.3. |
ShowDropButtonWhen | See Table 14.3. |
Check boxes are similar to option buttons—a set of choices presented to the user. However, option buttons permit the user to select only one from among the displayed options (like a set of radio pushbuttons). By contrast, users can select as many check boxes as they wish.
Most of the properties of the CheckBox control have been discussed already. The key property of the CheckBox that you haven't come across yet is TripleState, which is a feature of the OptionButton and ToggleButton controls as well.
TripleState is a Boolean property that determines whether the check box, option button, or toggle button can have a null state as well as True and False states. When a check box or other control is in the null state, it appears with a small black square in its box.
You can see the null state in the Font dialog box in Word when one of the check-box-controlled properties—such as the Strikethrough check box in Figure 14.10—is true for some but not all of the current selection. For example, select a word (or any amount of selected text) that is only partly struck through, and you trigger the null state for the Strikethrough check box, as shown in Figure 14.10. Normally, a check box is either checked or not, but when in a null state, it contains a small black square, indicating it's neither true nor false. (In earlier versions of Office, the null state in a check box was indicated by filling the box with gray or black.)
A couple of properties described briefly in the context of other controls deserve more detail here:
Figure 14.11 shows a sunken check box and a flat check box. The Value property, which indicates whether the check box is selected (True) or cleared (False), is the default property of the check box. Recall that the default property need not be specified in code; it's assumed. Thus, you can either write CheckBox1.Value or just CheckBox. The following three statements have the same effect:
If CheckBox1.Value = True Then If CheckBox1 = True Then If CheckBox1 Then
A group of OptionButtons provides a set of mutually exclusive options from which the user can choose. Only one of the buttons in a group can be selected. For instance, you could have two OptionButtons under the heading Sex: Male and Female. (Recall that a set of CheckBoxes permits multiple options to be chosen simultaneously. CheckBoxes are useful for choosing more complex options. For example, under the heading Typeface, you could have Italic, Bold, and Underlined options, all of which could be selected simultaneously.)
Like the CheckBox, the OptionButton control has a straightforward set of properties, almost all of which you've seen already in this chapter. This section shows you the GroupName property, which is unique to the OptionButton, and some of the key properties for working with option buttons.
The GroupName property is a String data type that assigns the option button to a group of option buttons. Alternatively, you can create a group by placing a set of option buttons on a Frame control. The key idea here is that, once grouped, the buttons become mutually exclusive. However, there can be more than one group (or set) on a form—as long as you employ a Frame control or the GroupName property to isolate the various groups of buttons.
The default setting for GroupName is a blank string (""), which means that an option button isn't assigned to a group until you explicitly assign it. When you enter the group name, the group is created. By using the GroupName property, you can have multiple groups of option buttons on the same form without using frames to specify groups, but you must somehow distinguish the logical groups of option buttons from each other so that the user can tell which option buttons constitute a group. Using a Frame control is the easiest way of segregating groups of option buttons both visually and logically—but it's useful to have the flexibility that GroupName provides when you need it. Also, a Frame has a built-in Caption property you can use to describe the group's purpose.
These are the other key properties of the OptionButton control:
When it's not selected, the ToggleButton control appears raised, but it looks pushed in when it's selected. The key properties for the ToggleButton control are the same as those for the CheckBox and CommandButton:
The Frame control is relatively straightforward, but it has several properties worth mentioning; they're shown in Table 14.5. The Frame control shares a couple of these properties with the Page object.
The CommandButton is used quite often. This control has three unique properties, listed in Table 14.6.
PROPERTY | DESCRIPTION |
Cancel | A Boolean property that determines whether the command button is the Cancel button for the user form (True) or not (False). The Cancel button for a user form can bear any name; what distinguishes it is that its Cancel property is set to True. The Cancel button is activated by the user's pressing Esc, or clicking the button, or putting the focus on the button and pressing Enter. Only one command button on a form can be the Cancel button at any given time. Setting the Cancel property for a command button to True causes VBA to set the Cancel property to False for any button for which it was previously set to True. |
Default | A Boolean property that determines whether the command button is the default button for the user form (True) or not (False). Only one command button on a form can be the default button at any given time. Setting the Default property for a command button to True causes VBA to set the Default property to False for any button for which it was previously set to True. The default button is activated by the user pressing Enter when the focus isn't on any other command button. |
TakeFocusOnClick | A Boolean property that determines whether the command button takes the focus when the user clicks it (True) or not (False). The default setting for this property is True, but you may want to set it to False when you need the focus to remain on another control in the user form even when the user clicks the command button. However, if the user uses the Tab key or the arrow keys to move to the command button, the command button will take the focus even if the Take FocusOnClick property is set to False. |
Note that it's useful to set the Accelerator property for each command button on a form. This way, the user can quickly access it from the keyboard.
SOMETIMES THE CANCEL BUTTON SHOULD BE THE DEFAULT BUTTON
Sometimes you'll be tempted to make the Cancel button the default on a form. This offers an obvious benefit for forms that offer irreversible actions, such as deleting text or deleting a file, but it can confuse accessibility aids (such as screen readers) and make it difficult for users with cognitive difficulties to work with the form. For these reasons, it's usually best to make the default button on a form a different button than the Cancel button.
TabStrip controls allow you to create a multipage dialog box. Click the Home tab in Word and then click the small arrow icon in the lower-right corner of the Font area on the Ribbon. Word's Font dialog box will open and you'll see a two-tab dialog box. One tab is labeled Font and the other tab is labeled Advanced. This is a good way to organize a dialog box when you have quite a few options to present to the user.
The TabStrip control has several unique properties and a number of properties that it shares with the MultiPage control. Table 14.7 lists these properties.
PROPERTY | DESCRIPTION |
ClientHeight | (Tab strip only.) A Single (data type) property that sets or returns the height of the display area of the tab strip, measured in points. |
ClientLeft | (Tab strip only.) A Single property that returns the distance, measured in points, between the left border of the tab strip and the left border of the control inside it. |
ClientTop | (Tab strip only.) A Single property that returns the distance, measured in points, between the top border of the tab strip and the top border of the control inside it. |
ClientWidth | (Tab strip only.) A Single property that sets or returns the width of the display area of the tab strip, measured in points. |
SelectedItem | Sets or returns the tab currently selected in a tab strip or the page currently selected in a MultiPage control. |
TabFixedHeight | A Single property that sets or returns the fixed height of the tabs, measured in points. Set TabFixedHeight to 0 to have the tabs automatically size themselves to fit their contents. |
TabFixedWidth | A Single property that sets or returns the fixed width of the tabs, measured in points. Set TabFixedWidth to 0 to have the tabs automatically size themselves to fit their contents. |
TabOrientation | Determines the location of the tabs in the tab strip or multipage. fmTabOrientationTop (0), the default, displays the tabs at the top of the tab strip or multipage. fmTabOrientationBottom (1) displays the tabs at the bottom of the tab strip or multipage. fmTabOrientationLeft (2) displays the tabs at the left of the tab strip or multipage, and fmTabOrientationRight displays the tabs at the right of the tab strip or multipage. |
A SpinButton allows the user to easily increment or decrement numbers, dates, and so on. The ScrollBar and SpinButton share a number of properties that you haven't yet encountered. Table 14.8 lists these properties.
PROPERTY | DESCRIPTION |
Delay | A Long (data type) property that sets the delay in milliseconds between clicks registered on the control when the user clicks and holds down the mouse button. The default delay is 50 milliseconds. The control registers the first click immediately, the second click after Delay x 5 (the extra delay is to assist the user in clicking only once), and the third and subsequent clicks after Delay. |
LargeChange | (Scroll bar only.) A Long property that determines how much the item is scrolled when the user clicks in the scroll bar between the thumb (the small square within the scroll bar) and the scroll bar's arrow. Set the LargeChange property after setting the Max and Min properties of the scroll bar. |
SmallChange | A Long property that determines how much movement occurs when the user clicks a scroll arrow in a scroll bar or spin button. SmallChange needs to be an integer value; the default value is 1. |
Max | A Long property that specifies the maximum value for the Value property of the scroll bar or spin button. Max must be an integer. The default value is 1. |
Min | A Long property that specifies the minimum value for the Value property of the scroll bar or spin button. Min must be an integer. The default value is 1. |
ProportionalThumb | (Scroll bar only.) A Boolean property that determines whether the thumb is a fixed size (False) or is proportional to the size of the scrolling region (True), thereby giving the user an approximate idea of how much of the scrolling region is currently visible. The default setting is True. |
By now, you've seen all the properties of the Image control. Most of the time when you use an Image control, you'll want to adjust the following properties:
AN EASY WAY TO CAPTURE A GRAPHIC IMAGE
The easiest way to display part of a Windows screen in an Image control is to capture it by pressing the Print Screen key (to capture the entire screen) or the Alt+Print Screen key combination (to capture the currently active window). Then paste it into an application such as the Windows Paint accessory, trim (crop) it there as necessary, and save it as a .BMP file. Windows 8 provides a third option: Press the Windows key plus the Print Screen key to capture and automatically save the screen to disk. The captured image will be saved in your Libraries folder in a subfolder named Screenshots. The image is saved as a .PNG graphics filetype—widely considered to be the best way to grab screen images.
The Page object is one of the pages contained within a MultiPage object. You've already seen all its properties (in the context of other controls) except for the Index property, which it shares with the Tab object.
The Index property is an Integer data type that determines the position of the Page object in the Pages collection in a MultiPage control or the position of a Tab object in the Tabs collection in a TabStrip. The first Page object or Tab object is numbered 0 (zero); the second Page or Tab object is numbered 1; and so on. You can change the Index property of a tab or page to change the position in which the tab or page appears in the collection.
The Tab object is one of the tabs contained within a TabStrip object. You've already learned about all its properties in the context of other controls.
As mentioned briefly earlier in this chapter, when you are designing a form, it's often handy to group controls. By grouping two or more controls, you can work with them as a single unit to size, reposition, format, or delete them. (Recall that this form-design grouping technique has nothing to do with creating a set of option buttons within a Frame control. That creates a mutually exclusive collection of radio buttons to display to the user during runtime.)
To group controls, select them by Shift+clicking, Ctrl+clicking, or dragging around them, and then right-click and choose Group from the context menu. Alternatively, select the controls, and then click the Group button on the UserForm toolbar (you'll need to display this toolbar—it's not displayed by default) or choose Format Group. VBA creates a new group containing the controls and places a shaded border with handles around the whole group, as shown on the right in Figure 14.12.
When you merely select a set of controls (by Shift+clicking, Ctrl+clicking, or dragging around them), you have only temporarily grouped them. You can still manipulate them as a group, but as soon as you deselect them—by, for example, clicking the background of the form itself—the grouping disappears. However, when you right-click and choose Group from the context menu, they will remain grouped until you right-click and choose Ungroup.
To ungroup controls, right-click any of the controls contained in the group and then choose Ungroup from the context menu. Alternatively, select the group of controls by clicking in any control in the group and then click the Ungroup button on the UserForm toolbar, or choose Format Ungroup. VBA removes the shaded border with handles from around the group and displays the normal border and handles around each individual control.
You can quickly size all controls in a group by selecting the group and then dragging the sizing handles on the surrounding border. For example, you could select the middle handle on the right side and drag it inward to shorten the controls, as shown in Figure 14.13. The controls will be resized proportionately to the change in the group outline.
When the controls are grouped, you can then use the Properties window to quickly modify any properties they have in common (such as Font). But resizing a group can present problems—the results can be ugly. Generally speaking, resizing works fine when you've grouped a number of controls of the same type, as in Figure 14.13. For example, sizing a group that consists of several command buttons or option buttons works well, whereas sizing a group that consists of a text box, a command button, and a combo box is seldom a good idea.
You can quickly delete a whole group of controls by right-clicking any of them and choosing Delete from the context menu or by selecting the group and pressing the Delete key.
Even after you've grouped a number of controls, you can still work with them individually if necessary. To do this, first click any control in the group to select the group as a whole, as shown on the left in Figure 14.14. Then click the control you want to work with. As shown on the right in Figure 14.14, VBA displays a dark shaded border around the group (indicating that the group still exists) and displays the lighter shaded border around the individual control, indicating that that control is selected.
You can then modify the selected individual control as if it were not grouped. Change its ForeColor property to blue, for instance, and only the caption in that particular control will turn blue. When you've finished working with it, click another control in the group to individually select it, or click elsewhere in the user form to deselect all individual controls and restore the group.
Even if you use the Snap To Grid feature, you'll often need to align controls manually. They must be ungrouped for this feature to work. The easiest way to align controls is to select two or more, then right-click in any one of them and choose an option from the Align submenu: Lefts, Centers, Rights, Tops, Middles, Bottoms, or To Grid. These options work as follows:
Lefts aligns the left borders of the controls.
Centers aligns the horizontal midpoints of the controls.
Rights aligns the right borders of the controls.
Tops aligns the tops of the controls.
Middles aligns the vertical midpoints of the controls.
Bottoms aligns the bottoms of the controls.
To Grid aligns the controls to the grid.
VBA aligns the borders or midpoints to the current position of that border or midpoint on the dominant control—the control that has white sizing handles around it rather than black sizing handles. After selecting the controls you want to align, make dominant the one that is already in the correct position by clicking it so that it takes on the white sizing handles. Then choose the alignment option you want.
Make sure the alignment option you choose makes sense for the controls you've selected. VBA will happily align controls in an inappropriate way if you tell it to. For example, if you select a number of option buttons or text boxes and choose Tops from the Align submenu, VBA will obligingly stack all the controls on top of each other, rendering them unusable. (To recover from such minor mishaps, press Ctrl+Z.)
The VBA Editor offers several placement commands on the Format menu:
The tab order of a user form (or of a frame control within a form) is the order in which VBA selects controls in the form or frame when the user moves through them by pressing the Tab key (to move forward) or the Shift+Tab key combination (to move backward).
Put another way, it's a Windows convention that when the user presses the Tab key, the focus moves to the next control in a window.
Only one control at a time can have the focus. For example, if a form has five text boxes, only one of these text boxes, the one that currently has the focus, will display characters as the user types. In addition, a button in a set of buttons can also have the focus, and when the user presses the Enter key, the button with the focus will be triggered. Or the user can click a different button to move the focus to that button.
VBA displays a visual cue to indicate which control currently has the focus. You'll see a dotted frame around a button or option button and a blinking insertion cursor in a text box.
Each frame you add to a user form has a separate tab order for the controls it contains: The frame itself appears in the tab order for the form, and the controls within the frame appear in the tab order for the frame.
Set the tab order for a form or a frame to make it as easy as possible for the user to work with your form. Generally, for English-speaking users, it's best to arrange the tab order from left to right and from top to bottom in the dialog box or frame. For international users, you may want to arrange the tab order from right to left. You may also need to arrange the tab order to move from one control to a related control that would not normally be next in the tab order.
The whole point of managing the tab order is that you simplify things for your user. Employing the Tab key in this way allows the user to fill in a whole form without once having to move their hand off the keyboard to keep selecting, with a mouse click, each next text box.
This kind of tabbing is particularly useful when the user is asked to fill in several fields by typing into multiple text boxes (such as Name, Address, Phone, and so on). As soon as users finish filling in one field, they can press Tab to move on to the next. (Even easier, pressing the Enter key while in a text box moves users to the next control in the tab order.) At the end, after they've filled in the last field, they can quickly close the dialog box if you make the OK button the next control in the tab order.
VBA assigns the tab order to the controls in a dialog box or frame on a first-come, first-served basis as you add the controls. Unless you add all the controls in perfect order, this default order will seldom produce the optimal tab order for a dialog box, so usually you'll want to adjust the tab order—or at least check to ensure that it's right. You're likely to place fewer controls on a frame than on a form, so you have a better chance of adding them in a suitable order, but you should check these controls too before unleashing the dialog box on users.
Just press F5 and then repeatedly press the Tab key to examine your current tab order. Alternatively, you can open a Tab Order dialog box (shown in Figure 14.15) by right-clicking in the open space in the background of the form or frame and choosing Tab Order from the context menu. Or select the user form or frame and then choose View Tab Order.
The time to adjust the tab order is after you've finished creating your form (adding a control later will require that you go back and modify the tab order). Here's how to change the tab order in a dialog box or frame:
Designing a custom form is only the first step in getting it to work in a procedure. The other step is writing the code to display the form to the user and make it perform its tasks.
Typically, the code for a form consists of the following:
Private Sub btnOK_Click() End Sub
Notice that the Editor automatically combines the Name property of the control with the name of the event as the procedure's name, separated by an underscore character: btnOK_Click.
IN STATIC DIALOG BOXES, CLICK EVENTS ARE USUALLY EMPLOYED WITH COMMAND BUTTONS
Most controls have quite a few events. Some of them might seem inappropriate or useless at first. For example, option buttons have a Click event. But why? It makes sense to trap (to respond in code to an event such as a user's mouse click) using command buttons in a static dialog box. (A static dialog box is the most common type. The controls don't change or move.) However, as you'll see in the next chapter, in a dynamic dialog box, you may want to trap the click on an option button and display further controls to get additional input from the user.
Once the code attached to a button has run, execution returns to the form (if it's still displayed) or to the procedure that called the form.
Note that code that runs directly in response to an event is called an event procedure or event handler. An event procedure can call other procedures as necessary, so multiple procedures can be run indirectly when a single event handler Sub is triggered.
You load a form by using the Load statement, and unload it by using the Unload statement. The Load statement loads the form into memory so that it's available to the program but doesn't display the form; for that you use the Show method (discussed in the next section). The Unload statement unloads the form from memory and releases any memory associated with that object. If the form is displayed when the Unload statement runs, VBA removes the form from the screen.
The syntax for the Load and Unload statements is straightforward:
Load UserForm1 Unload UserForm1
Here, UserForm1 is the name of the user form or dialog box. For example, the following statement loads the dialog box named frmMyDialog:
Load frmMyDialog
To display a form, you use the Show method; to hide a form, you use the Hide method. For example, the following statement displays the form named frmMyDialog:
frmMyDialog.Show
If you execute a procedure containing this line, the frmMyDialog form appears onscreen so the user can interact with it: enter text in its text boxes, select or clear its check boxes, use its drop-down lists, click its buttons, and so on.
When the user closes the form (by clicking the Close button on its title bar or by clicking a command button that dismisses it), the form disappears from the screen and the procedure continues to run. But until you retrieve settings from the form and take action on them, the form has no effect beyond its graphical display.
You can display a form by using the Show method without explicitly loading the form with a Load command first; VBA takes care of the implied Load command for you. There's no particular advantage to including the Load command, but it might make your code easier to read and to debug. For example, the two procedures shown here have the same effect:
Sub Display_Dialog() Load frmMyDialog 'loads the form into memory frmMyDialog.Show 'displays the form End Sub Sub Display_Dialog() frmMyDialog.Show 'loads the form into memory and displays it End Sub
If you run a Hide method without having loaded the form into memory by using the Load statement or the Show method, VBA loads the form but does not display it onscreen.
Once you've displayed the form, take a moment to check its tab order by pressing F5 and then moving through it using the Tab key. When you first open the form, is the focus on the appropriate control, the control the user is most likely to want to interact with first? When you move forward from that control, is the next control that is selected the next control that the user will typically need to use? Adjust the tab order as necessary, as described in “Adjusting the Tab Order of a Form” earlier in this chapter.
To specify a default command button in a form, set that command button's Default property to True. VBA selects the default button when it displays the form so that if the user simply presses the Enter key to dismiss the dialog box, this button receives the keystroke.
Only one button can be the default button at any given time. If you set the Default property of any button to True, VBA automatically changes to False the Default property of any other button previously set to True.
To make a form do something, your code will usually respond to the user's input. The following sections first cover the VBA commands for retrieving information from a dialog box. Then you'll see an example of how to retrieve the user's choices from both a relatively simple dialog box and then a more complex form.
To return (retrieve) a string from a text box, your code can check its Value property or Text property after the user has clicked an OK or Cancel button or otherwise dismissed the dialog box.
For example, if you have a text box named txtMyText, you could return its value and display it in a message box by using the following line:
MsgBox txtMyText .Value
THE TEXT PROPERTY OF A TEXT BOX IS UNIQUE
For a text box, the Value property and the Text property return the same information; for most other VBA objects, the Value property and the Text property return different information.
Recall that VBA supports both one-line and multiline text boxes. To create a multiline text box, select the text box in the user form or in the drop-down list in the Properties window and set its MultiLine property to True. The user can then enter multiple lines in the text box and start new lines by pressing Shift+Enter.
QUICK CHANGES FOR TWO-STATE PROPERTIES
Here's a tip: If you're changing a Boolean (two-state, True versus False) property—like Enabled, Visible, or Multiline—just double-click the value in the Properties window. For example, to change the default False setting for Multiline, double-click False in the Properties window. It changes to True. (This doesn't work with the Value property.)
To add a horizontal or vertical scroll bar to a text box, set its ScrollBars property to 1 - fmScrollBarsHorizontal (for a horizontal scroll bar), 2 - fmScrollBarsVertical (for a vertical scroll bar, which is usually more useful), or 3 - fmScrollBarsBoth (for both).
A regular option button is a binary control, so it can have only two values: True and False. True indicates that the button is selected, False that it's unselected. You can check an option button's value with a simple If… Then structure. For example, if you have two option buttons, named optSearchForFile and optUseThisFile, you can check their values and find out which was selected by using the following code:
If optSearchForFile = True Then 'optSearchForFile was selected; take action on this
Else 'optSearchForFile was not selected, so optUseThisFile was 'take action for optUseThisFile End If
Remember that Value is the default property of the OptionButton control. The previous code checks the value of the default property of the control, so you need not specify the property in your code. Default properties can be omitted as a kind of shorthand programming. The first line of code could be written out more fully as If optSearchForFile.Value = True Then. But in the code example, I chose to write it more succinctly, with = True implied: If optSearchForFile Then.
With more than two option buttons, use an If… Then… ElseIf condition or a Select Case statement to determine which option button is selected.
YOU CAN'T DIRECTLY TEST FOR A NULL VALUE
This is a bit esoteric, but as you saw earlier in this chapter, an option button or a check box can also have a null value if its TripleState property is set to True. Null means basically “neither completely true nor false”—the selected paragraph is partially boldface, so its FontStyle is both bold and regular. If you allow your option buttons or check boxes to have a null state, you'll need to check for that as well in your procedures. You can't directly check for the control's value being Null (for example, If opt1.Value = Null causes an error), so use an If statement or Select Case statement to test True and False first. If the Value of the control is neither True nor False, it Else must be Null.
Like an option button, a regular check box can only be either True or False, so you can use an If… Then structure to check its value. Here's an example:
If chkDisplayProgress = True Then 'take actions for chkDisplayProgress End If
Again, you're checking the default property of the control here—the Value property. The first line of code could also be written as If chkDisplayProgress.Value = True Then.
Sometimes you'll need to take an action if the check box was cleared (deselected) rather than selected. For example, if the user clears the check box, you may need to turn off a configuration option.
List boxes start out empty. So, before you can ask the user to choose an item in a list box, you must first fill the box with items from which the user can choose—you must tell VBA which items to display. To do so, you create a procedure to initialize (prepare) the user form and add the items to the list box before displaying it:
Private Sub UserForm_Initialize() End Sub
Here's a tip: VBA runs a UserForm_Initialize procedure every time the user form is brought to life. This procedure is a good place to add items to a list box or combo box or to set properties of other controls on the user form. In other words, this Initialize event is where you write code to do any necessary preliminary housekeeping before displaying the form to the user.
lstBatteries.AddItem "Battery #A4601" lstBatteries.AddItem "Battery #A4602" lstBatteries.AddItem "Battery #A4603" lstBatteries.AddItem "Battery #A4604"
THE INITIALIZE EVENT IS FLEXIBLE
By adding items when you initialize the form, you can add different numbers of items as appropriate. For example, if you wanted the user to pick a document from a particular folder, you could create a list of the documents in that folder on the fly in your code during runtime and fill the list box with the documents' names.
To retrieve the user's choice from a single-select-style list box, check the Value property in your code, as in this example:
MsgBox "You chose this entry from the list box: " & lstBattery.Value
Single-select list boxes are like a set of option buttons—the user is allowed to select only one of them.
When you use the MultiSelect property to create a list box capable of multiple selections, you can no longer use the Value property to return the items selected in the list box. When MultiSelect is set to True, Value always returns a null value. Instead, you use the Selected property to determine which rows in the list box are selected and the List property (it's an array) to return the contents (the values) of each selected row.
The following statements use a For… Next loop to build a string named strMsg containing the entries selected from a multiselect list box:
strMsg = "You chose the following entries from the list box: " & vbCr For i = 1 To lstBatteries.ListCount If lstBatteries.Selected(i - 1) = True Then strMsg = strMsg & lstBatteries.List(i - 1) & vbCr End If Next i MsgBox strMsg
To return a value from a combo box (a control that is, in effect, a combination list box and text box), you add items to the combo box list in an Initialize procedure and then check the Value of the combo box after the user has dismissed the dialog box. (The combo box control doesn't offer multiple-selection capabilities, so Value is the property to check.)
For example, you would use the following code to add items to a combo box named cmbColor :
Private Sub UserForm_Initialize() cmbColor.AddItem "Red" cmbColor.AddItem "Blue" cmbColor.AddItem "Yellow" End Sub
To return the item the user chose in the combo box, retrieve the Value property:
Result = cmbColor.Value
The item retrieved from a combo box can be either one of the items assigned in the Initialize procedure or one that the user has typed into the text-box portion of the combo box.
The following sections show you two examples of how you can create a procedure and then design a form that works with it to make the procedure more useful and powerful. In the first example, you'll record a macro in Word and then link a form to that code. In the second example, which will work with any VBA-enabled application, you'll create a user form and its associated code from scratch.
This first example moves the current paragraph up or down within the document by one or two paragraphs in Word.
Start by recording a procedure in Word to move the current paragraph. In the procedure, you need to record the commands for the following actions:
We want our finished procedure to display a dialog box with option buttons for moving the current paragraph up one paragraph, up two paragraphs, down one paragraph, or down two paragraphs. The dialog box should also include a check box that indicates the user wants the insertion point returned to its original position at the end of the procedure. Because this is presumably desirable default behavior for the procedure, this check box is selected by default. Users can clear the check box if they don't want to return the insertion point to its original position.
First, start Word and create a new, blank, scratch document (press Ctrl+N), and enter three or four paragraphs of text—just about anything will do, but it'll be easier to have recognizable text so that you can make sure the procedure is moving paragraphs as it should. Then place the insertion point in one of the paragraphs you've just entered and start recording a macro as discussed in Chapter 1, “Recording and Running Macros in the Office Applications”:
Record the following actions in the macro:
Note that if you started with the insertion point at the beginning of the first paragraph in the document, you'll only be able to move the insertion point up one paragraph. This doesn't matter—press the keystroke anyway to record it. If Word beeps at you, ignore it.
Open the recorded macro in the Visual Basic Editor by pressing Alt+F8, selecting the macro's name in the Macros dialog box, and clicking the Edit button.
You should see a macro that looks something like this:
1. Sub Move_Paragraph() 2. ' 3. ' Move_Paragraph Macro 4. ' Move a paragraph up or down 5. ' 6. With ActiveDocument.Bookmarks 7. .Add Range:=Selection.Range, Name:="Move_Paragraph_Temp" 8. .DefaultSorting = wdSortByName 9. .ShowHidden = False 10. End With 11. Selection.Extend 12. Selection.Extend 13. Selection.Extend 14. Selection.Extend 15. Selection.EscapeKey 16. Selection.Cut 17. Selection.MoveUp Unit:=wdParagraph, Count:=1 18. Selection.Paste 19. Selection.MoveDown Unit:=wdParagraph, Count:=1 20. Selection.MoveUp Unit:=wdParagraph, Count:=2 21. Selection.MoveDown Unit:=wdParagraph, Count:=2 22. Selection.GoTo What:=wdGoToBookmark, Name:="Move_Paragraph_Temp" 23. ActiveDocument.Bookmarks("Move_Paragraph_Temp").Delete
24. With ActiveDocument.Bookmarks 25. .DefaultSorting = wdSortByName 26. .ShowHidden = False 27. End With 28. End Sub
You can probably read this macro code easily enough by now:
If you wish, you can quickly delete unnecessary lines of code, and collapse the first With structure, to create a more succinct, more easily understood, version of the code:
1. Sub Move_Paragraph() 2. ActiveDocument.Bookmarks.Add Range:=Selection.Range, _ Name:= ="Move_Paragraph_Temp" 3. Selection.Extend 4. Selection.Extend 5. Selection.Extend 6. Selection.Extend 7. Selection.EscapeKey 8. Selection.Cut 9. Selection.-MoveUp Unit:=wdParagraph, Count:=1 10. Selection.Paste 11. Selection.-MoveDown Unit:=wdParagraph, Count:=1 12. Selection.-MoveUp Unit:=wdParagraph, Count:=2 13. Selection.-MoveDown Unit:=wdParagraph, Count:=2 14. Selection.GoTo What:=wdGoToBookmark, _ Name:= ="Move_Paragraph_Temp" 15. End Sub
Next, create the dialog box for the procedure (see Figure 14.16):
OPTION BUTTONS ARE MUTUALLY EXCLUSIVE
By default, all the option buttons on a user form (if they're not contained within a frame) are part of the same option group. This means that only one of these option buttons can be selected at any given time. If you want to provide more than one group of option buttons on a user form, you need to specify the separate groups. The easiest way to do this is to position each group within a separate Frame control as you did in this example. Alternatively, you can specify a different GroupName property for each option button.
Private Sub cmdCancel_Click() End Sub
Recall that the Editor chooses to create a procedure for the most common event for whatever control (or the form) you double-click to get down into the code window. For most controls, this will be the Click event, as it is for the CommandButton control.
Type an End statement between the lines:
Private Sub cmdCancel_Click() End End Sub
This End statement removes the form from the screen and ends the current procedure—in this case, the Move_Current_Paragraph procedure.
Now you'll attach code to the OK button, which is where things get interesting. When the user clicks the OK button, the procedure needs to continue executing and do all of the following:
Now continue creating the Move Current Paragraph dialog box:
First, enter the following two lines between the Private Sub and End Sub lines:
frmMoveParagraph.Hide Unload frmMoveParagraph
The frmMoveParagraph.Hide line activates the Hide method for the frmMoveParagraph user form, hiding it from display on the screen. The Unload frmMoveParagraph line unloads the dialog box from memory.
REMOVING A FORM CAN PREVENT CONFUSION
It isn't necessary to hide or unload a form to continue execution of a procedure, but if you don't, users may become confused. For example, if you click the OK button on a Print dialog box in a Windows application, you expect the dialog box to disappear and the Print command to be executed. If the dialog box didn't disappear (but it launched the printing job in the background), you'd probably think it hadn't registered your click, so you'd click again and again until it went away. Then you'd print multiple copies, which is so wrong.
If chkReturnToPreviousPosition = True Then End If
If the chkReturnToPreviousPosition statement is set to True—that is, if the check box is selected—the code in the lines following the Then statement runs. The Then statement consists of the lines for inserting a bookmark that you recorded earlier. Cut these lines from the procedure and paste them into the If… Then statement like this:
If chkReturnToPreviousPosition = True Then With ActiveDocument.Bookmarks .Add Range:=Selection.Range, Name:=" Move_Paragraph_Temp" End With End If
If the check box is selected, the procedure inserts a bookmark; if the check box is cleared, the procedure passes over these lines.
Selection.Extend Selection.Extend Selection.Extend Selection.Extend Selection.Cut
If optUpOne = True Then Selection.MoveUp Unit:=wdParagraph, Count:=1 ElseIf optUpTwo = True Then Selection.MoveUp Unit:=wdParagraph, Count:=2 ElseIf optDownOne = True Then Selection.MoveDown Unit:=wdParagraph, Count:=1 Else Selection.MoveDown Unit:=wdParagraph, Count:=2 End If Selection.Paste
Here, optUpOne, optUpTwo, optDownOne, and optDownTwo (which uses the Else statement here and therefore isn't specified by name in the listing) are the four option buttons from the dialog box, representing the choice to move the current paragraph up one paragraph, up two paragraphs, down one paragraph, or down two paragraphs, respectively.
The condition is straightforward: If optUpOne is True (that is, if the option button is selected), the first Then condition runs, moving the insertion point up one paragraph from its current position (after the current paragraph is cut, the insertion point will be at the beginning of the paragraph that was after the current one). If optUpOne is False, the first ElseIf condition is evaluated; if the condition evaluates to True, the second Then condition runs; and if the condition evaluates to False, the next ElseIf condition is evaluated. If that conditiona, too, turns out to be False, the Else code is run. In this case, the Else statement means that the optDownTwo option button was selected in the dialog box, so the Else code moves the insertion point down two paragraphs.
Wherever the insertion point ends based on which option button the user chose, the next line of code (Selection.Paste) pastes in the cut paragraph from the Clipboard.
If chkReturnToPreviousPosition = True Then Selection.GoTo What:=wdGoToBookmark, _ Name:=" Move_Paragraph_Temp" ActiveDocument.Bookmarks("Move_Paragraph_Temp").Delete End If
If the chkReturnToPreviousPosition check box is selected, VBA moves the insertion point to the temporary bookmark and then deletes that bookmark.
Listing 14.1 shows the full listing for the cmdOK button.
1. Private Sub cmdOK_Click() 2. frmMoveParagraph.Hide 3. Unload frmMoveParagraph 4. If chkReturnToPreviousPosition = True Then 5. With ActiveDocument.Bookmarks 6. .Add Range:=Selection.Range, _ Name:="Move_Paragraph_Temp" 7. End With 8. End If 9. Selection.Extend 10. Selection.Extend 11. Selection.Extend 12. Selection.Extend 13. Selection.Cut 14. If optUpOne = True Then 15. Selection.MoveUp Unit:=wdParagraph, Count:=1 16. ElseIf optUpTwo = True Then 17. Selection.MoveUp Unit:=wdParagraph, Count:=2
18. ElseIf optDownOne = True Then 19. Selection.MoveDown Unit:=wdParagraph, Count:=1 20. Else 21. Selection.MoveDown Unit:=wdParagraph, Count:=2 22. End If 23. Selection.Paste 24. If chkReturnToPreviousPosition = True Then 25. Selection.GoTo What:=wdGoToBookmark, _ Name:="Move_Paragraph_Temp" 26. ActiveDocument.Bookmarks("Move_Paragraph_Temp").Delete 27. End If 28. End Sub
Go ahead and try it. To test this example properly, you should remove the bookmark you inserted while recording the macro earlier in this chapter. To remove it, click the Bookmark item in the Links section in the Insert tab on Word's Ribbon. In the Bookmarks dialog box that opens, select Move_Paragraph_Temp and click the Delete button.
Now open the scratch document in Word that you created earlier in this chapter and filled with several paragraphs of text. Press Alt+F11 to open the Visual Basic Editor. Double-click frm-MoveParagraph in the Project Explorer to display the user form. Press F5 to run this procedure. Click the OK button in your user form and observe that the paragraphs were rearranged in the document.
This next example displays a user form that employs a list box from which the user can select a file to open. The user form is simple, as is its code. The macro includes a loop and an array to gather the names of the files in a folder and then displays the filenames in the list box. The user gets to select a file and click the Open button to open it. Figure 14.21 shows the user form in action, displaying Excel files.
You can adapt this example to any of the Office 2013 applications discussed in this book by changing the filename to an appropriate type for that application and also modifying a couple of the key statements. The version of this example we'll look at now shows you how to create the procedure in Excel.
Follow these steps to build the user form:
PROPERTY | VALUE |
(Name) | lbllnfo |
AutoSize | True |
Caption | Choose the file to open and click the Open button. |
Left | 10 |
Top | 6 |
WordWrap | False |
PROPERTY | VALUE |
(Name) | lstifles |
Height | 100 |
Left | 10 |
Top | 25 |
Width | 300 |
(Or just drag them around and eyeball them into a pleasing position.)
Follow these steps to create the code for the user form:
Option Base 1
Private Sub UserForm_Initialize() End Sub
Private Sub cmdCancel_Click() End Sub
If lstFiles.Value <> "" Then Documents.Open _ Filename:="c: ransfer" & lstFiles.Value
If lstFiles.Value <> "" Then Presentations.Open _ Filename:="c: ransfer" & lstFiles.Value
Listing 14.2 shows the full version of the code behind the Open a Current File user form.
1. Option Base 1 2. 3. Private Sub UserForm_Initialize() 4. 5. Dim strFileArray() As String 6. Dim strFFile As String 7. Dim intCount As Integer 8. 9. strFFile = Dir("c: ransferspreads*.xlsb") 10. intCount = 1 11. 12. Do While strFFile <> "" 13. If strFFile <> "." And strFFile <> ".." Then 14. ReDim Preserve strFileArray(intCount) 15. strFileArray(intCount) = strFFile 16. intCount = intCount + 1 17. strFFile = Dir() 18. End If 19. Loop 20. 21. lstFiles.List() = strFileArray 22. 23. End Sub 24. 25. Private Sub cmdCancel_Click() 26. Me.Hide 27. Unload Me 28. End Sub 29. 30. Private Sub cmdOpen_Click() 31. Me.Hide 32. If IstFiles.Value <> "" Then Workbooks.Open _ Name:="c: ransferspreads" & lstFiles.Value 33. Unload Me 34. End Sub
Listing 14.2 contains all the code that appears on the code sheet for the frmOpen_a_Current_File user form: a declarations section and three event procedures.
In the declarations section, line 1 contains the Option Base 1 statement, which makes any array used on the code sheet begin at 1 rather than at 0. Line 2 is a spacer.
Here's what happens in the UserForm_Initialize procedure (lines 3 to 23):
Here's what happens in the cmdCancel_Click procedure (lines 25 through 28):
Here's what happens in the cmdOpen_Click procedure (lines 30 through 34):
Remember that to test this example, you'll need to adjust lines 9 and 32 to include a file path on your machine where some XLSB files are stored. For Excel 2013, try this location: C:UsersYourNameAppDataRoamingMicrosoftExcelXLSTART.
Some applications, such as Word and Excel, let you use their built-in dialog boxes via VBA. If a built-in dialog box offers the functionality you need, using it can be a great solution: you don't have to build a custom dialog box, just reference the built-in dialog box in your code.
You shouldn't even need to debug the dialog box, and users of your procedures will probably be familiar with the dialog box from their work in the application. These built-in dialog boxes are called common dialog boxes, and we explored them briefly in the sidebar titled “Control a For… Next Loop with User Input via a Dialog Box” in Chapter 12.
To display a built-in dialog box, you need to know its name and constant. You also must decide which method to use to display the dialog box.
Although Office 2013 no longer uses menus (with some exceptions, such as the Visual Basic Editor), built-in dialog boxes (in Word and other applications) are still identified by constants derived from the older, pre-Ribbon menu-style interface. These constants start with the letters wdDialog (as in Word Dialog), followed by the name of the dialog box.
The name of the dialog box is derived from the pre–Office 2010 menu commands that displayed the dialog box prior to the introduction of the Ribbon interface (with Office 2007). For example, to refer to the Open dialog box, you use the constant wdDialogFileOpen, because in previous versions of Word, you would have chosen File Open to display that dialog box.
Or to display the Print dialog box (the old File Print options), you use the constant wdDialogFilePrint, and to display the Options dialog box (Tools Options), you use the constant wdDialogToolsOptions.
So, although the user interface has evolved beyond classic menus, the menu structure itself remains as part of the classification system for internal objects—such as these constants used to identify various dialog boxes.
Excel follows a similar but less rigid taxonomic convention. Built-in Excel dialog boxes are (for backward compatibility with older macro code) still identified by constants starting with the letters xlDialog followed by the name of the dialog box. The name of the dialog box is derived either from the classic menu commands that were required to display it or from the dialog box's title. For example, to refer to the Open dialog box, you use the constant xlDialogOpen (rather than xlDialogFileOpen).
Anyway, the easiest way to find the name for the built-in dialog box you need is to search the Visual Basic Editor's Help system for “Built-in Dialog Box Argument Lists” in Word or Excel. (Access employs a whole different system for common dialog boxes, requiring the importation of object libraries using its Visual Basic Editor's Tools References menu and the employment of specialized objects.)
You can also view a list of Word or Excel built-in dialog boxes by displaying the Object Browser (press F2 in the Editor) and typing wddialog (for Word) or xldialog (for Excel) in the Search textbox.
You use these constants with the Dialogs property, which returns the Dialogs collection object, which in turn contains all the built-in dialog boxes in the host application.
For example, to display Word's Save As dialog box, you use the Show method, as illustrated in the following statement:
Dialogs(wdDialogFileSaveAs).Show
It's as simple as that. To display Word's Replace dialog box, just substitute wdDialogEditReplace for wdDialogFileSaveAs.
THE Dialogs COLLECTION IS CREATABLE IN WORD, BUT NOT IN EXCEL
In Word, the Dialogs collection is a “creatable object,” meaning you can access it directly without going through the Application object. In Excel, however, the Dialogs collection is not creatable, so you must always add the Application object to this code, like this:
Application.Dialogs (xlDialogOptionsGeneral).Show.
VBA provides two methods of displaying built-in dialog boxes onscreen: Show and Display:
DISPLAYING A PARTICULAR TAB OF A WORD DIALOG BOX
If the dialog box you want to display has tabs, you can display the tab of your choice by specifying the DefaultTab property. You refer to a tab by the name of the dialog box plus the word Tab and the name of the tab. For example, the constant for the Bullets And Numbering dialog box is wdDialogFormatBulletsAndNumbering, and the constant for its Outline Numbered tab is wdDialogFormatBulletsAndNumberingTabOutlineNumbered. Likewise, the Font dialog box is referred to as wdDialogFormatFont, and its Character Spacing tab is referred to as wdDialogFormatFontTabCharacterSpacing. You could display this tab by using the following statements:
With Dialogs(wdDialogFormatFont) .DefaultTab = wdDialogFormatFontTabCharacterSpacing .Show End With
To get a list of all the tab constants, search for wdWordDialogTab in the Object Browser.
The Show method displays the specified dialog box and automatically responds to whatever actions the user takes in it. Show is useful when your user is merely going to perform a conventional interactive action. As a simple example, in a procedure that's supposed to perform certain formatting tasks on the current document, you could check to make sure a document was open before attempting to perform the formatting; then, if no document was open, you could display the built-in Open dialog box so that the user could open a file. (You might precede the Open dialog box with a message box explaining the problem.) Listing 14.3 shows the code for this part of the procedure.
1. If Documents.Count = 0 Then
2. Proceed = MsgBox("There is no document open."
& vbCr & vbCr & _
"Please open a document for the procedure to work on.",
vbOKCancel + vbExclamation, "Format Report")
3. If Proceed = vbOK Then
4. Dialogs(wdDialogFileOpen).Show
5. If Documents.Count = 0 Then End
6. Else
7. End
8. End If
9. End If
10. 'rest of procedure here
Remember that unlike the Show method, the Display method displays a built-in dialog box but doesn't respond to any actions the user takes in the dialog box. Instead, you must write code that checks the settings that the user chose in the dialog box and then write more code to carry out the user's wishes. When you use the Display method, the user gets to work with familiar dialog boxes, but you totally control the behavior that results from that interaction.
For example, you'll often need to find out which folder a procedure should be working in, such as when you need the location of a number of documents that the user wants to manipulate. To get the folder, you could display a straightforward input box and prompt the user to type in the correct path to the folder—if the user knows the path and can type it in correctly.
Perhaps a better solution is to display a list box containing the tree of drives, folders, and files on the user's hard drive, but to do this you need to dimension an array and fill it with the folders and filenames, and you need to refresh the display every time the user moves up or down the tree—quite a lot of programming work.
So why not just borrow all this functionality from a built-in common dialog box? It's already part of the Office applications. You can achieve the same result much more easily by using a built-in dialog box that has the tree built in (for example, the Open dialog box) and then retrieving the user's responses for your own purposes.
If you need to execute the settings (user choices) in a built-in dialog box, you can use the Execute method. But you might want to check the user's selections in the dialog box before implementing them. If you find a problem, you could then, for example, display a dialog box of your own, such as an Input Box, asking for clarification.
Most of the built-in Word and Excel dialog boxes have arguments that you can use for retrieving or setting values in the dialog box. For example, the Open dialog box in Word has arguments for Name, ConfirmConversions, ReadOnly, LinkToSource, AddToMru (adding the document to the Most Recently Used document list on the Recent section of the File tab on the Ribbon), PasswordDoc, and more. Some of these are options that you'll see in the Open dialog box itself; others are associated options that you'll find on the various tabs of the Options dialog box. You can guess some argument names from the names of the corresponding controls in the dialog box, but other names aren't directly related. To learn the names, search for “Built-in Dialog Box Argument Lists” in the VBA Editor's Help system (choose MSDN on the Web, then search with Bing).
For example, the following statements set the contents of the File Name text box in the Save As dialog box in Word and then display the dialog box:
With Dialogs(wdDialogFileSaveAs) .Name = "Yellow Paint Primer" .Show End With
Be aware that some arguments that applied to dialog boxes displayed by Office 2003 no longer apply to Office 2007, 2010, or 2013 dialog boxes. So you may need to experiment a bit to see if a particular legacy argument is still useful in the Office 2013 interface.
If you change the settings in a dialog box that uses sticky (persistent) settings, it's a good idea to change them back at the end of your procedure so that users don't get unexpected results the next time they open the dialog box.
To find out which button the user clicked in a dialog box, check the return value of the Show method or the Display method. The return values are shown in Table 14.12.
RETURN VALUE | BUTTON CLICKED |
−2 | Close |
−1 | OK |
0 | Cancel |
1 | The first command button |
2 | The second command button |
>2 (greater than 2) | Subsequent command buttons |
For example, you might want to cancel your whole procedure if the user clicks the Cancel button in a dialog box, like this:
If Dialogs(wdDialogFileOpen).Show = 0 Then End
In some applications, including Word, you can display some built-in dialog boxes for a specified time rather than having them stay open until the user dismisses them by clicking OK or Cancel or some other button. To do so, you use the TimeOut Variant argument with the Show method or the Display method. You specify TimeOut as a number of units, each of which is approximately a thousandth of a second. (If the system is busy with many other tasks, the actual result might be a slightly longer delay.) So you could display the General page of the Word Options dialog box for about 10 seconds—long enough for the user to check the Name setting and change it if necessary—by using the following statements:
With Dialogs(wdDialogToolsOptions) .DefaultTab = wdDialogToolsOptionsTabUserInfo .Show (10000) End With
THE TIMEOUT ARGUMENT DOESN'T WORK WITH CUSTOM DIALOG BOXES
TimeOut doesn't work with custom dialog boxes you create, only with the built-in Word dialog boxes. Also, some built-in Word dialog boxes—such as the New dialog box (wdDialogFileNew) and the Customize dialog box (wdDialogToolsCustomize)—don't recognize the TimeOut option either.
Timing out a dialog box is especially useful for noncritical information like the username in this example because it allows the procedure to continue even if the user has left the computer. Likewise, you might want to TimeOut a Save As dialog box in which the procedure suggested a viable filename but allowed users to override it if they were present. However, for a procedure in which the user's input is essential, you won't want to use the TimeOut argument. You want to compel the user to respond by at least clicking a button; in this context, the dialog box should not disappear all by itself via this timeout technique.
Understand what you can do with a custom dialog box. Custom dialog boxes—user interfaces you design as forms in the Visual Basic Editor—are often needed in macros and other kinds of Office automation. You might, for example, want to display a dialog box that allows the user to specify whether to let a macro continue beyond a certain point in its code or cease execution. Perhaps your macro is searching through a document for a particular phrase; then when it finds that phrase, it displays a dialog box to users asking if they want to continue further.
Master It Which VBA statement would you use to stop a macro from continuing execution?
Create a custom dialog box. You use the Visual Basic Editor to both design a custom dialog box (form) and write code for macros. You can attach the various controls to a form and then enter code behind the dialog box.
Master It How do you switch between the form-design window (sometimes called the object window) and the Code window in the Visual Basic Editor?
Add controls to a dialog box. It's easy in the Visual Basic Editor to add various controls—such as command buttons and text boxes—to a user form (a custom dialog box).
Master It How do you add a command button to a custom dialog box?
Link dialog boxes to procedures. Buttons, check boxes, option buttons—displaying various controls to the user is fine, but unless you write some code behind these various user-interface objects, what's the point? Your macro's user shouldn't discover that clicking a button does nothing.
Dialog boxes often display objects with which users can communicate their wishes to your code. Therefore, you write code that explores the values the user enters into controls and responds to whatever buttons the user might click.
Master It Create a small custom dialog box that displays a message in a label control saying, “Would you like to know the current date and time?” Put an OK button and a Cancel button on this form. Write code that simply ends the procedure if the user presses the Cancel button but that displays the date and time in the label if the user clicks the OK button. If the user clicks OK a second time, end the procedure.
Retrieve the user's choices from a dialog box. A major task of most dialog boxes is retrieving values that the user has specified in various controls by selecting check boxes and so on. Then you write code to carry out the user's wishes based on these retrieved values. This interaction via dialog box is the typical way that a user communicates with your procedures, and vice versa.
Master It Create a new dialog box that contains three option buttons captioned Small, Medium, and Large and named optSmall, optMedium, and optLarge. Write code in each option button's Click procedure to change the button's caption to boldface when the button is clicked.
3.12.74.18