Step 10: Adding decorations

Back Home Up Next

The only changes in Step 10 are in the InitMainWindow function. But these changes let you make your application more attractive and easier and more intuitive to use. In this step, you'll add a control bar with bitmap button gadgets and a status bar that displays the current menu choice. You can find the source for Step 10 in the files STEP10.CPP and STEP10.RC in the directory EXAMPLES\OWL\TUTORIAL.

There are four main changes in this step:

Changing the main window from a TFrameWindow to a TDecoratedFrame.
Creating a status bar and inserting it into the decorated frame window.
Creating a control bar, along with its button gadgets, and inserting it into the decorated frame.
Adding resources, such as a string table (which provides descriptions of each of the available menu choices) and bitmaps for the button gadgets.

Changing the main window

Changing from a TFrameWindow to a TDecoratedFrame is quite easy. Because TDecoratedFrame is based on TFrameWindow, a decorated frame can be used just about anywhere that a regular frame window is used. In this case, just create a TDecoratedFrame and pass it as the parameter to the SetMainWindow function.

Even the constructors of the TFrameWindow and TDecoratedFrame are alike. The only difference is the fourth parameter, which wasn't being used anyway. The fourth parameter for TFrameWindow is a bool that tells the frame window whether it should shrink to the size of its client window.

The fourth parameter for TDecoratedFrame is also a bool. This parameter indicates whether the decorated frame should track menu selections. Menu tracking displays a text description of the currently selected menu choice or button in a message bar or status bar. If you specify true for this parameter, you must supply a message or status bar for the window. If you don't, your application will crash the first time it tries to send a message to the message or status bar.

If you're using a status bar, you must include the resources for it in your resource file. These resources are contained in the file STATUSBA.RC in the INCLUDE\OWL directory.

The only other difference is that the decorated frame requires some preparation, such as adding decorations like the control bar and status bar, before it can become the main window. So instead of constructing and setting the window in one step, you must construct the window, prepare it, then set it as the main window.

Creating the status bar

Status bars are created using the TStatusBar class. TStatusBar is based on the TMessageBar class, which is itself based on TGadgetWindow. Both message bars and status bars display text messages. But status bars have more options than message bars. For example, you can have multiple text gadgets, styled borders, and mode indicators (such as Insert or Overwrite mode) in a status bar.

The TStatusBar constructor takes five parameters, although you only use the first two. The rest of the parameters take on their default values:

The first parameter is a pointer to the status bar's parent window. In this case, use frame, which is the pointer to the decorated frame window constructed earlier.
The second parameter is a TGadget::TBorderstyle enum. It can be one of None, Plain, Raised, Recessed, or Embossed. This parameter determines the style of the status bar. This parameter defaults to Recessed.
The third parameter is a TModeIndicator enum. It determines the keyboard modes that the status bar should show. These indicators can be one or more of ExtendSelection, CapsLock, NumLock, ScrollLock, Overtype, and RecordingMacro. This parameter defaults to 0, meaning to indicate no keyboard modes.
The fourth parameter is a TFont *. This contains the font that should be used in the status bar. This defaults to TGadgetWindowFont.
The fifth parameter is a TModule *. It defaults to 0.

Here is the status bar constructor:


TStatusBar* sb = new TStatusBar(frame, TGadget::Recessed);
       

Once the status bar is created, it is ready to be inserted into the decorated frame. This is described below.

Creating the control bar

Creating the control bar is more involved than creating the status bar. You first construct the actual TControlBar object. Then you create the gadgets that make up the controls on the bar and insert them into the control bar.

Constructing TControlBar

The TControlBar constructor takes four parameters, although you need to use only the first parameter here. The rest of the parameters take on their default values:

The first parameter is a pointer to the parent window. As with the status bar, use frame here to make the decorated frame the control bar's parent.
The second parameter is a TTileDirection enum. A TTileDirection enum can have two values, Horizontal and Vertical. This tells the control bar which way to tile its controls. This parameter defaults to Horizontal.
The third parameter is a TFont *. This contains the font that should be used in the status bar. This defaults to TGadgetWindowFont.
The fourth parameter is a TModule *. It defaults to 0.

Here is the control bar constructor:


TControlBar *cb = new TControlBar(frame);

cb->EnableFlatStyle();  // Enable the new flat look of toolbar buttons

       

Building button gadgets

Button gadgets are used as control bar buttons. They associate a bitmap button with an event identifier. When the user presses a button gadget, it sends that event identifier. You can set this up so that pressing a button on the control is just like making a choice from a menu. In this section, you'll see how to set up buttons to replicate each of your current menu choices.

Button gadgets are created using the TButtonGadget class. The TButtonGadget constructor takes six parameters, of which you need to use only the first three:

