|
|
Style | Description |
TBSTYLE_ALTDRAG | Allows the user to move the toolbar by dragging it while holding down the Alt key. |
TBSTYLE_CUSTOMERASE | Generates a NM_CUSTOMDRAW message when erasing the toolbar and button background, allowing the programmer to choose when and whether to control the background erasing process. |
TBSTYLE_FLAT | Creates a flat toolbar. Button text appears under the bitmap image. |
TBSTYLE_LIST | Button text appears to the right of the bitmap image. |
TBSTYLE_REGISTERDROP | For use in dragging and dropping objects onto toolbar buttons. |
TBSTYLE_TOOLTIPS | Creates a tooltip control that can be used to display descriptive text for the buttons. |
TBSTYLE_TRANSPARENT | Creates a transparent toolbar. |
TBSTYLE_WRAPABLE | Creates a toolbar that can have multiple rows of buttons. |
The third argument is the style of the toolbar itself. This argument is normally a combination of window and control bar styles. Normally, only two or three window styles are used, and the rest of the toolbar styles are control bar styles. The list of the normally used toolbar styles appears in Table 12.2.
Style | Description |
WS_CHILD | The toolbar is created as a child window. |
WS_VISIBLE | The toolbar will be visible when created. |
CBRS_ALIGN_TOP | Allows the toolbar to be docked to the top of the view area of the frame window. |
CBRS_ALIGN_BOTTOM | Allows the toolbar to be docked to the bottom of the view area of the frame window. |
CBRS_ALIGN_LEFT | Allows the toolbar to be docked to the left side of the view area of the frame window. |
CBRS_ALIGN_RIGHT | Allows the toolbar to be docked to the right side of the view area of the frame window. |
CBRS_ALIGN_ANY | Allows the toolbar to be docked to any side of the view area of the frame window. |
CBRS_BORDER_TOP | Places a border on the top edge of the toolbar when the top of the toolbar is not docked. |
CBRS_BORDER_BOTTOM | Places a border on the bottom edge of the toolbar when the top of the toolbar is not docked. |
CBRS_BORDER_LEFT | Places a border on the left edge of the toolbar when the top of the toolbar is not docked. |
CBRS_BORDER_RIGHT | Places a border on the right edge of the toolbar when the top of the toolbar is not docked. |
CBRS_FLOAT_MULTI | Allows multiple toolbars to be floated in a single miniframe window. |
CBRS_TOOLTIPS | Causes tooltips to be displayed for the toolbar buttons. |
CBRS_FLYBY | Causes status bar message text to be updated for the toolbar buttons at the same time as the tooltips. |
CBRS_GRIPPER | Causes a gripper to be drawn on the toolbar. |
The fourth argument, which you did not provide in your code, is the size of the toolbar borders. This argument is passed as a standard CRect rectangle class to provide the length and height desired for the toolbar. The default value is 0 for all of the rectangle dimensions, thus resulting in a toolbar with no borders.
The fifth and final argument, which you also did not provide in your code, is the toolbar's child window ID. This defaults to AFX_IDW_TOOLBAR, but you can specify any defined ID that you need or want to use for the toolbar.
After you create the toolbar, there is a curious bit of code:
// Find the Black button on the toolbar iTBCtlID = m_wndColorBar.CommandToIndex(ID_COLOR_BLACK); if (iTBCtlID >= 0) { // Loop through the buttons, setting them to act as radio buttons for (i= iTBCtlID; i < (iTBCtlID + 8); i++) m_wndColorBar.SetButtonStyle(i, TBBS_CHECKGROUP); }
The first line in this code snippet uses the CommandToIndex toolbar function to locate the control number of the ID_COLOR_BLACK button. If you design your toolbar in the order of colors that you used on the menu, this should be the first control, with a index of 0. It's best to use the CommandToIndex function to locate the index of any toolbar button that you need to alter, just in case it's not where you expect it to be. This function returns the index of the toolbar control specified, and you use this as a starting point to specify the button style of each of the color buttons.
In the loop, where you are looping through each of the eight color buttons on the toolbar, you use the SetButtonStyle function to control the behavior of the toolbar buttons. The first argument to this function is the index of the button that you are changing. The second argument is the style of button that you want for the toolbar button specified. In this case, you are specifying that each of the buttons be TBBS_CHECKGROUP buttons, which makes them behave like radio buttons, where only one of the buttons in the group can be selected at any time. The list of the available button styles is in Table 12.3.
Style | Description |
TBSTYLE_AUTOSIZE | The button's width will be calculated based on the text on the button. |
TBSTYLE_BUTTON | Creates a standard push button. |
TBSTYLE_CHECK | Creates a button that acts like a check box, toggling between the pressed and unpressed state. |
TBSTYLE_CHECKGROUP | Creates a button that acts like a radio button, remaining in the pressed state until another button in the group is pressed. This is actually the combination of the TBSTYLE_CHECK and TBSTYLE_GROUP button styles. |
TBSTYLE_DROPDOWN | Creates a drop-down list button. |
TBSTYLE_GROUP | Creates a button that remains pressed until another button in the group is pressed. |
TBSTYLE_NOPREFIX | The button text will not have an accelerator prefix associated with it. |
TBSTYLE_SEP | Creates a separator, making a small gap between the buttons on either side. |
The last thing that you do in the code that you add to the OnCreate function in the CMainFrame class is the following:
// Enable docking for the Color Toolbar m_wndColorBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); // (AppWizard generated line) // Dock the Color Toolbar DockControlBar(&m_wndColorBar);
In the first of these lines, you called the EnableDocking toolbar function. This function enables the toolbar for docking with the frame window. The value passed to this toolbar function must match the value passed in the following EnableDocking function that is called for the frame window. The available values for these functions are listed in Table 12.4. These functions enable the borders of the toolbar, and the frame window, for docking. If these functions are not called, then you will not be able to dock the toolbar with the frame window. If a specific side is specified in these functions for use in docking, and the sides do not match, you will not be able to dock the toolbar with the frame.
Style | Description |
CBRS_ALIGN_TOP | Allows the toolbar to be docked to the top of the view area of the frame window. |
CBRS_ALIGN_BOTTOM | Allows the toolbar to be docked to the bottom of the view area of the frame window. |
CBRS_ALIGN_LEFT | Allows the toolbar to be docked to the left side of the view area of the frame window. |
CBRS_ALIGN_RIGHT | Allows the toolbar to be docked to the right side of the view area of the frame window. |
CBRS_ALIGN_ANY | Allows the toolbar to be docked to any side of the view area of the frame window. |
CBRS_FLOAT_MULTI | Allows multiple toolbars to be floated in a single miniframe window. |
0 | The toolbar will not be able to dock with the frame. |
The final function that you added was a frame window function, DockControlBar, which is passed the address of the toolbar variable. This function physically docks the toolbar to the frame window. Because all of this code appears in the OnCreate function for the frame window, the toolbar is docked before the user sees either the window or the toolbar.
Now, after adding all of this code to the OnCreate function of the CMainFrame class, if you compile and run your application, you'll find a working color toolbar that you can use to select the drawing color, as shown in Figure 12.3.
FIGURE 12.3. The color toolbar on the drawing program.
Now that you have your color toolbar on the frame of your drawing application, it would be nice to be able to show and hide it just as you can the default toolbar and status bar through the View menu. This is simple enough functionality to add, but it doesn't necessarily work the way you might expect it to.
The first thing you need to do is add a menu entry to toggle the visibility of the color bar. Do this through the Menu Designer, adding a new menu entry on the View menu. Specify the menu properties as shown in Table 12.5.
Property | Setting |
ID | ID_VIEW_COLORBAR |
Caption | &Color Bar |
Prompt | Show or hide the colorbar\nToggle ColorBar |
To determine whether the toolbar is visible or hidden, you can get the current style of the toolbar and mask out for the WS_VISIBLE style flag. If the flag is in the current toolbar style, then the toolbar is visible. By placing this evaluation into the SetCheck function in the UPDATE_COMMAND_UI event message handler, you can check and uncheck the color bar menu entry as needed.
To add this functionality to your drawing program, add an event handler for the UPDATE_COMMAND_UI event message on the ID_VIEW_COLOR menu. Be sure to add this event-handler function into the CMainFrame class. (You're still making all of your coding changes so far in the frame class.) Edit the event-handler function, adding the code in Listing 12.2.
1: void CMainFrame::OnUpdateViewColorbar(CCmdUI* pCmdUI) 2: { 3: // TODO: Add your command update UI handler code here 4: /////////////////////// 5: // MY CODE STARTS HERE 6: /////////////////////// 7: 8: // Check the state of the color toolbar 9: pCmdUI->SetCheck(((m_wndColorBar.GetStyle() & WS_VISIBLE) != 0)); 10:
11: ///////////////////////
12: // MY CODE ENDS HERE 13: /////////////////////// 14: }
Because the CToolBar class is derived from the CWnd class (via the CControlBar class), you might think that you could call the ShowWindow function on the toolbar itself to show and hide the toolbar. Well, you can, but the background for the toolbar will not be hidden along with the toolbar. All the user would notice is the toolbar buttons appearing and disappearing. (Of course, this might be the effect you are after, but your users might not like it.)
Instead, you use a frame window function, ShowControlBar, to show and hide the toolbar. This function takes three arguments. The first argument is the address for the toolbar variable. The second argument is a boolean, specifying whether to show the toolbar. (TRUE shows the toolbar; FALSE hides the toolbar.) Finally, the third argument specifies whether to delay showing the toolbar. (TRUE delays showing the toolbar; FALSE shows the toolbar immediately.)
Once a toolbar is toggled on or off, you need to call another frame window function, RecalcLayout. This function causes the frame to reposition all of the toolbars, status bars, and anything else that is within the frame area. This is the function that causes the color toolbar to move up and down if you toggle the default toolbar on and off.
To add this functionality to your drawing program, add an event handler for the COMMAND event message on the ID_VIEW_COLOR menu. Be sure to add this event-handler function into the CMainFrame class. (You're still making all of your coding changes so far in the frame class.) Edit the event-handler function, adding the code in Listing 12.3.
1: void CMainFrame::OnViewColorbar() 2: { 3: // TODO: Add your command handler code here 4: 5: /////////////////////// 6: // MY CODE STARTS HERE 7: /////////////////////// 8: BOOL bVisible; 9: 10: // Check the state of the color toolbar 11: bVisible = ((m_wndColorBar.GetStyle() & WS_VISIBLE) != 0); 12: 13: // Toggle the color bar 14: ShowControlBar(&m_wndColorBar, !bVisible, FALSE); 15: // Reshuffle the frame layout 16: RecalcLayout(); 17: 18: /////////////////////// 19: // MY CODE ENDS HERE 20: /////////////////////// 21: }
At this point, after compiling and running your application, you should be able to toggle your color toolbar on and off using the View menu.
It's commonplace now to use applications that have more than just buttons on toolbars. Look at the Visual C++ Developer Studio, for example. You've got combo boxes that enable you to navigate through your code by selecting the class, ID, and function to edit right on the toolbar. So how do you add a combo box to a toolbar? It's not available in the toolbar designer; all you have there are buttons that you can paint icons on. You can't add a combo box to any toolbar by using any of the Visual C++ wizards. You have to write a little C++ code to do it.
To learn how to add a combo box to a toolbar, you'll add a combo box to the color toolbar you just created. The combo box will be used to select the width of the pen the user will use to draw images. (If you haven't added the support for different drawing widths from the exercise at the end of Day 10, you might want to go back and add that now.)
To add a combo box to your toolbar, the first thing that you need to do is what Visual C++ was designed to prevent you from having to do. You need to edit the resource file yourself. You cannot do this through the Visual C++ Developer Studio. If you try to open the resource file in the Developer Studio, you will be popped into the Resource View tab of the workspace pane, editing the resource file through the various resource editors and designers. No, you'll have to edit this file in another editor, such as Notepad.
Close Visual C++, the only way to guarantee that you don't write over your changes. Open Notepad and navigate to your project directory. Open the resource file, which is named after the project with a .rc filename extension. Once you open this file in Notepad, scroll down until you find the toolbar definitions. (You can search for the word "toolbar.") Once you've found the toolbar definitions, go to the end of the Color toolbar definition and add two separator lines at the bottom of the toolbar definition.
For instance, to make these changes to your drawing application, you need to navigate to the Toolbar project directory and then open the Toolbar.rc file. (If you are adding these toolbars to the MDI drawing application, you need to look for the Day11.rc file.) Search for the toolbar section, and then add two SEPARATOR lines just before the end of the IDR_TBCOLOR section, as shown in Listing 12.4. Once you add these two lines, save the file, exit Notepad, and restart Visual C++, reloading the project.
1: ////////////////////////////////////////////////////////////////////// 2: // 3: // Toolbar 4: // 5: 6: IDR_MAINFRAME TOOLBAR DISCARDABLE 16, 15 7: BEGIN 8: BUTTON ID_FILE_NEW 9: BUTTON ID_FILE_OPEN 10: BUTTON ID_FILE_SAVE 11: SEPARATOR 12: BUTTON ID_EDIT_CUT 13: BUTTON ID_EDIT_COPY 14: BUTTON ID_EDIT_PASTE 15: SEPARATOR 16: BUTTON ID_FILE_PRINT 17: BUTTON ID_APP_ABOUT 18: END 19: 20: IDR_TBCOLOR TOOLBAR DISCARDABLE 16, 15 21: BEGIN 22: BUTTON ID_COLOR_BLACK 23: BUTTON ID_COLOR_BLUE 24: BUTTON ID_COLOR_GREEN 25: BUTTON ID_COLOR_CYAN 26: BUTTON ID_COLOR_RED 27: BUTTON ID_COLOR_MAGENTA 28: BUTTON ID_COLOR_YELLOW 29: BUTTON ID_COLOR_WHITE 30: SEPARATOR 31: SEPARATOR 32: END
You added these two SEPARATOR lines in the toolbar definition so that the second separator can act as a place holder for the combo box that you are going to add to the toolbar. There are two reasons that you had to make this edit by hand and not use the Visual C++ toolbar designer. The first reason is that the toolbar designer would not allow you to add more than one separator to the end of the toolbar. The second reason is that, if you don't add anything else on the end of your toolbar after the separator, the toolbar designer decides that the separator is a mistake and removes it for you. In other words, the Visual C++ toolbar designer does not allow you to add the place holder for the combo box to your toolbar.
Next, you need to add the text strings that you will load into your combo box. To add these strings, you need to open the string table in the Resource View of the workspace pane. Here you find all of the strings that you entered as prompts in various properties dialogs. This table has a number of IDs, the values of those IDs, and textual strings that are associated with those IDs, as shown in Figure 12.4. You'll need to add the strings to be placed into your toolbar combo box in the string table; each line in the drop-down list must have a unique ID and entry in the strings table.
FIGURE 12.4. The string table editor.
For instance, to add the strings for the combo box that you will be adding to the color toolbar, insert a new string, either by selecting Insert|New String from the menu or by right-clicking the string table and selecting New String from the pop-up menu.
In the String properties dialog, specify a string ID for the string and then enter the string to appear in the drop-down list. Close the properties dialog to add the string. For the strings in the Width combo box that you are going to add to the color toolbar, add the strings in Table 12.6.
ID | Caption |
IDS_WIDTH_VTHIN | Very Thin |
IDS_WIDTH_THIN | Thin |
IDS_WIDTH_MEDIUM | Medium |
IDS_WIDTH_THICK | Thick |
IDS_WIDTH_VTHICK | Very Thick |
Before you can add the combo box to the color toolbar, you need to create a combo box variable that you can use for the combo box. Because you are not able to add this combo box through any of the designers, you need to add it as a variable to the CMainFrame class.
To add the combo box variable to the main frame class for the color toolbar, select the Class View tab in the workspace pane. Right-click the CMainFrame class and select Add Member Variable from the pop-up menu. Specify the variable type as CComboBox, the name as m_ctlWidth, and the access as protected.
Once you add the combo box variable to the main frame class, you need to perform a series of actions, all once the toolbar has been created:
To organize this so that it doesn't get too messy, it might be advisable to move the creation of the color toolbar to its own function that can be called from the OnCreate function of the main frame class. To create this function, right-click the CMainFrame class in the workspace pane and select Add Member Function from the pop-up menu. Specify the function type as BOOL, the function description as CreateColorBar, and the access as public. Edit the new function, adding the code in Listing 12.5.