Teach Yourself Borland Delphi 4 in 21 Days

Previous chapterNext chapterContents


- 6 -

Working with the Form Designer and the Menu Designer


As you know by now, Delphi is heavily form-based, a model that takes maximum advantage of the visual programming environment. In this chapter you will explore

To illustrate the use of the Form Designer, you will build an application that approximates the Windows Notepad program. Along the way you will gain valuable experience working with the Form Designer. Later in the chapter, you'll explore the Menu Designer in detail.

This chapter might seem elementary if you have used Delphi extensively. Even so, be sure to take a quick look to discover things previously unknown or to rediscover things you've forgotten. I'm willing to bet there is at least one thing in this chapter that will be new to you.

Working with the Form Designer

The Delphi Form Designer is a powerful visual programming tool. It enables you to place, select, move, resize, and align components and much more. The Form Designer also enables you to size and position the form itself, add menus, and create specialized dialog boxes--everything you need to create the user interface to a typical Windows program.

I'll examine each Form Designer feature in the following sections. As you read, I encourage you to stop and experiment any time you are curious about how something works. Sometimes a few minutes playing around can teach you a technique that you will use for a long time to come.

The Form Designer's Context Menu

When you first start Delphi or when you create a new project, you are presented with a blank form in the Form Designer. The Form Designer, like most Delphi windows, has a context menu associated with it. Table 6.1 lists and describes each item on the Form Designer context menu.

TABLE 6.1. THE FORM DESIGNER'S CONTEXT MENU ITEMS.

Item Description
Align to Grid Aligns selected components to the Form Designer grid.
Bring to Front Brings selected components to the front of all other components.
Send to Back Sends selected components behind all other components.
Revert to Inherited Causes the selected control to revert to its original state when you are working with a form that you have inherited from the Object Repository. (Inheriting forms from the Object Repository is covered on Day 8, "Creating Applications in Delphi.")
Align Displays the Alignment dialog box.
Size Displays the Size dialog box.
Scale Displays the Scale dialog box.
Tab Order Displays the Edit Tab Order dialog box.
Creation Order Displays the Creation Order dialog box.
Flip Children For non-English versions of Windows, this command changes the reading order of a component. Disabled for English versions of Windows.
Add to Repository Adds this form to the Object Repository. Custom forms can be saved to be used later. (The Object Repository is discussed on Day 8.)
View as Text Shows the form description as text in the Code Editor. You can edit the form's text version if you like. Choose View as Form from the Code Editor context menu to go back to the form. You can also use Alt+F12 to switch from the View as Text and View as Form options.


NOTE: Delphi creates a form file (DFM) for every form you create and places it in your project's directory. The form file is a binary resource file that can't be read by mere humans. When you choose the View as Text context menu item, Delphi converts the binary resource to readable form. When you switch back to the View as Form option, Delphi recompiles the form file to implement any changes you have made.

Most of the context menu options are discussed in the following sections. Others are discussed in later chapters when you examine the particular aspect of Delphi to which they pertain.

Placing Components

Placing a component on a form is simple. All you have to do is select the component you want from the Component palette and click on the form to place the component. When you click on the form, the component's upper-left corner is placed at the location you clicked. Notice that when you click a button on the Component palette, the button appears as pressed. When you click on the form to place the component, the button on the Component palette pops up again to indicate that the action is complete.


TIP: As you learned on Day 4, "The Delphi IDE Explored," to place a component on a form multiple times, press and hold Shift when you first select the component's button on the Component palette. Each time you click on the form, a new component will be added. Click the Arrow button on the Component palette to stop placing components.

Most components can be sized. You can place a component on a form and then size it, or you can size the component at the same time you place it on the form. To size while placing the component, click on the form where you want the top-left corner to be placed and then drag with the mouse until the component is the desired size. When you release the mouse, the component will be placed at the size you specified.


NOTE: Not all components can be sized in this manner. Nonvisual components, for example, are represented on the form by an icon. Although you can click and drag to place a nonvisual component, the drag size will be ignored. Another example is a single-line edit component. The edit component can be placed by dragging, but only the drag width will be used. The drag height will be ignored because the height of a single-line edit component defaults to the height of a single-line edit control.


CAUTION: If you change your mind while placing the control via the dragging method, you can press the Esc key on the keyboard before you release the mouse button to cancel the operation. The component's button will still be pressed on the Component palette, however, so you might need to click the Arrow button to return to component-selection mode.

Placing components is simple enough that you don't need to spend much time on the subject. You had some experience with placing components yesterday, so let's move on to other things.

The Form Designer Grid

The Form Designer has a built-in grid that aids in designing forms. By default, Delphi shows the grid. The grid size is initially set to eight pixels horizontally and eight pixels vertically. When the Form Designer is set to display the grid, a dot is placed at the intersection of each grid point. Components placed on a form will snap to the nearest grid point. By snap to I mean that the component's top-left corner will automatically jump to the nearest grid point. This is an advantage because you frequently want a group of controls to be aligned either on their left, right, top, or bottom edge. When the Snap to Grid option is on, you merely get close enough to the correct location and the Form Designer automatically places your component at the nearest grid point. This saves you time by sparing you from tweaking the individual component's size or position on the form.