The first parameter is a reference to a TResId object (see the note on page 43 regarding the TResId class). This should be the resource identifier of the bitmap you want on the button. There are no real restrictions on the size of the bitmap you can use in a button gadget. There are, however, practical considerations: the control bar height is based on the size of the objects contained in the control bar. If your bitmap is excessively large, the control bar will be also.
The second parameter is the gadget identifier for this button gadget. Usually the gadget identifier, event identifier, and bitmap resource identifier are the same. For example, the button gadget for the File New command uses a bitmap resource called CM_FILEOPEN, has the gadget identifier CM_FILEOPEN, and posts the event CM_FILEOPEN. The bitmap is given the same identifier in the resource file as the event identifier. This makes it a little easier on you when working with the code. This is not a rule, however, and you can name the bitmap and event identifier whatever you like. The only stipulation is that the event identifier must be defined and have some sort of processing enabled and the resource identifier must be valid. You should also notice that there are a number of entries in the application's string resource table that have the same IDs as the gadgets and events. When a string exists with the same identifier as a button gadget, that string is displayed in the status bar when the gadget is pressed.
The third parameter is a TType enum. This indicates what type of button this is. There are three possible button types, Command, Exclusive, and NonExclusive. In this application, all the buttons are command buttons. This parameter defaults to Command.
The fourth parameter is a bool indicating whether the button is enabled. By default this parameter is false.
The fifth parameter is a TState enum. This parameter indicates the initial state of the button, and can be Up, Down, or Indeterminate. This parameter defaults to Up.
The sixth parameter is a bool that indicates the repeat state of the button. If the repeat state is true, the button repeats when it is pressed and held. By default, this parameter is false.

Separator gadgets

There is another type of gadget commonly used when constructing control bars, called a separator gadget. Normally gadgets in a control bar are right next to each other. A separator gadget provides a little bit of space between two gadgets. This lets you separate gadgets into groups, place them in predetermined spots on the control bar, and so on.

Separator gadgets are contained in the TSeparatorGadget class. This is a simple class that takes a single int parameter. By default the value of this parameter is 6. This parameter indicates the number of pixels of space the separator gadget should take up.

Inserting gadgets into the control bar

Once your gadgets are constructed, you need to insert them into the control bar. The control bar can take gadgets because it is derived from the class TGadgetWindow. TGadgetWindow provides the basic functionality that lets you use gadgets in a window. TControlBar refines that functionality, producing a control bar.

You can insert gadgets into the control bar using the Insert function. This version of the Insert function is inherited by TControlBar from TGadgetWindow (later you'll use another version of this function contained in TDecoratedFrame). This function takes three parameters, although you need to use only the first parameter in the tutorial application:

The first parameter is a reference to a TGadget or TGadget-derived object.
The second parameter is a TPlacement enum, which can have a value of Before or After. This parameter indicates whether the gadget should be placed before or after the gadget's sibling. The default value is After. This parameter has no effect if there is no sibling specified.
The gadget's sibling is specified by the third parameter, which is a TGadget *. The sibling should have already been inserted into the control bar. This parameter defaults to 0.

In the tutorial application, constructing the gadgets and inserting them into the control bar is accomplished in a single step. Here is the code where the gadgets are inserted into the control bar:

cb->Insert(*new TButtonGadget(CM_FILENEW, CM_FILENEW,
           TButtonGadget::Command));
cb->Insert(*new TButtonGadget(CM_FILEOPEN, CM_FILEOPEN,
           TButtonGadget::Command));
cb->Insert(*new TButtonGadget(CM_FILESAVE, CM_FILESAVE,
           TButtonGadget::Command));
cb->Insert(*new TButtonGadget(CM_FILESAVEAS, CM_FILESAVEAS,
           TButtonGadget::Command));
cb->Insert(*new TSeparatorGadget);
cb->Insert(*new TButtonGadget(CM_PENSIZE, CM_PENSIZE,
           TButtonGadget::Command));
cb->Insert(*new TSeparatorGadget);
cb->Insert(*new TButtonGadget(CM_ABOUT, CM_ABOUT,
           TButtonGadget::Command));
       

Notice that the button gadgets replicate the menu commands you already have. This provides an easy way for the user to access frequently used menu commands. Of course, you aren't restricted to using gadgets in a control bar as substitutes or shortcuts for menu commands. Using the TType parameter, you can set up gadgets on a control bar to work like radio buttons (by using Exclusive with a group of gadgets), check boxes (using NonExclusive), and so on.

Inserting objects into a decorated frame

Now that you've constructed the decorations for your TDecoratedFrame window, all you need to do is insert the decorations into the window and make the window the main window.

Inserting decorations into a decorated frame is similar to inserting gadgets into a control bar. The TDecoratedFrame::Insert function takes two parameters:

The first is a reference to a TWindow or TWindow-derived object. This TWindow object is the decoration. In this case, the TWindow-derived objects are the TStatusBar object and the TControlBar object.
The second parameter is a TLocation enum. This parameter can have one of four values, Top, Bottom, Left, or Right. This indicates where in the decorated frame the gadget is to be placed.

Here is the code for inserting the decorations into the decorated frame:

// Insert the status bar and control bar into the frame
frame->Insert(*sb, TDecoratedFrame::Bottom);
frame->Insert(*cb, TDecoratedFrame::Top);
      

Once you've inserted the decorations into the frame, the last thing you have to do is set the main window to frame and set up the menu:

// Set the main window and its menu
SetMainWindow(frame);
GetMainWindow()->AssignMenu("COMMANDS");
       

Where to find more information

Here's a guide to where you can find more information on the topics introduced in this step:

Decorated frame windows are discussed in "Window objects" in the ObjectWindows Programmer's Guide.
Gadgets are discussed in "Gadget and gadget window objects" in the ObjectWindows Programmer's Guide.
Status bars and control bars are discussed in both "Window objects" and "Gadget and gadget window objects" in the ObjectWindows Programmer's Guide.


Copyright © 1998-2001 Yura Bidus. All rights reserved.