home   Java Script   MS Access   Perl   HTML   Delphi   C ++   Visual Basic   Java   CGIPerl   MS Excel   Front Page 98   Windows 98   Ms Word   Builder   PHP   Assembler     Link to us   Links    

Teach Yourself Borland Delphi 4 in 21 Days

Previous chapterNext chapterContents

- 13 -

Beyond the Basics

Today you learn ways to turn a good Windows application into a great Windows application. Specifically, I discuss the following:

This discussion continues tomorrow as you look at implementing advanced Windows programming features in your Delphi applications.

Creating Window Decorations

No, I'm not talking about pretty lights around the front window of your house. What I am talking about are features such as toolbars and status bars. These features are often called window decorations. This section deals with these types of decorations and how to implement them in your application.


A toolbar (also called a control bar or a speedbar) is almost standard equipment for Windows programs today. Users expect certain amenities, and a toolbar is one of them. A top quality toolbar should have the following features and capabilities:

Some of the features in this list are optional features that not every toolbar needs to have. With Delphi, implementing these toolbar features is easy to accomplish. A little later in the chapter I talk about command enabling in the section "Adding Functionality with Command Enabling." I'll save discussion of command enabling for toolbar buttons for that time.

NOTE: It is considered good practice to place on the toolbar only buttons that have corresponding menu items. The toolbar is an alternative to using the menu. It should not contain items found nowhere else in the program.