The grid settings can be modified via the Preferences page of the Environment Options dialog box. (I'll discuss the Environment Options in detail on Day 9, "Projects, the Code Editor, and the Code Explorer.") From here you can change the grid size or turn off the Snap to Grid feature. You can also turn the grid display on or off. When the grid display is off, the grid is still active (assuming Snap to Grid is on), but the dots marking grid points are not drawn on the form.

Selecting Components

After you place a component on a form, you often have to select the component in order to modify it in some way. You might have to select a component to perform one of the following actions:

Selecting Individual Components

To select a single component, just click on it. When you select the component, eight black sizing handles appear around the component to indicate that it is selected. (I'll discuss the sizing handles in a moment.) Figure 6.1 shows a form with a button component selected.

As soon as you select a component, the Object Inspector changes to show the properties and events for the control you selected. To deselect a control, click on the form's background or Shift+click on the control. (Shift+click is described in the next section.)


NOTE: Each component has a default event handler associated with it. When you double-click a component on a form, the Code Editor displays the default event handler for that component, ready for you to type code. In most cases, the default event handler is the OnClick handler. Exactly what happens when the component is double-clicked depends on how the component is designed. For example, in the case of the Image component, double-clicking will display the Picture Editor dialog box.

FIGURE 6.1. A form with a button component selected.


Selecting a Group of Components

You can also select multiple components so that you can act on them as a group. This is accomplished in one of three ways:

To select all components on the form, choose Edit | Select All from the main menu.

Selecting Components with Shift+Click

To use the Shift+click sequence, first select one control. Then press and hold the Shift key on the keyboard and click on any other controls you want to include in the selection. Each control you click is bounded by four gray boxes to indicate that it is part of the selection.

You can remove a control from the selection by continuing to hold the Shift key and again clicking on the component. In other words, the Shift+click sequence toggles a component's inclusion in the selection. To illustrate, first start with a blank form and then perform the following steps:

1. Place three button components anywhere on the form. They will automatically be labeled Button1, Button2, and Button3.

2. Click Button1. The black sizing rectangles appear around the component.

3. Press and hold the Shift key on the keyboard. Click Button2. It is added to the selection. Gray boxes now appear at the corners of both Button1 and Button2.

4. Shift+click on Button3. Now all three buttons are part of the selection.

5. Shift+click again on Button2. Button2 is removed from the selection (the gray boxes disappear), but Button1 and Button3 are still included in the selection.

6. Shift+click on Button1. Now Button3 is the only component in the selection. The gray boxes are replaced with the black sizing rectangles.

7. Shift+click on Button1 and Button2. All three buttons are now part of the selection again.

Figure 6.2 shows the form as it will look at the end of this sequence. Keep in mind that your buttons could have been placed anywhere on the form. Keep the form handy because you'll use it again in the next exercise.

FIGURE 6.2. A form with three buttons selected.


NOTE: If you click on a component that is part of a selection, nothing will happen. To select a single control that is currently part of a group selection, you need to first click on the form's background or press the Esc key to remove the group selection. Then you can click on the individual control you want to select.


Selecting Multiple Components by Dragging

You can select multiple controls by dragging a bounding rectangle around the controls to be selected. The bounding rectangle is a broken-line rectangle that changes size as you drag. In fact, you don't have to drag the bounding rectangle completely around the components. You have only to touch a component with the bounding rectangle in order for it to be included in the selection.

Be sure that you start by placing the mouse cursor over the form's background and not on a component. Hold the left mouse button down and begin dragging. You will see the bounding rectangle as you drag. Surround or touch the components you want selected and release the mouse button. Any components that were inside the bounding rectangle (or touching it) are included in the selection.

When you have selected a group of controls, you can use the Shift+click technique explained in the previous section to add other controls to the selection or to remove controls from the selection. For example, you might want to select all controls in one area of your form except for one. Surround the controls and then deselect the control you want to exclude from the selection.

Go back to the form with the three buttons you created earlier (if you've already discarded that form, create a new one and place three buttons on it). Start at the top-left corner and drag down and to the right to surround the buttons. Let go of the mouse button and the controls will be selected. Figure 6.3 shows the form and the bounding rectangle being dragged.

FIGURE 6.3. Controls being selected by dragging.

CAUTION: You can use Shift+drag to select non-adjacent groups of controls. If, for instance, you have two separate groups of controls in different areas on your form, you can drag around the first set and then hold the Shift key down and drag around the second set. Both groups will be selected.



NOTE: You don't have to drag down and to the right. You can drag in any direction to select components.


Selecting Multiple Items: Components within Components

Frequently you will have components placed within other components. The Panel component is often used as a container for other components. To select a group of components on a panel, you have to hold down the Ctrl key on the keyboard while you drag to select the components. (Try it without holding down the Ctrl key and see what happens!) In case you're wondering, yes, you can use a combination of Ctrl+Shift+drag. (I suppose the Borland designers could have figured out some way of working the Alt key in there, too.)

To illustrate, first start with a blank form. Then do the following:

1. Select a Panel component from the Component palette and place it on the form using the drag method. Drag it so that it occupies most of the form.

2. Now select a Button component and place six buttons on the form. Your form will look something like Figure 6.4.

FIGURE 6.4. The form with a panel and six buttons.

3. Drag a bounding rectangle around Button1, Button2, and Button3. Notice that you moved the panel, which is not what you expected (and not what you wanted). Move the panel back to where it was.

4. Hold down the Ctrl key and drag a rectangle around Button1, Button2, and Button3. The buttons are selected.

5. Now hold down both the Ctrl and Shift keys and drag the bounding rectangle around Button5 and Button6. Now all buttons are selected except Button4.

Using the Ctrl+drag sequence is the only way to select a group of components contained within another component if you are using the drag method. You can use the Shift+click method to select components contained within another component just as you do when selecting components on a form.

Moving Components

Moving components is a common and simple task. To move an individual component, place the mouse cursor over the component and drag. As you drag, a rectangle that represents the component moves with the mouse cursor. When you have the rectangle where you want it, let go of the mouse button and the component will be moved to that location.


NOTE: When you move a control via drag and drop, the control's Left and Top properties are automatically updated. If you pause for a moment while moving a component, you will notice a tooltip appear next to the mouse cursor. The tooltip shows what the new top and left position of the component will be when you stop dragging.


A similar tooltip is displayed when sizing a component by dragging. In the case of sizing a component, the tooltip shows what the new width and height of the component will be when you stop dragging. Figure 6.6 shows the tooltip you see when sizing a component (in the lower-right corner).

If you have the Snap to Grid option on, the dragging rectangle will snap to the nearest grid point as you drag.


TIP: If you change your mind while dragging, you can press the Esc key on the keyboard before you release the mouse button to cancel the drag operation. The component will return to its original position.

Dragging a group of controls works the same way. After you have a group of components selected, place the mouse cursor over any one of the controls and begin dragging. The dragging rectangle will be displayed for each control in the group. This enables you to visualize where the group will be placed when you release the mouse button.


NOTE: You cannot move a group of components if components in the group have different parent controls. For instance, let's say you select both a Button component on the main form and a SpeedButton on a panel. Because these two components have different parent controls, you cannot move them as a group.



TIP: When you have selected a control, you can nudge it a pixel at a time by holding down the Ctrl key while using the arrow keys on the keyboard. This technique works for both groups of controls and individual controls. The Snap to Grid feature is overridden when you use this technique.
After you have moved a component using this method, the component is no longer on a grid point--it is offset by some amount. If you now drag the component, it will maintain its offset from the grid point as you drag.
TIP: If you move a control using the Ctrl+arrow method and want to align it again to the grid, choose Edit | Align to Grid from the main menu. The control's top-left corner will snap to the nearest grid point.

A control cannot be dragged outside its parent form. If you drag a component off the form's left or top edge, you will see that the component is clipped at the form's edge. If, however, you drag the component off the right or bottom of the form and drop it, scrollbars will appear on the form so that you can scroll to see the rest of the form.

The form's Width and Height properties are not altered. If you drag the component back onto the visible part of the form, the scrollbars disappear again. This is the default behavior and will occur unless you change the form's AutoScroll property to False. Figure 6.5 shows a Memo component that has been dragged partially off the form's right edge. Notice the scrollbar that appears at the bottom of the form.

Preventing Components from Being Moved or Sized

Components can be locked into place so that they cannot be moved. Locking components is useful if you know that a form's design is final and you don't want to worry about accidentally moving controls. To lock a form's controls, choose Edit | Lock Controls from the main menu. Locked controls cannot be moved or sized. When controls are locked, their sizing handles are gray with a black border. To unlock the controls, choose Edit | Lock Controls again. The controls can now be moved as before. You can lock all components on a form with this technique or none of the components. You cannot, however, lock just selected components.

FIGURE 6.5. A form with AutoScroll in action.

Ordering, Cutting, Copying, and Pasting Components

Sometimes you will place components on top of one another to achieve a visual effect. For example, a shadowed box can be created by placing a white box over a black box (both would be Shape components). Obviously you can't have the shadow on top of the box, so you have to order the controls to tell Delphi which controls go on top and which go on the bottom. Let's do a simple exercise that illustrates this. Along the way, you will also see how you can use Copy and Paste with components. First, start with a blank form (you know the drill by now). Now follow these steps:

1. Click on the Additional tab on the Component palette and choose the Shape component. Click on the form to place the shape. A white square appears on the form.

2. Size the shape as desired (mine ended up being 209 pixels by 129 pixels).

3. Be sure the Shape component is selected. Choose Edit | Copy from the main menu.

4. Choose Edit | Paste from the main menu. A copy of the shape is placed below and to the right of the original shape. Conveniently, this is exactly where you want it.


NOTE: After a paste operation, the component just pasted will be selected.

5. Double-click the Brush property in the Object Inspector and change its Color property to clBlack. The new shape is now black, but it is on top of the original shape. Can't have that!

6. Click the secondary mouse button and choose Send to Back from the context menu (you can also choose Edit | Send to Back from the main menu). The black shape is moved behind the white shape. You now have a box with a shadow. (As an alternative, you could have clicked on the white shape and used Bring to Front to move it on top of the black shape.)

This exercise illustrates two features of the Form Designer. It shows how you can change the stacking order of controls and how you can use Copy and Paste to copy components. The original component's properties are copied exactly and pasted in as part of the pasting process. Each time you paste a component, it is placed below and to the right of the previous component you pasted.


NOTE: If a component that can serve as a container is selected when you perform Paste, the component in the Clipboard will be pasted as the container component's child. For example, you might want to move a button from the main form to a panel. You can select the button and choose Edit | Cut from the main menu to remove the button from the form and place it in the Clipboard. Then you can select the panel and choose Edit | Paste from the main menu to paste the button onto the panel.

I don't need to go into much detail on the cut operation. When you cut a component, the component disappears from the form and is placed in the Clipboard. Later, you can paste the component onto the form or onto another component such as a Panel component.


TIP: You can also copy a component and paste it into your source code. The results will be something like this:

object Edit1: TEdit
  Left = 24
  Top = 16
  Width = 457
  Height = 21
  TabOrder = 0
  Text = `Edit1'
end



This is not code that will compile, but this technique will give you a component's size and position as it appears on the form. This information comes in handy when you create components on-the-fly at runtime rather than at design time. You can place a dummy component visually on the form, get its size and position using Copy and Paste, and then delete the component. Then you can write code to create the component at runtime and know that it will be properly sized and positioned.


Sizing Components

With some components, you drop them on a form and accept the default size. Buttons are a good example. A standard button has a height of 25 pixels and a width of 75 pixels. For many situations, the default button size is exactly what you want. With some components, however, the default size is rarely exactly what you need. A Memo component, for example, nearly always has to be sized to fit the specific form on which you are working.

Sizing by Dragging

When you select a control, eight black sizing handles appear around the control. When you place the mouse cursor over one of the sizing handles, the cursor changes to a double-headed arrow known as the sizing cursor. When you see the sizing cursor, you can begin dragging to size the control. How the component is sized depends on which sizing handle you grab.

The sizing handles centered at the top and bottom of the component size it vertically (taller or shorter). Likewise, the right and left sizing handles size the component horizontally (wider or narrower). If you grab one of the sizing handles in the component's corners, you can size both horizontally and vertically at the same time. As with moving a component, a sizing rectangle appears as you drag. When the sizing rectangle is the desired size, let go of the mouse button and the component will be resized. Figure 6.6 illustrates a memo component being sized by dragging; Figure 6.7 shows the form after the drag operation.


NOTE: Sizing applies to visual components only. Nonvisual components appear on the form as an icon that cannot be sized. The sizing handles appear on nonvisual components and the handles can be dragged, but the result of the dragging operation will be ignored.

FIGURE 6.6. A memo component being sized.

FIGURE 6.7. The form after sizing the memo component.

Groups of controls cannot be sized by dragging. The sizing handles (black squares) are replaced by selection indicators (gray squares) when you select more than one component.


TIP: To size all the components in a group at one time, modify the Width or Height property in the Object Inspector or use the Size dialog box (the Size dialog box is discussed in the next section). All components in the selection will take on the new values.


TIP: To size a control or group of controls by one pixel at a time, hold down the Shift key and press any arrow key on the keyboard. The up and down arrows size the control vertically and the right and left arrows size it horizontally. Only the component's Width and Height properties are affected. The Top and Left properties are not modified.


Sizing with the Size Dialog Box

Another sizing option is the Size dialog box. You can bring up the Size dialog box by choosing Edit | Size from the main menu. Figure 6.8 shows the Size dialog box.

FIGURE 6.8. The Size dialog box.

The Size dialog box is used when you want to force a group of controls to the same width or height. For instance, let's say you have six edit components on a form, all with different widths. To make the form appear more balanced, you might want to make all the edit components the same width. First, select the components and then invoke the Size dialog box. From there you can choose Shrink to smallest (in the Width column) to make all the components the width of the shortest edit component, or Grow to largest to make all the components the width of the longest component in the group. You can also enter an exact width in the Width box, in which case you would leave the Height set on No change. When you click OK, the components will all be the same width.


TIP: The Size dialog box can also be invoked from the Form Designer context menu.


Sizing with the Scale Dialog Box

Another sizing tool is the Scale dialog box, shown in Figure 6.9. This dialog box enables you to specify a scaling percentage. To make the components twice as large, enter 200 in the Scaling factor box. To reduce the components' size by half, enter 50 in the Scaling factor box. The Scale dialog box is convenient for quickly changing the size of all the form's components. You can bring up the Scale dialog box by choosing Edit | Scale from the main menu or Scale from the Form Designer context menu.

A control can also be sized and moved by using the various Alignment options. Let's take a look at those in the next section.

FIGURE 6.9. The Scale dialog box.



NOTE: Remember, components can always be moved by modifying their Left and Top properties and sized by modifying their Width and Height properties in the Object Inspector.

Aligning Components

Regardless of whether you have the Snap to Grid option turned on, you sometimes need to align components after placing them. Aligning components could mean aligning several components along a common edge, centering components on the form, or spacing components. There are two ways to align components:

The following sections explain these two methods.


NOTE: You might have noticed the Alignment property for some components. This property pertains only to the way the component's text is aligned (centered, right-justified, or left-justified) and has nothing to do with aligning components on a form.

The Alignment Palette and the Alignment Dialog Box

It is often necessary to move or size components relative to the form or relative to one another. The Alignment palette contains several buttons that aid in that task. The Alignment dialog box performs the same operations as the Alignment palette, but in a different format. To display the Alignment palette, choose View | Alignment Palette from the main menu. Figure 6.10 shows the Alignment palette and describes each button. If you pause the mouse cursor over a button on the Alignment palette, a tooltip describing the button will appear.

FIGURE 6.10. The Alignment palette.



TIP: The Alignment palette can save you a lot of work. Don't spend too much time trying to get controls to line up exactly. Place the components on the form and then use the Alignment palette to position them.

The Align Left Edges button is used to line up components on their left edges. Start with a blank form and then do the following:

1. Place five button components vertically on the form without regard to their left edges.

2. Select the buttons by dragging a bounding rectangle around them. The selection indicators show that all the buttons are selected. The form will look something like the one in Figure 6.11.

FIGURE 6.11. The form with the buttons randomly placed.

3. Choose View | Alignment Palette from the main menu. The Alignment palette is displayed. Move the Alignment palette, if necessary, so that it doesn't obscure the form.

4. Click the Align Left Edges button on the Alignment palette. The buttons are all lined up.

See how easy that is? As long as you have the buttons selected, let's look at another alignment option. The Space Equally Vertically alignment option can now be used to space the buttons evenly. The buttons should still be selected, so all you have to do is click the Space Equally Vertically button on the Alignment palette, and voilà! The buttons are perfectly spaced. The form will now look like Figure 6.12.

FIGURE 6.12. The form with the buttons aligned and equally spaced.


NOTE: The Space Equally Vertically alignment option spaces the components equally between the first component in the column (the top component) and the last component in the column (the bottom component). Be sure to set the first and last components where you want them before choosing the Space Equally Vertically alignment option. This is true of the Space Equally Horizontally alignment option as well.

The Center Horizontally in Window and Center Vertically in Window alignment options do exactly as their names indicate. These options are convenient for centering a single control on the form or for centering a group of controls. As long as you still have the group of buttons selected, click both the Center Horizontally in Window and Center Vertically in Window buttons on the Alignment palette. The buttons will be centered on the form both horizontally and vertically.


NOTE: When you select a group of controls and click one of the centering buttons, the controls will be treated as a group. If you choose each control individually and center it both horizontally and vertically on the form, all the controls will be stacked on top of one another in the middle of the form. By selecting the group and then centering, you get the entire group centered as you intended.

The form will now look like the one shown in Figure 6.13.

FIGURE 6.13. The form with the buttons centered.



NOTE: The Center Horizontally in Window and Center Vertically in Window alignment options can be used to align components contained within other components, such as buttons on a panel. The components will be centered horizontally or vertically on their parent component regardless of whether the parent is a panel, a form, or some other container component.

The Align Tops, Align Bottoms, and Align Right Edges options work just like the Align Left Edges option you used earlier. There's not much point in going over all the possibilities that exist for their use.


TIP: The first component selected will be the anchor point when using any edge-alignment option. Refer to Figure 6.4. Let's say you selected Button3 first and then used Shift+click to select the remaining buttons. When you choose Align Left Edges, Button3 will remain where it is and all the other buttons will line up with Button3's left edge because Button3 is the anchor component.

The Align Horizontal Centers and Align Vertical Centers options can be used to center components relative to one another. This is best illustrated with shapes. Start with a new form (or delete the buttons from the form you have been working on). Now do the following:

1. Click on the Additional tab on the Component palette and choose the Shape component. Click somewhere on the upper left of the form to add the shape.

2. Change the Shape property to stCircle.

3. Change the Width and Height properties to 150.

4. Double-click the Brush property and change its Color property to clBlack.

5. Place another Shape component on the form.

6. Change the second shape's Shape property to stCircle as well. Now you have two circles of different sizes on the screen--a white circle and a black circle.

7. Click on the black circle. Hold the Shift key and click on the white circle. Both shapes are selected.

8. Choose View | Alignment Palette from the main menu, if necessary (it might already be displayed). Arrange the Alignment palette so you can see the two shapes on the form. Observe the shapes as you perform the last two steps.

9. Click the Align Vertical Centers button on the Alignment palette. The vertical centers are aligned.

10. Click the Align Horizontal Centers button on the Alignment palette. The horizontal centers are aligned. Congratulations--you made a tire!

Did you see the effect as you performed the last two steps? Notice that because you selected the black circle first, it did not move (it is the anchor component), but the white circle moved as you clicked the alignment buttons. You can use these alignment options to center any number of controls on one another. These two alignment options have no effect when used on a single control.

Like the Component palette, the Alignment palette has a context menu associated with it. Place the mouse cursor over the Alignment palette and click the secondary mouse button. The context menu is displayed. Table 6.2 lists the items on the Alignment palette's context menu and explains their uses.

TABLE 6.2. THE ALIGNMENT PALETTE'S CONTEXT MENU ITEMS.

Menu Item Description
Stay on Top Forces the Alignment palette to always be on top. This is useful if you are frequently switching back and forth between the Form Designer and the Code Editor. Because the Alignment palette is a small window, it's easy to lose it.
Show Hints Turns the hints (tooltips) for the Alignment palette buttons on and off.
Hide Hides the Alignment palette. (You can also use the close box on the
Alignment palette to hide it.) To show the Alignment palette again, you
have to choose View | Alignment Palette from the main menu.
Help Brings up Delphi Help with the Alignment palette page displayed.

The Alignment dialog box performs the same actions as the Alignment palette. To bring up the Alignment dialog box, choose Edit | Align from the main menu or Align from the Form Designer's context menu. Figure 6.14 shows the Alignment dialog box.

FIGURE 6.14. The Alignment dialog box.

In most cases, the Alignment palette is easier to use, but you can certainly use the Alignment dialog box if you prefer.

Using the Align Property

Another type of alignment can be set using the Align property. This property controls how a component is aligned with its parent. The possible values for the Align property and a description of each are listed in Table 6.3.

TABLE 6.3. POSSIBLE VALUES FOR THE Align PROPERTY.

Value Description
alBottom The component is aligned at the bottom of the parent window. A status bar is an example of a component aligned along the bottom of a main form.
alClient The component expands to fill the parent window's client area. If other components occupy part of the client area, the component fills what client area remains. Examples include Memo components, Image components, and RichEdit components.
alLeft The component is aligned along the parent window's left edge. A vertical toolbar is an example of a left-aligned component.
alNone The component is placed as designed with no special relationship to the parent. This is the default for most components.
alRight The component is aligned along the parent's right edge.
alTop The component is aligned along the top of the parent's window. A toolbar is an example of this type of alignment.

An example helps explain the Align property. Start with a blank form and then perform these steps:

1. Click on the Standard tab on the Component palette and choose a Panel component. Place the panel anywhere on the form.

2. Locate the Align property in the Object Inspector (it's at the top of the list). Notice that it is set on alNone. Change the Align property to alTop. The panel is aligned at the top of the form and it expands to fill the form's width.

3. Try to move the panel back to the middle of the form. The panel will snap back to the top.

4. Try to make the panel narrower. Notice that the panel retains its width.

5. Change the panel's height. Note that the panel's height can be changed (the width cannot).

6. Change the Align to alBottom. Now the panel is glued to the bottom of the form.

7. Change the Align to alRight and then alLeft. The width is now the same as the height was before. In effect, the panel is rotated. Again, attempts to move the panel or size it vertically fail.

8. Change the Align property to alClient. The panel expands to fill the form's entire client area. The panel cannot be resized in any dimension.

9. Change the Align property to alNone. The panel can again be sized and moved.

As you see, changing Align to anything other than alNone effectively glues the panel to one edge of the form. In the case of alClient, the panel is glued to all four edges.

Setting the Tab Order

New Term: The tab order refers to the order in which components receive input focus when the user presses the Tab key on the keyboard.

Delphi forms automatically support component navigation using the Tab key. This means that you can move forward from component to component using Tab and backward using Shift+Tab.


NOTE: There are two types of visual components. Windowed components are components that accept keyboard focus, which means that the component can be clicked with the mouse or tabbed to with the Tab key. When a component has keyboard focus, it either displays a specialized cursor (such as the I-beam cursor in an edit control) or has a focus rectangle drawn somewhere on the component. Windowed components include the Edit, Memo, ListBox, ComboBox, and Button components, as well as many more.

Non-windowed components are components that don't accept keyboard focus. Components such as Image, SpeedButton, Label, Shape, and many others are non-windowed components.

The tab order applies only to windowed components. Non-windowed components are excluded from the tab order.


The tab order is initially set based on the order the components were placed on the form when the form was designed. You can modify the tab order by changing the TabOrder property for each control in the Object Inspector, but that method is tedious because you have to go to each control individually. The Edit Tab Order dialog box provides an easier way (see Figure 6.15).

FIGURE 6.15. The Edit Tab Order dialog box.

The Edit Tab Order dialog box is invoked by choosing Edit | Tab Order from the main menu. This dialog box displays all windowed components currently on the form; non-windowed components are not displayed. To change the tab order, click on the name of the component you want to move in the tab order and then click the up or down buttons as needed. You can also drag the component to its new position in the tab order. After you get the tab order the way you want it, click OK to set it that way. You can confirm the new settings by viewing each control's TabOrder property.


NOTE: The tab order starts with 0. The first component in the tab order is 0, the second is 1, and so on.

Building an Example Application

To illustrate how different components work together, let's build a prototype of an application that resembles Windows Notepad, Windows standard text editor.


NOTE: Building a text editor probably doesn't sound too glamorous. To be honest, it's not. What building a text editor will do for you, however, is teach you how to conquer many of the real-world problems you will encounter when programming in Delphi. It might not be glamorous, but it will almost certainly teach you more than building Snazzy Gadgets 1.0.

New Term: A prototype is an application that has the appearance of a working application but lacks full functionality, usually because it's in the early stages of design.


NOTE: Delphi is perfect for quick prototyping of an application. You can have the main screens and dialog boxes designed and displayed in much less time than it would take with traditional Windows programming tools. That is not, however, to say that Delphi is just for prototyping. Delphi is fully capable of handling all your 32-bit Windows programming needs.

Step 1: Starting a New Application

1. Choose File | New Application from the main menu. If prompted to save the current project, click No.

2. The form is selected, so change the Name property to MainForm.

3. Change the Caption to ScratchPad 1.0.

4. Choose Project | Options from the main menu. Click on the Application tab and enter ScratchPad 1.0 for the application's title. Click OK to close the Project Options dialog box.

Step 2: Adding a Toolbar

Most Windows applications these days have a toolbar. Building a toolbar requires several steps in itself. I'm not quite ready to explain everything there is to know about toolbars in Delphi, so I'll save that for Day 13, "Beyond the Basics." You'll add a toolbar to the ScratchPad program at that time. What you can do for now, though, is add a toolbar that can be used as a placeholder for the real toolbar that you add later. Follow these steps:

1. Click on the Win32 tab on the Component palette and choose the ToolBar component (it's the third from the right).

2. Click anywhere on the form to add the toolbar. Notice that the toolbar automatically aligns itself to the top of the form.

3. Right-click on the toolbar and choose New Button. A button appears on the toolbar.
4. Repeat step 3 to add a second button.

That's all you are going to do with the toolbar for now. As I said, you'll make a real toolbar for this program on Day 13.

Step 3: Adding a Status Bar

Okay, so far, so good. Windows Notepad doesn't have a status bar (or a toolbar, for that matter), but you can put one in your application by following these steps:

1. Click on the Win32 tab on the Component palette and choose the StatusBar component.

2. Click anywhere on the form. The status bar is automatically placed at the bottom of the form. The status bar has a default Align value of alBottom.

3. Change the Name property to StatusBar.

The form will now look like Figure 6.16.

FIGURE 6.16. The ScratchPad form up to this point.

Step 4: Adding the Memo Component

You need some component in which to type text, so you can use a memo component to add this feature (believe it or not, you're almost done with your prototype):

1. Click on the Standard tab on the Component palette and choose a Memo component. Place the memo anywhere on the form's client area.

2. Change the Name property to Memo.

3. Double-click the Value column next to the Lines property. The String List Editor is displayed. Delete the word Memo and click OK.

4. Change the Scrollbar property to ssVertical. (Initially, you want only a vertical scrollbar on the memo.)

5. Change the Name property of the Font property to Fixedsys. (Because this is a Notepad copycat, you'll use the system font.)

6. Change the Align property to alClient. The memo expands to fill the client area between the toolbar and the status bar.

Stand back and admire your work. This is starting to look like a real application! If the form looks too large or too small, resize it by dragging the lower-right corner. It's your program, so make it look the way you want it to look.


TIP: Pressing the Esc key selects the parent of the control that currently has the selection. For example, our form's client area is covered by components, which makes it impossible to select the form itself. To make the form the active component in the Object Inspector, select the memo component and then press the Esc key on the keyboard. You can also choose the form from the Component Selector combo box on the Object Inspector.

Notice that all the controls automatically resize themselves to retain their relationship with the parent window--the form, in this case. That is one of the main advantages to the Align property. The form now looks like the one in Figure 6.17.

Running the Program

You can now click the Run button to run the program. You can type text in the window's client area and you can press the toolbar buttons (although they don't do anything at this point). Keep in mind that this is a prototype and is mostly for show right now. You add more to the program by the end of the day.

FIGURE 6.17. The completed prototype.

You'd better save the project because you're going to use it later in the chapter. Choose File | Save All from the main menu. Save the main form's source unit as SPMain and the project as Scratch.

May I See a Menu, Please?

Menus are a big part of most Windows applications. Some Windows programs don't have menus, but the vast majority do. Delphi makes creating menus easy with the Menu Designer. The Menu Designer has the following features:

All the Menu Designer's commands are accessed via the Menu Designer context menu or by interacting with the Object Inspector. Figure 6.18 shows the Menu Designer's context menu.

For the most part, these menu items are self-explanatory, so I'm not going to go over each one. Rather, you can learn about them by working with them. To begin, let's add a main menu to the ScratchPad application you created earlier. After that you'll add a context menu.

FIGURE 6.18. The Menu Designer's context menu.

Creating a Main Menu

The Menu Designer enables you to quickly build any menu. The menu structure for a main menu consists of a MainMenu component, which is represented by the VCL class TMainMenu. Each item on the menu is a MenuItem component that is encapsulated in the TMenuItem class. You don't need to be too concerned about the intricacies of how these classes work together because the Menu Designer makes creating menus easy. With that brief overview, let's add a main menu to the ScratchPad application.

Adding a Main Menu to the Form

The first thing you must do is add a MainMenu component to your form.


NOTE: By now you have had some experience with Delphi. From this point on I will abbreviate some steps that you need to take to perform certain actions. For example, from here on I'll say, "Place a MainMenu component on the form" rather than "Click on the Standard tab on the Component palette. Click the MainMenu button and click on the form to place the component." Don't worry, I'll still give plenty of details when new operations are introduced.

1. Open the ScratchPad project you created earlier in the chapter.

2. Place a MainMenu component on the form and change its Name property to MainMenu. Notice that a MainMenu component has very few properties and no events. All the menu's work is done by the individual menu items.

3. Double-click on the MainMenu icon. The Menu Designer is displayed.

The Menu Designer looks like a blank form without grid points. The Menu Designer can be sized in any way you want. The size is just for your convenience and has no bearing on how the menu operates at runtime. At this point, the Menu Designer is waiting for you to begin building the menu. After you have created your first menu, you will find that menu creation is easy and intuitive.

Creating a Menu by Hand

Although there are easier ways to create a File menu, you will create your first menu by hand. The Menu Designer always has a blank menu item that acts as a placeholder for any new menu items you will create. When you first start the Menu Designer, the blank item is selected.

1. Change the Name property to FileMenu.

2. Click on the Caption property in the Object Inspector, type &File, and press Enter.


NOTE: The ampersand (&) is used to create the underlined character for a menu item. The underlined character is the accelerator the user can type in combination with the Alt key to navigate a menu using the keyboard. You can put ampersands anywhere in the menu item's text. For instance, the customary text string for the Exit menu item would be E&xit so that the x is the accelerator. All you have to do is provide the ampersands before the appropriate letter, Windows will take it from there.

At this point, several things happen. First, the File menu shows up in the Menu Designer. It also appears on the main form behind the Menu Designer. The other thing that happens is that a new, blank placeholder is added below the File menu you just created (you'll have to click on the File menu in the Menu Designer to see the placeholder). In addition, a new pop-up placeholder is created to the right of the File menu. The Object Inspector is displaying a blank MenuItem component, waiting for you to enter the Caption and Name property values. Figure 6.19 shows the Menu Designer as it appears at this point.

FIGURE 6.19. The Menu Designer and Object Inspector after creating the File menu.

Let's continue with the creation of the menu:

1. Change the Name property for the new item to FileNew.

2. Change the Caption property to &New and press Enter. Again, a blank item is created in the Menu Designer.

3. Repeat steps 1 and 2 and create menu items for Open, Save, and Save As. If you need help on where to place the ampersand, refer to Figure 6.20. Don't worry that you might not get it exactly right. You can always go back later and fix any errors.


TIP: Make your menus as standard as possible. Be sure that your accelerators (the underlined characters) are the same as in other Windows programs. Also, remember that an ellipsis (...) following a menu item's text is a visual cue to the user that choosing the menu item will invoke a dialog box.

At this point, you need a menu separator.

New Term: A separator is the horizontal line on a menu that separates groups of menu items.

Adding a separator is easy with the Delphi Menu Designer. All you have to do is put in a hyphen for the Caption property. Select the blank menu item under Save As, type a hyphen for the Caption, and press Enter. A separator is placed in the menu. Continue adding menu items until your menu looks like the one in Figure 6.20. If you need to modify a menu item, just click on it and change properties in the Object Inspector as needed.

FIGURE 6.20. The Menu Designer with the finished File menu.


NOTE: The Menu Designer always provides a blank menu item at the bottom of each pop-up menu and on the menu bar's right side. You cannot delete these blank items, but there's no need to--they are used only in the Menu Designer and won't show on the menu when your program runs.

Now that the File menu is done, you need to create an Edit menu and a Help menu.

Inserting a Menu from a Template

This time you'll take the easy approach. First, click on the blank pop-up menu placeholder to the right of the File menu. Now click your secondary mouse button and choose Insert From Template from the context menu. The Insert Template dialog box is displayed, as shown in Figure 6.21.

FIGURE 6.21. The Insert Template dialog box.

This dialog box shows a list of templates from which you can choose. You can use the predefined templates or create your own. In this case, you are only interested in adding an Edit menu, so choose Edit Menu and click OK. A full Edit menu is immediately inserted into the Menu Designer. In fact, it's a little too full. I'll deal with that in a moment.

As long as you're here, you can add the Help menu, too. Click on the placeholder to the right of the Edit menu. Choose Insert From Template again, and this time insert a Help menu. (Don't choose the Expanded Help menu, though.) You'll tidy up both the Edit and Help menus in the next section. Notice that the main form has been updating to show the new menu items as they are placed.


NOTE: You can insert templates to create pop-up menus as easily as creating main menu items.

Yes, inserting from a template is really that easy. After using Delphi for a while, you will no doubt have your own custom templates to choose from for building menus quickly and easily. You still have to update the Name properties to meaningful names, but it's much easier than creating the whole menu from scratch.


NOTE: The Insert From Resource choice works the same as Insert From Template except that it expects a resource script file (a resource script file has the extension .RC) containing a valid menu definition. The menu resource must use the begin/end menu resource syntax and cannot use braces. For example, the following is an invalid menu resource:

MENU_1 MENU
{
 POPUP "File"
 {
  MENUITEM "Open", 100
  MENUITEM "About", 101
 }
}



The following menu resource, however, is legal:

MENU_1 MENU
BEGIN
 POPUP "File"
 BEGIN
  MENUITEM "Open", 100
  MENUITEM "About", 101
 END
END



This applies only to menus inserted with Insert From Resource and not to menu resources in general.



Deleting Menu Items

The process of creating a Windows application is a living, breathing thing. Rarely will you get everything exactly right the first time. Users will request new features, the boss will come up with a few changes, and some features will even be dropped. You will often need to update your application's menus as these changes occur. For example, the Edit menu inserted earlier is a little verbose for your needs; there are several items that you just don't need. No problem--you can just delete them:

1. Click on the Edit menu.

2. Click on the item called Repeat <command>.

3. Press Delete on the keyboard or choose Delete from the Menu Designer context menu to delete the item. The item disappears and the remaining items move up.

4. Delete the Paste Special menu item as well.

There, that was easy! You're not quite done with the Edit menu, but before going on, I want to mention a very useful feature of the Menu Designer. You are probably familiar with using Shift+click and Ctrl+click when selecting items in other Windows programs. These techniques can be used in Windows Explorer to select files, for example. The Menu Designer supports Shift+click and Ctrl+click with one qualification--you can use these to select multiple menu items but not to deselect an item. As always, an exercise can illustrate better than I can explain:

1. The Edit menu should still be displayed. If not, click on Edit to reveal the Edit menu.

2. Click on the menu item called Goto.

3. Hold down the Shift key and click on the menu item called Object. All items between those two points are selected.

4. Press Delete on the keyboard to delete all the items at one time.

5. Move to the Help menu and delete the middle two items. Only the Contents and About items remain.

As you can see, the Shift+click technique can be used to quickly delete unwanted menu items. Now you have the menus trimmed back to the way you want them to appear in the ScratchPad application.

Inserting Menu Items

Inserting menu items is pretty straightforward. Just click on the menu item above which you want to insert a new item and press the Insert key on the keyboard (or choose Insert from the Menu Designer's context menu). A blank menu item is inserted, and you can now modify the Name and Caption properties just as you did earlier. Let's insert an item into the Edit menu:

1. Click on Edit to display the Edit menu.

2. Click on the Find menu item.

3. Press the Insert key on the keyboard. A new menu item is provided, and all other menu items below the new item move down.

4. Change the Name property to EditSelectAll and change the Caption property to Select &All.

5. Click on the empty placeholder at the bottom of the Edit menu. Add a menu separator (remember, just enter a hyphen for the Caption property).

6. Click on the placeholder again and add a new item. Make the Name property EditWordWrap and the Caption property &Word Wrap.

Moving Menu Items

You can easily move menu items as needed. You can move them up or down within the pop-up menu they are already in, or you can move them across pop-ups. There are two ways to move a menu item. The first is by using Cut and Paste. Cut and Paste 
work as you would expect, so there's no need to go over that. 

The other way to move a menu item is by dragging it to a new location and dropping it. Let's try it. You really want the Select All menu item just below the Undo item. That's easy enough to fix, you can just move it:

1. Click on Edit to display the Edit menu.

2. Click on the Select All item and drag it up until the separator under the Undo item is highlighted.

3. Let go of the mouse and the menu item is moved.

Too easy, right? Yes, but that's what Delphi is all about.

Batch Modifying Properties

Sometimes you want to modify several menu items' properties at once--that is called batch modifying. For example, you have a few menu items in the ScratchPad application that you are not ready to implement at this time. You aren't ready for printing support, for instance, nor are you ready to implement the help system. Therefore, you need to gray out (disable) those menu items:

1. Choose Help | Contents in the Menu Designer.

2. Change the Enabled property to False. The menu item is grayed out.

3. Click on the File menu.

4. Click on the Print menu item, hold the Shift key down, and click on the Print Setup menu item. Both items are selected.

5. In the Object Inspector, change the Enabled property to False. Both menu items are disabled.

6. Repeat steps 4 and 5 to disable the Find and Replace items on the Edit menu.

You can modify a group of menu items at one time with this method. Simply select the items you want to modify and then change the property you want to modify. All menu items currently selected will have the new property value.

Adding Bitmaps to Menu Items

You can easily add bitmaps to your menus. First click on a menu item for which you want to add a bitmap. Then, double-click in the Value column of the Bitmap property in the Object Inspector. When the Picture Editor comes up, you can select a bitmap for the menu item. The bitmap can be a single image or a bitmap strip (an image list). If you are using an image list, you should set the ImageIndex property to the index number of the image in the image list you want to display for this menu item.


NOTE: The menu item bitmaps don't display in the Menu Designer or on the form at design time. You will have to run the program to see the bitmaps.

Creating Submenus

There's nothing special or tricky about creating submenus. A submenu is a menu item that, when clicked, expands to show more menu choices. A submenu is denoted by a right-pointing arrow next to the menu item text. You can create a submenu by choosing Create Submenu from the Menu Designer context menu or by holding down the Ctrl key and pressing the right-arrow key. When you create a submenu, a blank menu item is placed to the right of the menu item. You can add menu items to the submenu just as you did when you created the main menu. You can create a submenu by inserting a menu template as well.

Adding Shortcuts

You can easily add a keyboard shortcut to a menu item by changing its ShortCut property in the Object Inspector. The Edit menu that you inserted earlier already had keyboard shortcuts built in. For example, the customary shortcut for Cut is Ctrl+X. If you look at the Edit menu, you will see Ctrl+X listed next to the Cut item (the shortcut was already assigned when you loaded the menu from a template).

Click on the Cut menu item and you will see that the ShortCut property says Ctrl+X. Click on the Value column next to the ShortCut property. On the Value column's right side you will see a drop-down button. Click on the button to display the list of available shortcuts. The list you see there contains just about any keyboard shortcut you need. To set the keyboard shortcut for a menu item, simply pick a shortcut from the list.

The standard shortcut for Select All is Ctrl+A, so let's add that as a shortcut for our Select All menu item:

1. Choose Edit | Select All from your menu in the Menu Designer.

2. Click on the ShortCut property in the Object Inspector.

3. Choose Ctrl+A from the list of available shortcuts. Now the Select All menu item shows Ctrl+A next to it.

That's all you have to do; Delphi takes care of it from there. The shortcuts function without you having to write any code.

Final Touches

Let's finish off your menu. First, you'll make the Word Wrap menu item on by default. This menu item is going to be used to turn word wrapping on or off. When word wrapping is on, the Word Wrap menu item will have a check mark next to it. When word wrapping is off, it will not have a check mark next to it. Click on the Word Wrap menu item and change the Checked property to True. A check mark shows up to indicate that the word wrap feature is on.

Another thing you need to do is to change the Name property on all of the menu items that you inserted from a template. They were given default names, and you want to change them to more meaningful names. Follow these steps:

1. Click on the Edit | Undo menu item. Change the Name property from Undo1 to EditUndo. Notice that you prepend the pop-up menu name, Edit, to the front of the menu item name and remove the 1 at the end.

2. You can use any naming convention you like, but be consistent. Repeat the process for the Cut, Copy, Paste, Find, and Replace menu items.

3. Now move to the Help menu and modify the Name property of the Contents item to HelpContents, and that of the About menu item to HelpAbout.

That about finishes your menu. Run through the menu to check it once more. If you find any errors, make the necessary changes. When you are satisfied that the menu is correct, click the close box to close the Menu Designer.


NOTE: You can access the Code Editor directly from the Menu Designer by double-clicking any menu item. When you double-click a menu item, the Code Editor displays the OnClick event for that item and you can start typing code. In this case, you are going to go back to the main form and do your code editing there.

Writing the Code

Okay, so you have all these menu items but no code to make them work. It's going to be a lot of work implementing all these, right? Actually, it's easy. Most of the required code is already part of the TMemo class. All you have to do is call the appropriate TMemo methods in the menu handlers. You'll have to do a few other things, but most of what you add is code you have seen before.

Adding Components to the Form

Before writing the code, you need to add the usual OpenDialog and SaveDialog components to the form:
1. Place an OpenDialog component on the form.

2. Change the Name property to OpenDialog.

3. Place a SaveDialog component on the form.

4. Change the Name property to SaveDialog.

5. Line up the MainMenu, OpenDialog, and SaveDialog icons on the form.

Writing the Menu Items' Code

Okay, that was easy enough. Now let's get on with writing the code for the menu items. You'll start with the File Exit menu item (hey, it's the easiest!). Be sure that the Menu Designer is closed so you don't confuse the Menu Designer with the Form Designer.

1. Choose File | Exit from the main menu. The Code Editor comes to the top and the FileExitClick event handler is displayed.

2. The cursor is positioned and ready to go. Type the following at the cursor (I always indent two spaces, by the way):

Close;




NOTE: In step 2 I had you use the Close function to close the form. That works fine here because this is the application's main form. But if you want to terminate the application from anywhere in the program, you should use this:

Application.Terminate;



This code ensures that the application is terminated regardless of which form is currently open.



That's it. I told you it was the easiest. Let's do one more; then I'm going to turn you loose to finish the rest on your own.

1. Choose Edit | Cut from the main menu. The Code Editor comes to the top and the EditCutClick event handler is displayed.

2. Type the following at the cursor:

Memo.CutToClipboard;

And that's all there is to that particular menu item. You might not fully realize it, but VCL does a lot for you behind the scenes. The whole idea of a framework is to take the burden of the low-level details off the programmer's back. Life is good.

Adding the Finishing Touches

One of the interesting aspects of a program like Delphi is that you rarely view your program as a whole. Delphi conveniently takes you to the section of code you need to work on to deal with a particular event, so you usually only see your program in small chunks. Listing 6.1 contains the main form unit for the ScratchPad program up to this point. The class declaration is entirely Delphi generated. Follow the examples you've just worked through to write code for each of the remaining menu items. Copy the code for each of the menu OnClick handlers from Listing 6.1. (The comment lines are there to explain to you what the code is doing. You don't have to include them when you type the code.)


NOTE: The event handlers appear in the source file in the order in which they were created. Don't be concerned if the order of the event handlers in your source file doesn't exactly match Listing 6.1. The order in which the functions appear makes no difference to the compiler.

LISTING 6.1. SPMAIN.PAS.

unit SPMain;
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,    ÂDialogs,
  Menus, StdCtrls, ComCtrls, ToolWin;
type
  TMainForm = class(TForm)
    StatusBar1: TStatusBar;
    ToolBar1: TToolBar;
    ToolButton1: TToolButton;
    ToolButton2: TToolButton;
    Memo: TMemo;
    MainMenu: TMainMenu;
    FileMenu: TMenuItem;
    FileNew: TMenuItem;
    FileOpen: TMenuItem;
    FileSave: TMenuItem;
    FileSaveAs: TMenuItem;
    N1: TMenuItem;
    FilePrint: TMenuItem;
    FilePrintSetup: TMenuItem;
    N2: TMenuItem;
    FileExit: TMenuItem;
    Edit1: TMenuItem;
    EditReplace: TMenuItem;
    EditFind: TMenuItem;

N4: TMENUITEM;

    EditPaste: TMenuItem;
    EditCopy: TMenuItem;
    EditCut: TMenuItem;
    N5: TMenuItem;
    EditUndo: TMenuItem;
    Help1: TMenuItem;
    HelpAbout: TMenuItem;
    HelpContents: TMenuItem;
    EditSelectAll: TMenuItem;
    N3: TMenuItem;
    EditWordWrap: TMenuItem;
    OpenDialog: TOpenDialog;
    SaveDialog: TSaveDialog;
    procedure FileExitClick(Sender: TObject);
    procedure EditCutClick(Sender: TObject);
    procedure EditCopyClick(Sender: TObject);
    procedure EditPasteClick(Sender: TObject);
    procedure FileNewClick(Sender: TObject);
    procedure FileSaveClick(Sender: TObject);
    procedure FileOpenClick(Sender: TObject);
    procedure FileSaveAsClick(Sender: TObject);
    procedure EditUndoClick(Sender: TObject);
    procedure EditSelectAllClick(Sender: TObject);
    procedure EditWordWrapClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  MainForm: TMainForm;
implementation
{$R *.DFM}
procedure TMainForm.FileExitClick(Sender: TObject);
begin
  { All done. Close the form. }
  Close;
end;
procedure TMainForm.EditCutClick(Sender: TObject);
begin
  { Call TMemo.CutToClipboard. }
  Memo.CutToClipboard;
end;
procedure TMainForm.EditCopyClick(Sender: TObject);
begin
  { Call TMemo.CopyToClipboard. }
  Memo.CopyToClipboard;
end;
procedure TMainForm.EditPasteClick(Sender: TObject);
begin
  { Call TMemo.PasteFromClipboard. }
  Memo.PasteFromClipboard;
end;
procedure TMainForm.FileNewClick(Sender: TObject);
var
  Res : Integer;
begin
  { Open a file. First check to see if the }
  { current file needs to be saved. }
  if Memo.Modified then begin
    { Display a message box. }
    Res := Application.MessageBox(
      `The current file has changed. Save changes?',
      `ScratchPad Message', MB_YESNOCANCEL);
    { If Yes was clicked then save the current file. }
     if Res = IDYES then
       FileSaveClick(Sender);
    { If No was clicked then do nothing. }
    if Res = IDCANCEL then
      Exit;
  end;
  { Delete the strings in the memo, if any. }
  if Memo.Lines.Count > 0 then
    Memo.Clear;
  { Set the FileName property of the Save Dialog to a }
  { blank string. This lets us know that the file has }
  { not yet been saved. }
  SaveDialog.FileName := `';
end;
procedure TMainForm.FileOpenClick(Sender: TObject);
var
  Res : Integer;
begin
  { Open a file. First check to see if the current file needs }
  { to be saved. Same logic as in FileNewClick above. }
  if Memo.Modified then begin
    Res := Application.MessageBox(

`THE CURRENT FILE HAS CHANGED. SAVE CHANGES?',

      `ScratchPad Message', MB_YESNOCANCEL);
    if Res = IDYES then
      FileSaveClick(Sender);
    if Res = IDCANCEL then
      Exit;
  end;
  { Execute the File Open dialog. If OK was pressed then }
  { open the file using the LoadFromFile method. First   }
  { clear the FileName property. }
  OpenDialog.FileName := `';
  if OpenDialog.Execute then begin
    if Memo.Lines.Count > 0 then
      Memo.Clear;
    Memo.Lines.LoadFromFile(OpenDialog.FileName);
    SaveDialog.FileName := OpenDialog.FileName;
  end;
end;
procedure TMainForm.FileSaveClick(Sender: TObject);
begin
  { If a filename has already been provided then there is }
  { no need to bring up the File Save dialog. Just save the }
  { file using SaveToFile. }
  if SaveDialog.FileName <> `' then begin
    Memo.Lines.SaveToFile(SaveDialog.FileName);
    { Set Modified to False since we've just saved. }
    Memo.Modified := False;
  { If no filename was set then do a SaveAs. }
  end else FileSaveAsClick(Sender);
end;
procedure TMainForm.FileSaveAsClick(Sender: TObject);
begin
  { Display the File Save dialog to save the file. }
  { Set Modified to False since we just saved.     }
  SaveDialog.Title := `Save As';
  if SaveDialog.Execute then begin
    Memo.Lines.SaveToFile(SaveDialog.FileName);
    Memo.Modified := False;
  end;
end;
procedure TMainForm.EditUndoClick(Sender: TObject);
begin
  { TMemo doesn't have an Undo method so we have to send }
  { a Windows WM_UNDO message to the memo component.     }
  SendMessage(Memo.Handle, WM_UNDO, 0, 0);
end;
procedure TMainForm.EditSelectAllClick(Sender: TObject);
begin
  { Just call TMemo.SelectAll. }
  Memo.SelectAll;
end;
procedure TMainForm.EditWordWrapClick(Sender: TObject);
begin
  { Toggle the TMemo.WordWrap property. Set the Checked }
  { property of the menu item to the same value as WordWrap. }
  Memo.WordWrap := not Memo.WordWrap;
  EditWordWrap.Checked := Memo.WordWrap;
  { If WordWrap is on then we only need the vertical scroll }
  { bar. If it's off, then we need both scroll bars.        }
  if Memo.WordWrap then
    Memo.ScrollBars := ssVertical
  else
    Memo.ScrollBars := ssBoth;
end;

end.

And Now, the Moment You've All Been Waiting For...

After you create the event handlers for the menu items, you are ready to run the program. Click the Run button and the program should compile and run. If you get compiler errors, carefully compare your source code with the code in Listing 6.1. Make any changes and click the Run button again. You might have to go through this process a few times before the program will compile and run. Eventually, though, it will run (I promise!).

When the program runs, you will find a program that, although not yet 100 percent feature-complete, acts a lot like Windows Notepad. Even though you have a few things to add before you're finished, you have a fairly good start--especially when you consider the actual time involved up to this point. Figure 6.22 shows the ScratchPad program running.

FIGURE 6.22. The ScratchPad program in action.

Pop-Up Menus (Context Menus)

I am not quite done with the discussion of menus. In Delphi, you can create pop-up menus as easily as you can a main menu. A nice feature of Delphi is that you can assign a particular pop-up menu to a component via the component's PopupMenu property. When the cursor is placed over the component and the secondary mouse button is clicked, that pop-up will automatically be displayed. Writing event handlers for pop-up menus is exactly the same as writing event handlers for main menus.

A common feature of text-editing programs is to place the Cut, Copy, and Paste operations on a context menu. You'll add that capability to ScratchPad. To create the pop-up, you'll cheat and copy part of the main menu. Follow these steps:

1. Choose a PopupMenu component from the Component palette and place it on the form.
2. Change the Name property to MemoPopup.

3. Double-click the PopupMenu icon to run the Menu Designer.

4. Click the secondary mouse button to bring up the Menu Designer context menu. Choose Select Menu from the context menu. A dialog box is displayed that shows the menus available for your application. Choose MainMenu and click OK.

5. Click on the Edit menu. Click on the Cut menu item, hold down the Shift key, and click on the Paste menu item. Cut, Copy, and Paste are all now highlighted.

6. To copy the selected items to the Clipboard, choose Edit | Copy from the Delphi main menu (don't choose Edit | Copy from the menu you are creating in the Menu Designer) or press Ctrl+C.

7. Again, choose Select Menu from the Menu Designer context menu. This time, choose MemoPopup and click OK. The Menu Designer shows a blank pop-up menu.

8. Choose Edit | Paste from the main menu or type Ctrl+V on the keyboard. The Cut, Copy, and Paste menu items are inserted into the pop-up.

Okay, just a few more things and you'll be done. You need to change the Name property for the new menu items:

1. For the Cut menu item, change the Name property to PopupCut.

2. For the Copy menu item, change the Name property to PopupCopy.

3. For the Paste menu item, change the Name property to PopupPaste.

The final step is to write event handlers for the pop-up menu items. Hmmm...you have already written code for the main menu's Cut, Copy, and Paste items. It would be a shame to duplicate that effort (even if it is just a single line in each case). Could you just use the same event handlers that you created earlier? Sure you can. Just follow these steps:

1. Click on the Cut popup menu item.

2. Click on the Events tab in the Object Inspector.

3. Click the drop-down arrow button in the Value column next to the OnClick event (the only event in the list). A list of event handlers created so far is displayed.

4. Choose the EditCutClick event handler from the list. Now, when the Cut pop-up menu item is clicked, the Edit | Cut handler will be called. No code duplication is required.

5. Repeat steps 1 through 4 for the Copy and Paste items on the pop-up menu. When you are done, close the Menu Designer.

6. On the main form, click on the Memo component. Change the PopupMenu property to MemoPopup (by choosing it from the list).

You can attach just about any event to any event handler by using this method. Now run the program again to test the new context menu. Of course it works!

Creating and Saving Menu Templates

Delphi provides you with several menu templates that you can insert into your main menus and pop-ups. You can also create and save your own templates for future use in your programs. First, start the Menu Designer and create the menu.


NOTE: When creating menus to use as templates, you first must have a main menu or a pop-up menu on a form in order to start the Menu Designer. You can use a temporary, blank form if you want. Start with a blank form, place a MainMenu component on it, and double-click the menu component's icon to start the Menu Designer. After you are done creating menu templates, discard the blank form without saving.

When you have created the menu, choose Save As Template from the Menu Designer's context menu. The Save Template dialog box is displayed. Give the menu a meaningful name and click the OK button, and the menu is saved as a template. To insert the menu, choose Insert From Template from the Menu Designer's context menu just as you did earlier. Any menus you have created will show up along with Delphi's prebuilt templates.

To remove a template that you previously added, choose Delete Templates from the Menu Designer's context menu. The Delete Templates dialog box is displayed, and you can choose the templates you want to delete. When you click the OK button, the selected menu templates will be deleted. Press Cancel to close the dialog box without deleting any templates.

Summary

Congratulations! You have just covered the bulk of the Delphi visual programming features. I hope it was enjoyable as well as educational. The Form Designer is a powerful tool that enables you to do as much programming as possible in a visual manner. If you haven't had to create windows and dialogs using traditional Windows programming tools, you might not fully appreciate that advantage. Trust me, it's significant. The Menu Designer is also a powerful tool, particularly because of the capability to import menus, which makes menu creation easy and actually fun with Delphi. The Menu Designer also makes updating existing menus a snap.

Workshop

The Workshop contains quiz questions to help you solidify your understanding of the material covered and exercises to provide you with experience in using what you have learned. You can find the answers to the quiz questions in Appendix A, "Answers to the Quiz Questions."

Q&A

Q I'm using the Alignment palette a lot, and every time I switch from the Code Editor back to the Form Designer, the Alignment palette gets lost somewhere. Is there anything I can do about that?

A Locate the Alignment palette (it's there somewhere!) and click your secondary mouse button to bring up the Alignment palette's context menu. Choose the Stay on Top item from the context menu. Now the Alignment palette will always be on top where you can find it.

Q I am trying to select a group of components on a panel by dragging the selection rectangle around them, but I keep moving the panel. What's wrong?

A You need to hold down the Ctrl key while dragging when you are selecting components contained on a panel.

Q I've moved my components around my form several times and now the tab order is erratic. What can I do to fix that?

A Choose Tab Order from the Form Designer's context menu. Arrange the tab order the way you want it. When you click OK, the new tab order will be implemented.

Q The menu templates provided are nice, but they have so much stuff on them that I don't need. What can I do about that?

A You can do two things. First, you can import a menu and then simply delete the items you don't want. Using the click, Shift+click method you can get rid of unwanted menu items in just a few seconds. Deleting items from a menu inserted from a template has no adverse effects. The second thing you can do is to follow the click, Shift+click method and then, when you have the menu just the way you want it, you can save it as a new template. That way you can keep the original Delphi-supplied template and have your customized template as well.

Q Can I save my own menus as templates?

A Yes. First create the menu and then choose Save As Template from the Menu Designer context menu. Give the template a name, click OK, and the template is saved. Now all you have to do to reuse the menu later is insert the menu using the Insert From Template feature.

Quiz

1. When do you use Ctrl+drag in selecting components?

2. What significance does the first component selected have when aligning a group of components?

3. What is the quickest method to select a group of components?

4. How can you make a group of components all have the width of the group's widest component?

5. What happens when you double-click a component on a form?

6. What does the Align property's alClient option do?

7. What does the ellipsis following a menu item mean?

8. What two ways can you move a menu item?

9. How do you add menu accelerators to menu items?

10. How do you initially disable a menu item?

Exercises

1. Place five edit components on a form and arrange them so that they are stacked vertically with their left edges aligned.

2. Turn the Snap to Grid option off (choose Tools | Environment Options from the main menu). Place five controls of your choice on a form and align their right edges.

3. Place a ListBox component on a blank form and modify it so that it always occupies the form's entire client area.

4. Add an About box to the ScratchPad program. Use the Alignment palette to quickly align the text labels.

5. Add an Undo item and a menu separator to the context menu for the ScratchPad program.

6. Start a new application. Place six edit components on a form in random fashion. Now arrange the tab order so that tabbing proceeds from top to bottom. Run the program to test the tabbing order.

7. Add the Ctrl+S keyboard shortcut to the File | Save menu item in the ScratchPad program.

8. Open the Picture Viewer project you created on Day 4. Remove all unused menu items.


Previous chapterNext chapterContents

© Copyright, Macmillan Computer Publishing. All rights reserved.