WTL for MFC Programmers, Part III - Toolbars and Status Bars
Original: Michael Dunn [English] Translation: Orbit (Star Rails Orbit) [http://www.winmsg.com/cn/orbit.htm]
Download Demonstration Code
This chapter
Introducing the toolbar and status of the main window (Toolbars and Status Bars) wizards to the code generated by the toolbar and status bar
CMAINFRAME How to create a toolbar and status bar display and hide the inherent feature of the toolbar and status toolbar and status bars Create different styles of toolbar toolbar editor toolbar buttons UI status update (Updating)
Enable a toolbar to support the UI status Update using Rebar instead of simple toolbar multi-pane status strip
The UI status update of the pane is started: the topic reference and reference modification records for the dialog
Introduction to the third part
Since the emergence of a general control as a Windows 95, the toolbar and status strip have become a very common thing. Since MFC supports floating tool strips to make them more popular. With the update of the general control, Rebars (initially referred to as Coolbar) makes the toolbar have another display method. In the third part, I will introduce WTL's support for these controls and how to use them in your program.
Main window toolbar and status bar
CFraMewindowImpl has three hWnd type member variables to be initialized when the window is created, and we have seen M_HWndClient, which is the handle of the "View" window of the main window client area, now we have two:
M_hWndToolbar: Toolbar or Rebar window handle M_HWndStatusbar: Window handle of the status bar
CfraMewindowImpl only supports a toolbar, nor a multi-point docking toolbar like MFC, if you want to use multiple toolbars and don't want to modify the internal code of CFraMewIndowImpl, you need to use Rebar. I will introduce them and demonstrate how to add tool bars and rebar to Rebar using the application wizard.
CFrameWindowImpl :: OnSize () message response function calls UpdateLayout (), updateLayout () Do two things: From the new positioning of all controls and changing the size of the view window to fill the entire client area. The actual work is done by updatebarsposition (), updateLayout () just calls the function. The code implemented is quite simple, transmitting a WM_SIZE message to the toolbar and status strip, and position them to the top or bottom of the main window by the default window processing procedure.
When you tell the Application Wizard to add a toolbar and status bar, the wizard adds the code to create their code in CMAINFRAME :: OnCreate (). Now let's take a look at these code, of course, to write a clock program.
The wizard is the toolbar and state strip generation code
We will start a new project to let the wizard create a toolbar and status bar for the main window. First create a new project called WTLCLOCK2, in the first page of the wizard, select SDI and make the "Generate CPP File" checkbox:
On the second page, cancel the rebar to enable the wizard to create only one normal toolbar:
Copy the corresponding code from the second part, the new program looks like this:
CMAINFRACMAINFRAME How to create a toolbar and status bar
In this example, more code has been directed to the CMAINFRAME :: oncreate () function, the role of these codes is to create a control bar and inform the CupdateUi button on the toolbar.
LRESULT CMainFrame :: OnCreate (UINT / * uMsg * /, WPARAM / * wParam * /, LPARAM / * lParam * /, BOOL & / * bHandled * /) {CreateSimpleToolBar (); CreateSimpleStatusBar (); m_hWndClient = m_view.Create (. ..); // ... // register object for message filtering and idle updates CMessageLoop * pLoop = _Module.GetMessageLoop (); ATLASSERT (pLoop = NULL);! pLoop-> AddMessageFilter (this); pLoop-> AddIdleHandler ( this); Return 0;} This is the beginning of the newly added code, the cframeWindowImpl :: createSimpleToolbar () function creates a toolbar using the resource IDR_MAINFRAME and assigns the handle to m_hwndtoolbar, below the code code:
BOOL CFrameWindowImpl :: CreateSimpleToolBar (UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR) {ATLASSERT (:: IsWindow (m_hWndToolBar)!); If (nResourceID == 0) nResourceID = T :: GetWndClassInfo () m_uCommonResourceID. M_HWNDTOOLBAR = T :: CreateSimpletoolbarctrl (m_hwnd, nresourceid, true, dwstyle, nid); return (m_hwndtoolbar! = null);}
parameter:
NresourceId
Tool strip resources have Id. If you use the default value 0 as a parameter, the program will use the declare_frame_wnd_class macro to specify the resource, and the IDR_MAINFRAME used here is the code generated by the wizard.
DWStyle
Type or style of the toolbar. Default ATL_SIMPLE_TOOLBAR_STYLE is defined as a combination of TBStyle_Tooltips, sub-windows, and visible three styles, which makes the mouse to move on the button to pop up the tooltip.
NID
The window ID of the toolbar is usually used.
CreateSimpleToolbar () first checks if a toolbar has been created, then call the createSimpleToolbarCtrl () function creation toolbar control, the toolbar control handle is saved in m_hwndtoolbar. CreateSimpleToolBarctrl () is responsible for reading resources and creates the corresponding toolbar buttons, then returns the handle of the toolbar window. This part of the code is quite long, I don't do it here, if you are interested in this code in Atlframe.h.
The OnCreate () function calls the next CFrameWindowImpl :: CreateSimpleStatusBar () function, which creates a status bar and handle m_hWndStatusBar present, following is the code for the function: BOOL CFrameWindowImpl :: CreateSimpleStatusBar (UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = .. . SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) {TCHAR szText [128]; // max text lentgth is 127 for status bars szText [0] = 0; :: LoadString (_Module.GetResourceInstance (), nTextID, szText, 128); return CreateSimpleStatusbar (Sztext, DWStyle, NID);
The text displayed in the status bar is loaded from the string resource, and the parameters of this function are:
NTextID
The resource ID of the string displayed on the status strip, the string of the ATL_IDS_IDLEMESSAGE that is generated by the wizard is "Ready".
DWStyle
State strip style. The default value contains the sbars_sizegrip style, which makes a logo that change the window size in the lower right corner of the status bar.
NID
The window ID of the status bar is usually used.
CreateSimpleStatusbar () calls another overload function to create a status:
BOOL CFrameWindowImpl :: CreateSimpleStatusBar (LPCTSTR lpstrText, DWORD dwStyle = ... SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) {ATLASSERT (:: IsWindow (m_hWndStatusBar)!); M_hWndStatusBar = :: CreateStatusWindow (dwStyle, lpstrText, m_hWnd, nID); return (m_hwndstatusbar! = null);
This overloaded version first checks if the status strip has been created, then call the CreateStatusWindow () creation status strip, and the handle of the status bar is stored in m_hwndstatusbar.
Show and hide toolbars and status bars
The CMAINFRAME class also has a view menu, which has two commands: display / hide the toolbar and status strip, their ID is ID_view_toolbar and id_view_status_bar. The CMAINFRAME class has the response function of these two commands, display and hide the corresponding control bar, and below is the code of the onviewtoolbar () function:
LRESULT CMainFrame :: OnViewToolBar (WORD / * wNotifyCode * /, WORD / * wID * /, HWND / * hWndCtl * /, BOOL & / * bHandled * /) {BOOL bVisible = :: IsWindowVisible (m_hWndToolBar);! :: ShowWindow ( m_hwndtoolbar, bvisible? sw_shownoactivate: sw_hide); uisetcheck (id_view_toolbar, bvisible); UpdateLayout (); return 0;} These code flip control strips, the corresponding flipping View | Toolbar menu check tag, then call UpdateLayout () Relocate the control bar and change the size of the view window.
Intrinsic feature of the toolbar and status bar
The MFC framework provides a lot of good features, such as the tooltles of the toolbar buttons, and the brush help of the menu item. The corresponding functionality in the WTL is implemented in the CFrameWindowIMPL class. The screenshot below shows the tooltips and brush help.
The CFraMewindowImplbase class has two messages corresponding functions to implement these features, onMenuselect () processes the WM_MENUSELECT message, which looks up the bridging of a string of transcathered help like MFC: first load the same string resources as menu resource ID, in the string Find / n characters, use / n's content as the content of the help. The ONTOOLTEXTA () and the ONTOOLTIPTEXTW () function respond to TTN_GetDispinfoA messages and TTN_GetDispinFow messages, respectively, and provides tooltips for toolbar buttons. These two processing functions are loaded with the onMenusElect () function, just use the string following / N. (Border: onMenuselect () and the onTooltipTexta () function are unsafe for DBCS characters because it does not check the head and tail of the DBCS string when looking for / n characters) Below is the toolbar and its associated help string example of:
Create a different style of toolbar
If you don't like to display 3D buttons on the toolbar (although the interface element elements from availability is a bad thing), you can change the style of the toolbar by changing the parameters of the createSimpleToolbar () function. For example, you can create an IE style toolbar :: CMAINFRAME :: OnCreate () to create an IE style toolbar:
CreateSimpleToolbar (0, ATL_SIMPLE_TOOLBAR_STYLE | TBSTYLE_FLAT | TBSTYLE_LIST);
If you use the wizard to add a manifest file to your program, it will use the version 6.0 version of the general control on the Windows XP system, you cannot select the type of buttons, the toolbar will automatically use the flat button, even if you create a toolbar TBStyle_flat style.
Toolbus editor
As we see before, the wizard creates several default buttons for our program, of course only the About button has event processing. You can use the toolbar editor to modify the toolbar resources like the MFC's engineering, create toolbar with this toolbar resource. Below is the tool bar generated by the guide in the editor:
For our clock, we add four buttons, two buttons are used to change the color of the view window, and two other uses to display / hide the toolbar and status bar. Here is our new tool:
These buttons are:
IDC_CP_COLORS: Change the view window color to the color IDC_BW_COLORS of the CodeProject website: Change the view window color to black and white color id_view_status_bar: Show or hide status bar id_view_toolbar: The two buttons of the display or hide the toolbar have the corresponding menu item, they all call A new function setColor () of the view class, delivers the foreground color and background color to this function, and the view window changes the display of the window with the two parameters. Responding to the processing function of these two buttons and the processing function of the response to the corresponding menu item, there is no difference in using the command_id_handler_ex macro, and you can view the code of the example project to understand the details of these messages. In the next section I will introduce the UI status update of the status strip and the toolbar button, enabling them to reflect the current state of the toolbar or status bar.
UI status update for toolbar buttons
The code generated by the wizard has added the CMAINFRAME to the CHECK and Uncheck's UI update processing for both menu items for VIEW | Toolbar and View | Status Bar. This is the same as the second chapter: two commands to the CMAINFRAME class use the UI update macro:
BEGIN_UPDATE_UI_MAP (CMAINFRAME) UPDATE_ELEMENT (ID_View_toolbar, Updui_Menupopup) Update_element (id_view_status_bar, UPDUI_MENUPOPUP) End_UPDATE_UI_MAP ()
The toolbar of our clock program has the same ID as the corresponding menu item, so the first step is to add an UPDUI_TOOLBAR flag for each macro:
BEGIN_UPDATE_UI_MAP (CMainFrame) UPDATE_ELEMENT (ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP | UPDUI_TOOLBAR) UPDATE_ELEMENT (ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP | UPDUI_TOOLBAR) END_UPDATE_UI_MAP ()
It is also necessary to add two functions to the toolbar button, but fortunately, the wizard has been done for us, so if this program is compiled, the menu item and the toolbar button will be updated.
Make a tool strip support UI status update
If you see the code code code code, you will find a new code, this code sets the initial state of the two menu items:
Lresult cmainframe :: oncreate (...) {// ... m_hwndclient = m_view.create (...); uiaddtoolbar; uiSetCheck (id_view_toolbar, 1); uisetcheck (id_view_status_bar, 1); // .. }
UIADDTOOLBAR () passes the window handle of the toolbar to CUPDATEUI, so the CUPDATEUI will send a message to this window when the status of the update button is required. Another important call is in OnIdle ():
Bool cmainframe :: onidle () {uiupdatetoolbar (); return false;}
When there is no message waiting in the message queue, cMessageloop :: run () calls OnIdle (), uiupdatetoolbar () traverses the UI update table, finds the interface that has changed the status of the updui_toolbar flag and the UisetCheck () Elements (of course, toolbars), the status of the corresponding change button. Note that if the status of the update pop-up menu does not need to do more, because the CupdateUI responds to the WM_INITMENUPOPUP message, only the menu status is updated when this message is received.
If the viewing example code will find that it also demonstrates how to update the status of the top menu item on the menu bar of the frame window. There is a menu item to perform the start and stop commands, start and stop the role of the clock, of course, this requires some incompetent things: menu items on the menu bar are always popped up. For complete introduction Cupdateui I also add them in an example code, to find out that they can find calls to UIAddMenubar () and UIUPDATEMENUBAR () two functions. Use Rebar instead of simple toolbar
CFraMewindowImpl also supports the use of the Rebar control, making your program like IE, using Rebar is also a way to use multiple toolbars in the program (translator plus: The other method is to modify the source code of the WTL). To use Rebar, you need to select the check box that supports Rebar on the second page of the wizard, as shown below:
The second example engineering WTLCLOCK3 uses the rebar control, if you are studying an example code, then open WTLClock3 now.
You will first notice that the code for creating the toolbar is somewhat different, and this feeling is because we use Rebar in the program. The following is the relevant code:
LRESULT CMainFrame :: OnCreate (...) {HWND hWndToolBar = CreateSimpleToolBarCtrl (m_hWnd, IDR_MAINFRAME, FALSE, ATL_SIMPLE_TOOLBAR_PANE_STYLE); CreateSimpleReBar (ATL_SIMPLE_REBAR_NOBORDER_STYLE); AddSimpleReBarBand (hWndToolBar); // ...}
The code starts from the creation toolbar, but uses a different style, which is ATL_SIMPLE_TOOLBAR_PANE_STYLE, which is defined in the atlFrame.h file, similar to the ATL_SIMPLE_TOOLBAR_STYLE style, just there is a style such as CCS_noparentAlign, which is the toolbar as rebar The sub-window can work properly.
The next line code is to call the createSimpleRebar () function, which creates the Rebar control and stores the handle into the m_hwndtoolbar. Next, call the addsimpleRebarband () function to create a bar in REBAR and telling Rebar. This is a toolbar.
CMAINFRAME :: OnViewToolbar () functions are also somewhat unique, it only hides the bar of the toolbar on the toolbar rather than hidden M_HWndToolbar (if hidden m_hwndtoolbar will hide the entire Rebar, not just the toolbar).
If you use multiple toolbars, you only need to create them on OnCreate () as you generated on the first toolbar like the wizard. CframeWindowIMPL uses standard Rebar controls, unlocked toolbars like MFC, where you can work is to arrange these tool bars in the REBAR.
Multi-pane status bar
Another state bar class implements a state of multi-pane, as the Caps, Lock and Num Lock indicators as the default status bars of the MFC, this class is CMULTIPANESTATUSBARCTRL, which demonstrates how to use this class in the WTLClock3 example project. This class supports a limited UI update. When the pop-up menu is displayed, the pane with the "default" property extends to the width of the entire state bar for the display of the menu.
The first step is to declare a CMULTIPANESTATUSBARCTRL type member variable in CMAINFRAME: Class CMAINFRAME: PUBLIC ... {// ... protected: cmultipanestatusbarctrl m_wndstatusbar;};
Then create a status strip in OnCreate () and this UI update:
m_hwndstatusbar = m_wndstatusbar.create (* this); UIAddStatusbar;
Just like the CreateSimpleStatusbar () function, we also store the handle of the status bar in M_HWndStatusbar.
The next step is to call the CMULTIPANESTATUSBARCTRL :: SetPanes () function creation pane:
Bool setpanes (int * ppanes, int npanes, bool bsettext = true);
parameter:
Ppanes
Array of storage pane IDs
npanes
The number of elements in the pane ID array (the translator plus: is the number of panes)
BsetText
If you are true, all panes are set immediately, which will be explained below.
The pane ID can be id_default_pane, this ID is used to create a pane that supports the bridging help, and the pane ID can also be a string resource ID. For non-default pane WTLs load this ID corresponding to the string and calculate the width, and set the pane to the corresponding width, which is the same as the logic used by the MFC.
BSETTEXT controls if the pane is immediately displayed the relevant string, if it is true, setpanes () shows the string of each pane, otherwise the pane is blank.
Here is our call to setpanes ():
// Create The Status Bar Panes. Int Anpanes [] = {ID_DEFAULT_PANE, IDPANE_STATUS, IDPANE_CAPS_INDICATOR}; M_WndstatusBar.Setpanes (Anpanes, 3, False);
The string corresponding to IDPane_status is "@@@", which should have enough width (expect to be) to display two clock status strings "Running" and "stopped". Like MFC, you need your own estimation pane width, and the string corresponding to IDPane_caps_indicator is "CAPS".
Pate's UI status update
In order to update the text on the pane, we need to add the corresponding pane to the UI update table:
Begin_UPDATE_UI_MAP (CMAINFRAME) / / ... UPDATE_ELEMENT (1, UPDUI_STATUSBAR) / / Clock Status Update_Element (2, UPDUI_STATUSBAR) / / CAPS INDICATOR END_UPDATE_UI_MAP ()
The first parameter of this macro is the index of the pane instead of the ID, which is unfortunate, because if you rearrange the pane, you have to remember to update the UI update table.
Since we call setPanes () is the third parameter is false, the pane is initially empty. Let's take the next step to set the initial text of the clock status pane to "Running"
// set the initial text for the clock status Pane. Uisettext (1, _t ("running"));
As in front, the first parameter is the index of the pane. Uisettext () is the only UI update function that the status strip supports. Finally, add the call to the UIUpdateStatusbar () function in CMAINFRAME :: OnIdle (), so that the pane of the status bar can be updated in the idle time:
Bool cmainframe :: onidle () {UIUPDATETOOLBAR (); UIUPDATESTATUSBAR (); RETURN FALSE;}
When you use uiupdatestatusbar (), a question of CUPDATEUI is exposed - the text of the menu item is not changed after calling uisettext ()! If you are watching the WTLClock3 project, the clock's start / stop menu item is moved to the Clock menu, set the text of the menu item in the response process of the menu item command. Anyway, if the current call is UIupdateStatusbar (), the call to UisetText () will not work. I didn't study if this problem can be fixed, so if you intend to change the text of the menu, you need to pay attention to this place.
Finally, we need to check the status of the Caps Lock key, update the corresponding two panes. These codes are called by OnIdle (), so the program checks their status at each free time.
Bool CMAINFRAME :: OnIdle () {// Check The Current Caps Lock State, And if it is on, show the status bar. If (getKeyState (vk_capital) & 1) Uisettext (2, CSTRING (LPCTSTR (IDPane_Caps_indicator)); Else Uisettext (2, _T (")); UIUpdatetoolbar (); UIUpdateStatusbar (); Return False;}
The "Caps" string is loaded from the string resource for the first time, but a huge tips in the CString constructor (with sufficient document description) are used.
After all the code is completed, the status strip looks like this:
Beneneur: Topics about dialogments
In Chapter 4 I will introduce the usage of the dialog (including ATL classes and WTL enhancements), improvements in the control package and WTL related dialog messages.
Quote and reference
"How to use the wtl multipane status bar control" by Ed Gadziemski introduces the usage of the CMULTIPANESTATUSBARCTRL class.
Modify record
On April 11, 2003, this article was first published.