On Day 8, "Creating Applications in Delphi," I said that the easiest way to construct a toolbar is to use the Application Wizard. Even if you already have a partially written application, you can still use the Application Wizard to create a toolbar. Just generate an application with the Application Wizard, copy the panel with the toolbar to the Clipboard, reopen your original application (don't bother saving the Application Wizard application), and paste the toolbar into your application from the Clipboard. Slick and easy.

However, the Application Wizard doesn't give you everything you could possibly need in a toolbar. Most notably, the Application Wizard uses the old method of creating a toolbar--with a panel and speed buttons. The preferred way of creating a toolbar is to use the ToolBar and CoolBar components (found on the Win32 tab of the Component palette). Let's take a look at those components next.

NOTE: The CoolBar and ToolBar components require version 4.72.2106.4 or later of COMCTL32.DLL, which should have been installed as part of the Delphi installation. If you don't have the latest version of this DLL, you can find it at Microsoft's Web site (http://www.microsoft.com). When you deploy your applications using these components, you should install COMCTL32.DLL version 4.70 or later. Be sure you are using a good installation program so that you don't overwrite a new version of this DLL when you install your application.

The CoolBar Component

The CoolBar component is an encapsulation of the Win32 cool bar (sometimes called a rebar). This component is a specialized container control. Most of the time the CoolBar is used as a container for toolbars, but its use isn't limited strictly to toolbars.

Cool Bar Bands

A cool bar has bands that can be moved and resized at runtime. The bands show a sizing grip on the left side, giving the user a visual cue that the band can be moved or sized. Cool bar bands are represented by the TCoolBand class. A cool bar band can contain only one component. Usually that component is a toolbar, but it can be a combo box or any other component. Let's do an exercise to better understand how the CoolBar component works:

1. Start with a new application and drop a CoolBar component on the form.

2. Drop a ComboBox component on the cool bar. Delphi creates a new band to hold the combo box. Notice that the combo box fills the width of the cool bar.

3. Drop another ComboBox component on the cool bar. Another band is created and is placed below the first band.

4. Place your mouse cursor between the sizing grip and the combo box on the second band. The cursor will change to a pointing hand, indicating that you can move the band. (You can also use the sizing grip to drag the band.) Drag the band up into the band above it. As you do, the first band will shrink to make room for the band you are dragging. Drop the band near the middle of the cool bar. You can now use the sizing grips to resize either band.

5. Place a Panel component on the cool bar. A new band is created to hold the panel.

6. Select the cool bar and change its AutoSize property to True.

7. Place a Memo component on the form below the cool bar. Set its Align property to alClient.

Now your form looks like Figure 13.1.

FIGURE 13.1. The form with a cool bar and three bands.

Now run the program. Experiment with the cool bar bands. Drag them up or down or resize them. Notice that as you drag the bands up or down, the cool bar resizes as needed and the memo always fills the remaining client area.

Cool bar bands are accessed through the Bands property. This property is a TCoolBands, which is a list of TCoolBand components. If you want to hide the second band, you can do this:

CoolBar.Bands[1].Visible := False;

You can add bands in two ways. As you have already seen, you can create a band by dropping any component on the cool bar, but you can also use the Bands Editor. To invoke the Bands Editor, double-click the cool bar or click the ellipsis button next to the Bands property in the Object Inspector. You add bands by clicking the Add button; you delete bands by clicking the Delete button. The Move Up and Move Down buttons enable you to change the order of the bands.

NOTE: If the AutoSize property is set to True, you will have to turn it off temporarily if you want to add new bands by dropping components on the cool bar. Set the AutoSize property to False, make the cool bar higher, drop a component on the cool bar, and set the AutoSize property to True again.

NOTE: When you select a band in the Bands Editor, the Object Inspector displays the band's properties. Figure 13.2 shows the Bands Editor and the Object Inspector when a band is selected.

FIGURE 13.2. The cool bar Bands Editor.

The Bitmap property enables you to set a background bitmap for a band. To select an image that will appear to the left of the band, you use ImageIndex. ImageIndex requires the ImageList property of the cool bar to be set to a valid TImageList. You can set a band's minimum height and width through the MinHeight and MinWidth properties. To make a band immovable, set the FixedSize property to True.

Other CoolBar Properties

A cool bar can be either vertical or horizontal. By default the Align property is set to alTop. To make a vertical cool bar, change the Align property to alRight or alLeft. Some components, when placed on a cool bar, automatically orient themselves based on whether the cool bar is vertical or horizontal. Another way to change the orientation of the cool bar is by setting the Vertical property.

The Bitmap property enables you to set a background bitmap for the cool bar. The bitmap you choose will be tiled to fill the cool bar's background. Note that this sets the background bitmap for the cool bar itself, not for any individual bands on the cool bar (as discussed in the previous section). You use the ImageList property to set the image list that the bands will use to display an image to the left of any band that has its ImageIndex property set.

The AutoSize property determines whether the cool bar will resize itself when bands are moved. You saw the effect of the AutoSize property in the preceding exercise.

NOTE: Check out the TControlBar component on the Additional tab of the Component palette. TControlBar is a native VCL component that works very much like a cool bar. This component does not rely on COMCTL32.DLL as does TCoolBar, so it is less susceptible to the whims of Microsoft.

The ToolBar Component

The ToolBar component encapsulates the Win32 toolbar control. The toolbar will automatically arrange and size the controls placed on the toolbar so that they all have a consistent height. You can use the ToolBar component with or without a cool bar. If you have only a single toolbar, use the toolbar without a cool bar. If you have multiple toolbars that you want to enable the user to move, place two or more toolbars on a cool bar.

Creating a toolbar and adding buttons to it is very easy. If your toolbar buttons will have glyphs (and most do), you have to use an ImageList component for the glyphs. To illustrate how to build a toolbar with the ToolBar component, let's again go back to the ScratchPad program. You'll tear it apart and put it back together.

Removing the Old Toolbar

If you recall, the toolbar you created for ScratchPad originally was just a placeholder. The first thing you need to do is get rid of the old toolbar by performing these steps:

1. Click the Memo component and change its Align property to alNone. Drag down the top of the Memo to make room for the new toolbar.

2. Click the toolbar component and delete it.

Adding a New Toolbar

Now you can start adding components back again. The first thing to do is add a cool bar and a toolbar. You don't really need a cool bar at this stage because you have only one toolbar, but you might want to add another toolbar later, so it's best to plan ahead. Perform these steps:

1. Drop a CoolBar component on the form. It automatically aligns itself to the top of the form. Change its Name property to CoolBar.

2. Drop a ToolBar component on the cool bar. Change its Name property to MainToolBar.

3. Double-click the EdgeBorders property in the Object Inspector to show all the edge border items. Change the ebTop style to False (all EdgeBorders styles should now be False).

4. Change the Flat property to True. This gives the toolbar buttons a flat appearance until the cursor passes over them.

5. Click the cool bar and change the AutoSize property to True. The cool bar sizes itself to the size of the toolbar.

6. Click the Memo component and change its Align property back to alClient.

Adding Buttons to the Toolbar

Now you begin adding buttons to the toolbar; you will add several buttons and a few spacers. At first the buttons won't have glyphs on them, but you'll take care of that later. For now, follow these steps:

1. Right-click the toolbar and choose New Button. A button is placed on the toolbar. Change the button's Name property to FileNewBtn. Set the Hint property to New|Create A New File and the ShowHint property to True. (Remember when you wrote the hint code on Day 8? That code is still in the program, so the new hints will work immediately.)

2. Right-click on the toolbar and again choose New Button. A second button is placed on the toolbar to the right of the first button. Change its Name property to FileOpenBtn. Set the Hint property to Open|Open An Existing File and the ShowHint property to True.

3. Add another button. Change this button's Name property to FileSaveBtn. Set the Hint property to Save|Save A File and the ShowHint property to True.

TIP: Buttons and spacers added to the toolbar always appear to the right of the toolbar's last control. You can't insert a button at a specific location in the toolbar, but after a button or spacer is added, you can drag it to a different location on the toolbar. The existing buttons will make room for the new button.

That finishes the first set of buttons (except for the glyphs). You are about to add a second set of buttons, but before you do, there needs to be a little separation between the first set of buttons and the second. Back to work:

1. Right-click on the toolbar again, but this time choose New Separator. A separator is added to the toolbar.

2. Add another button. This time change the Name property to EditCutBtn and the Hint property to Cut|Cut To Clipboard.

3. Add buttons for Copy and Paste. Change their Name and Hint properties as appropriate.

4. Add another separator.

5. Add a button called HelpAboutBtn. Change its Hint property to About|About ScratchPad.

6. Select the Cut, Copy, Paste, and Help buttons (use Shift+-Click to select each button). Change the ShowHint property to True. It will be changed for all buttons selected.

Your form now looks like the one shown in Figure 13.3.

Figure 13.3. The ScratchPad main form after adding a toolbar.

Making the Toolbar Buttons Functional

You now have a good start on the toolbar, but the toolbar buttons don't do anything because you haven't assigned any event handlers to their OnClick events. Let's do that next.

1. Click the FileNewBtn (the first button) and select the Events page in the Object Inspector. Click the drop-down arrow next to the OnClick event and choose FileNewClick. The button is now hooked up to the FileNewClick event handler.

2. Repeat step 1 for each remaining button, being careful to select the appropriate OnClick handler for each button (FileOpenClick, FileSaveClick, EditCutClick, and so on).

3. If you haven't yet created an About Box for ScratchPad, create one. When you are done, create an event handler for the Help|About menu item. Hook the OnClick event of the HelpAboutBtn to the event handler for the Help|About menu item.

Adding Bitmaps to the Toolbar Buttons

Obviously this toolbar is missing something. You need to add glyphs to the toolbar buttons. To do so, you must add an ImageList component to the form by following these steps:

1. Place an ImageList component on the form. (You find it on the Win32 tab of the Component palette.) Change the Name property to ImageList.

2. Right-click the ImageList component's icon on your form and choose ImageList Editor. The ImageList Editor is displayed. (You can also double-click the ImageList icon on your form to display the ImageList Editor.)

3. Click the Add button. Navigate to the Common Files\Borland Shared\Images\ Buttons directory. Select the FILENEW.BMP file and click Open.

A message box appears and asks whether you want to separate the bitmap into two images. What is happening here is that the image list's Width and Height properties are both set to 16. The bitmap you have selected is wider than 16 pixels, so it has to be split into two images or shrunk to fit. If you recall, the button bitmaps that come with Delphi are a single bitmap with two images. The first image is the normal button bitmap, and the second image is for the disabled button. You will have the ImageList Editor split the bitmap into two images, and then you will delete the second part of the image.

4. Click Yes to have the ImageList Editor split the bitmap into two images. The ImageList Editor now shows two images. You need only the first of these images, so click on the second image (the disabled button image) and click the Delete button.

5. Click the Add button again. This time choose the FILEOPEN.BMP file. Click Yes again when prompted to split the bitmap into two images. Click on the disabled image for this bitmap and delete it. Figure 13.4 shows the image editor as it looks just before deleting the second image.

FIGURE 13.4. The ImageList Editor after adding three images.

6. Repeat step 5 for each remaining button (File Save, Cut, Copy, Paste, and About). Use any bitmaps you like, but make certain you delete the extra bitmap each time you add an image to the list. Also make sure that the images in the ImageList editor follow the order of the buttons on the toolbar. When you are done, you will have seven images in the image list, numbering from 0 to 6.

7. Click OK to close the ImageList Editor.

TIP: You can select multiple images in the ImageList Editor's Add Images dialog box and add them all to the image list at one time.

Now you are ready to hook the image list to the toolbar. Click on the toolbar. Locate the Images property in the Object Inspector and choose ImageList from the drop-down list. If you did everything right, your buttons now have glyphs. You probably didn't notice, but each time you added a toolbar button, Delphi automatically incremented the ImageIndex property for the button. Because you created the buttons and images in the same order, the glyphs on the buttons should be correct. If a button is wrong, you can either change the button's ImageIndex property or go back to the ImageList Editor and change the order of the images in the image list.

TIP: To rearrange the images in an image list, drag them to a new position in the ImageList Editor.

Disabled Button Glyphs

Right now you have glyphs only for the buttons in the enabled state. You also need glyphs that will be displayed when the buttons are disabled. You aren't disabling the toolbar buttons yet, but you will be before the day is done. There are two ways to implement the disabled button glyphs:

Certainly the easier of these two methods is to let the toolbar create the disabled state buttons automatically. Most of the time this is sufficient. Sometimes, however, the algorithm for creating the disabled buttons glyphs doesn't work well. (The glyphs end up losing definition and don't look quite right.) This happens with buttons that don't have enough contrasting colors. In that case, you can create a second image list that contains the disabled button glyphs. Set the DisabledImages property of the toolbar to the image list containing the disabled glyphs, and the rest is automatic. For ScratchPad you're going to go with the automatic disabling of toolbar buttons, so nothing further is required.

Poor old ScratchPad is back together again. This is a good time to save the project. After saving the project, click the Run button and give the program a workout. Click the buttons and see whether they do what they are supposed to do. If all went well, you have a working program again. If your program won't compile, review the steps and try to fix the problem. If all else fails, you can refer to the ScratchPad project of the book's code, available at http://www.mcp.com/info (Day 13).

Toolbar Tips and Hints

I covered nearly everything there is to be said about tooltips and hints in the discussion of components on Day 7, "VCL Components"; again on Day 8, "Creating Applications in Delphi," when adding hint text support for the ScratchPad program; and again today when rebuilding the toolbar.

There is one issue I didn't talk about, and that is changing the tooltip properties. The TApplication class has four properties that control how the tooltips behave. Table 13.1 lists these properties and their descriptions.


Property Description
Hintcolor Sets the background color of the Tooltip window. Default: CLINFOBK
HintHidePause Controls how long to wait (in milliseconds) before hiding the tooltip if the mouse cursor remains stationary over the component. Default: 2500 milliseconds
HintPause Controls the interval between the time the mouse cursor is paused over a component and the time the tooltip appears (in milliseconds). Default: 500 milliseconds
HintShortPause Controls how long to wait before showing tooltips after they have already been shown--for example, when the user is roaming over a group of toolbar buttons. Default: 50 milliseconds

The default values for these properties are sufficient for most applications. Still, if you need to change any hint properties, you have that option.


Adding Other Controls to Toolbars

Because the ToolBar component is so versatile, nothing special needs to be done to add other types of controls to your toolbar. The most common type of control to add to a toolbar is a combo box. You can use a toolbar combo box to select a font, a configuration option, a zoom setting. . . the possibilities are endless.

To add a component to the toolbar, select the component from the Component palette and drop it on the toolbar. The toolbar will take care of aligning the component. Add spacers as necessary to separate components visually. When the component is on the toolbar, you deal with it just as you would a component on a form. I could try to complicate this for you, but the truth is, it's just that simple. If you've never tried to implement a combo box on a toolbar using the Windows API, you cannot appreciate how much work Delphi saves you. Take my word for it--it's significant.

Toolbars come in many shapes and sizes, and Delphi makes creating and implementing toolbars very easy. With Delphi, you no longer have the excuse, "That's too hard!" In fact, you might even enjoy creating toolbars with Delphi.

Dockable Toolbars

Dockable toolbars are common in many Windows programs. Dockable toolbars are a paradox of sorts. On the one hand, they are a cool feature and most power users expect a good application to have dockable toolbars. On the other hand, I doubt anyone actually uses the docking capability of most dockable toolbars. Still, dockable toolbars are easy enough to implement in Delphi, so you might as well provide them.

NOTE: The docking features discussed in this section apply to any windowed control, not just to toolbars.

Creating a Dockable Toolbar

Making a toolbar dockable requires two steps:

After you set these two properties, you can drag your toolbar around the screen. Dragging the toolbar around the screen doesn't get you very much, though. In order for dockable toolbars to make sense, you have to have a target for the drop part of the drag-and-drop equation.

Dock Sites

A dockable toolbar needs to have a place to dock. As Roger Waters said, "Any fool knows a dog needs a home." Home for a dockable toolbar is a dock site. A dock site is any windowed component that has its DockSite property set to True. Components that are typically used as dock sites are TCoolBar, TControlBar, TPageScroller, TPanel, and TPageControl. There are other controls that have a DockSite property, but those controls are less likely to be used as dock sites.

An exercise helps illustrate the use of dock sites. Follow these steps:

1. Drop a CoolBar component on a blank form. Set its DockSite property to True.

2. Drop a ToolBar on the CoolBar. Set the toolbar's DragKind property to dkDock and its DragMode property to dmAutomatic. Create a few buttons on the toolbar so that you can better see the toolbar.

3. Place a second CoolBar on the form. Change its Align property to alBottom and its DockSite property to True.

4. Place a third CoolBar on the form. Change its Align property to alLeft and its DockSite property to True. Size the CoolBar so that its width is 40 pixels or so.

Now run the program. Drag the toolbar from dock site to dock site. Notice how the toolbar changes its orientation when you drag it to the cool bar on the left side of the form.

Let's experiment some more. Set each of the CoolBar components' AutoSize properties to True. This will cause each CoolBar to change its size based on the controls it contains. Now run the program again and move the toolbar to the individual dock sites. Notice that each cool bar is nearly invisible until the toolbar is docked to the site. Then the cool bar expands to contain the toolbar.

Floating Toolbars

A toolbar can be made into a floating toolbox by simply dragging the toolbar off its dock site and dropping it anywhere (anywhere other than another dock site, that is). The toolbar becomes a floating window. You can specify the type of window that should host the floating dock site by setting the FloatingDockSiteClass property to the name of the class you want to act as the parent to the floating toolbar. For example, suppose that you design a form that has all the characteristics you want for a custom floating toolbox, and that the form is called MyToolBox. In that case, you could cause this form to be the host for a floating toolbar with this code:

ToolBar.FloatingDockSiteClass := TMyToolBox;

When the toolbar is undocked and the mouse button released, Delphi will automatically create an instance of the TMyToolBox class and place the toolbar in the form for that class. To dock the floating toolbox again, simply drop it on any dock site. To make a dock site accept a floating toolbox, you must respond to the OnDockOver and OnDockDrop events for the dock site. In the OnDockDrop event handler, call the ManualDock method of the toolbar to cause the toolbar to dock.

Status Bars

A status bar is another feature that makes an application more marketable. Not all applications benefit from a status bar, but many can. The VCL StatusBar component, which encapsulates the Win32 status bar control, makes creating status bars a breeze. First, take a quick look at the major properties of the StatusBar component, listed in Table 13.2.


Property Description
AutoHint Automatically displays hints in the status bar when the mouse cursor passes over any component whose Hint property has been set.
Panels For status bars with multiple panels. This property defines the individual panels.
SimplePanel Determines whether the status bar shows a simple panel or multiple panels.
SimpleText The text for the status bar's simple panel.
Property Description
SizeGrip Determines whether the status bar displays the sizing grip in the lower-right corner. The sizing grip provides an area that the user can drag to size the window. The absence of the sizing grip doesn't prevent the window from being sized, but the presence of the size grip makes sizing a window easier.
UseSystemFont Always uses the current system font, overriding the settings of the Font property. This is particularly useful for users who use Plus pack themes.

As you can see from this table, a status bar can be a simple status bar or have multiple panels. Let's discuss this choice next.

Simple or Complex?

A status bar can be either a simple status bar or a complex status bar. A simple status bar has a single panel that occupies the entire status bar. If you want a simple status bar, set the SimplePanel property to True. The SimplePanel property acts as a toggle. You can switch between a simple and a complex status bar at runtime by setting SimplePanel to True or False, accordingly.

A complex status bar is one with multiple panels. If you elect to use a complex status bar, you can use the StatusBar Panels Editor to set up the panels you want to see on your status bar. To invoke the StatusBar Panels Editor, double-click on the Value column of the Panels property. To add a panel, click the Add New button on the StatusBar Panels Editor. To delete a panel, click the Delete Selected button. To edit a panel, select the panel and then make changes to the panel's properties in the Object Inspector. Figure 13.5 shows the StatusBar Panels Editor and Object Inspector when editing panels.

FIGURE 13.5. The StatusBar Panels Editor.

NOTE: The individual panels in a complex status bar are instances of the TStatusPanel class.

Most of the properties are self-explanatory, but a couple require further note. The Text property contains the text that will be displayed in the panel. You can also use the Text property at runtime to change the text in the panel. Setting the status bar text is discussed a little later; you don't need to supply text for the panel at design time if you are going to change the text at runtime.

You can set the Style property to either psText or psOwnerDraw. If the Style is set to psText (the default), the panel behaves as you would expect. The text is aligned in the panel according to the value of the Alignment property. If the Style is set to psOwnerDraw, it is up to you to draw any text or image that is displayed in the panel. Owner drawing of panel items is discussed later in the section "Owner-Drawn Status Bar Panels."

The Width, Bevel, and Alignment properties for the panel are straightforward. Experiment with these properties to see how they affect your status bar's appearance.

NOTE: In the Form Designer you immediately see the results of changes made to the status bar via the StatusBar Panels Editor. Position the StatusBar Panels Editor so that you can view the status bar as you work with the StatusBar Panels Editor. Each time you make a change, it will be reflected in the Form Designer.

When you are done adding panels to the status bar, close the StatusBar Panels Editor and return to the Form Designer.

NOTE: When you modify the Panels property of a StatusBar component, the Form Designer automatically sets the SimplePanel property to False. The assumption is that if you are using multiple panels, you don't want to have a simple status bar.

Changing Text in the Status Bar

There are two ways to change text in a status bar:

Manually changing the text in the status bar is simple, particularly if you have a simple status bar. When the SimplePanel property is True, you can set the SimpleText property to the text you want displayed in the status bar:

StatusBar.SimpleText := `This shows up in the status bar.';

In the case of complex status bars, changing the text is only slightly more complicated. If you want to change the text for the first panel of a complex status bar, you would use something like this:

StatusBar.Panels[0].Text := `Status Bar Text';

The Panels property of the StatusBar component has a property called Items that is an array of panels in the status bar. Setting the Text property for an element in the Items array changes the text for that panel (because Items is the default array property for the Panels object, you don't have to specifically reference Items). As you can see, the array is 0-based. The first panel in the status bar is array element 0.

Automatic status bar hint text doesn't require much in the way of explanation. All you have to do is set the AutoHint property to True. The rest is, as the property name implies, automatic.

NOTE: You can still modify the status bar's text manually even when using AutoHint. There's nothing to stop you from changing the text manually, but remember that the text will be replaced the next time the mouse passes over a component with hint text.

Owner-Drawn Status Bar Panels

Earlier I said that a panel's Style property can be either psText or psOwnerDraw. When you set a panel's style to psOwnerDraw, you must take the responsibility of drawing anything in the panel that needs to be displayed there. It is unlikely that you are going to go to the trouble of using an owner-drawn panel just to display text. Usually it means you are going to display some sort of icon or bitmap in the status bar. Regardless of what is being drawn on the panel, the steps are the same:

1. Set the panel's Style property to psOwnerDraw (usually via the StatusBar Panels Editor).
2. Respond to the OnDrawPanel event.

Obviously, the real work here is going to take place in the event handler for the OnDrawPanel event. The declaration for the OnDrawPanel event handler looks like this:

procedure TForm1.StatusBar1DrawPanel(StatusBar: TStatusBar;
  Panel: TStatusPanel; const Rect: TRect);

The StatusBar parameter is a pointer to the status bar. Usually you have a pointer to the status bar anyway (the Name property of the StatusBar component), so this parameter is not all that useful unless you are using multiple owner-drawn status bars. The Panel property is a pointer to the particular panel that currently needs drawing. You can use this parameter to determine which panel needs drawing if you have more than one owner-drawn panel in your status bar. The Rect parameter contains the panel's size and position. The Rect parameter is important because it tells you the exact dimensions of the drawing area.

The OnDrawPanel event handler is called once for each panel that has its Style property set to psOwnerDraw. If you have only one panel to draw, you don't have to worry about much except the Rect parameter. If you have multiple panels to draw, you must first determine which panel to draw and then do your drawing. An illustration might help to explain this. The book's code includes a program called StatBar that illustrates some of the things you can do with status bars. Run the program and examine its source for tips on implementing status bars in your applications. Figure 13.6 shows the StatBar program running.

FIGURE 13.6. The StatBar program with owner-drawn status bar panels.

As you can see, the status bar in this program has multiple panels. The middle three panels are owner-drawn. The panels marked OVR and EXT simulate the status bar on a word processing program or code editor. In those types of programs, the Overtype or Extended Selection modes might be on or off. If the mode is on, the text in the status bar panel shows in black. If the mode is off, the text has a 3D disabled-text appearance. The third owner-drawn panel displays a stock Windows icon to illustrate the use of a graphic on a status bar. Run the program and experiment with it to learn how it works.

Listing 13.1 shows the OnDrawPanel event handler from the StatBar program. Examine it and read the comments to understand what is going on in the code.


procedure TMainForm.StatusBarDrawPanel(StatusBar: TStatusBar;
  Panel: TStatusPanel; const Rect: TRect);
  R : TRect;
  Icon : HIcon;
  with StatusBar.Canvas do begin
    { Create a temporary TRect object. The Rect parameter
    { is const so we can't change it. }
    R := Rect;
    { Check to see if panel 3 is the panel which needs
    { to be drawn. If so, draw an icon in the panel. }
    if Panel.Index = 3 then begin
        { Load one of the stock Windows icons. This time
        { using the API is easier than using VCL. }
        Icon := LoadIcon(0, IDI_HAND);
        { Draw the icon and shrink it down to 15 x 15 pixels. }
        { Center it in the panel, too. }
        DrawIconEx(Handle, Rect.Left + 6, 3,
          Icon, 15, 15, 0, 0, DI_NORMAL);
        { Nothing more to do. }
    { This rather lengthy if statement checks to see if
    { either the Overtype Mode or Extended Selection
    { check boxes are checked. If so, then what we need
    { to do is to draw the text twice. First, we draw it
    { in white. Then we draw it again, offset by 1 pixel,
    { in gray. The effect is a 3D disabled-text look. }
    if ((Panel.Index = 1) and (OvrMode.Checked = False)) or
      ((Panel.Index = 2) and (ExtendedSel.Checked = False))
        then begin
      { Move over and down one pixel for the offset. }
      Inc(R.Top, 2);
      { Change the text color to white. }
      Font.Color := clWhite;
      { Set the backround mode to transparent so the
      { text appears hollow and so that the white
      { text can be seen under the gray. }
      Brush.Style := bsClear;
      { Draw the text using the API function DrawText. }
      { I use DrawText because it allows me to center
      { the text both horizontally and vertically within
      { the given rectangle. }
      DrawText(Handle, PChar(Panel.Text), -1,
      { Set the color to gray because we're going to
      { draw the text in gray in a moment. }
      Font.Color := clGray;
      { Set the rect back to the original size. }
      Dec(R.Top, 2);
    { Display the text. If the item is not disabled then
    { the default color (black) is used to draw the text. }
    { If the item is disabled, then the text color has
    { been set to gray by the code above. }
    DrawText(Handle, PChar(Panel.Text), -1,

This code might seem intimidating, but most of it is comment lines. The code itself is relatively simple. The comment lines explain what is happening at each step: The 3D appearance for the disabled text is accomplished by drawing the text once in white and then drawing it again in gray with a slight offset. The result is that the text looks recessed. The icon is displayed using the Windows API functions LoadIcon and DrawIconEx.

Owner drawing of status bar panels is daunting at first, but you'll soon find out that it's not all that bad. You might write Windows applications for a long time and never need owner-drawn panels in your status bar. If you ever need them, however, you'll know that's not impossible to accomplish.

Adding Functionality with Command Enabling

Command enabling is the process of enabling or disabling buttons depending on current conditions. For example, there's not much point of having the Cut or Copy button or menu item enabled for a text editor when no text is currently selected. Likewise, if there is no text in the Clipboard, the Paste button should be disabled.

Command enabling isn't difficult, especially with Delphi's new TActionList component. Still, it takes time to get right. It takes time because you have to pay attention to detail. (Sometimes it is attention to detail that separates the great applications from the mediocre applications.)

Command Enabling with TActionList and TAction

The TAction class provides a convenient way of performing command enabling. TActionList, the nonvisual component that manages actions, is found on the Additional tab of the Component palette. TActionList, as its name implies, contains a list of TAction objects. You create an action and then assign that action to any controls that need to be enabled or disabled based on that action. By controls I mean menu items, toolbar buttons, context menu items, and so on.

Let's take the Edit|Cut menu item, for example. You could have at least three objects associated with this particular task:

You create actions with the ActionList Editor. Given the Edit|Cut example, you would create an action for Cut called, say, CutAction. Then, using the Object Inspector, you assign CutAction to the Action property of each of the objects that correspond to the cut operation (toolbar buttons and menus, for example). At runtime, when you need to enable the Cut option, you can do so with just one line of code:

CutAction.Enabled := True;

This will enable all components with their Action properties set to CutAction. Disabling the Cut items is as simple as assigning False to the Enabled property of the action. The OnUpdate event of TAction and TActionList provides a convenient place to put your command-enabling code.

Command enabling with TAction is something that you have to experience to fully appreciate. You add command enabling to ScratchPad in the next section.