|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Contents
Introduction to Part IIIEver since they were made into common controls in Windows 95, toolbars and status bars have become commonplace. MFC's support for multiple floating toolbars also helped their popularity. In later common controls updates, rebars (or coolbars as they were originally called) added another way to present toolbars. In Part III, I will cover how WTL supports these kinds of control bars and how to use them in your own apps. Remember, if you encounter any problems installing WTL or compiling the demo code, read the readme section of Part I before posting questions here. Toolbars and Status Bars in a Frame
The When you tell the AppWizard to give your frame a toolbar and status bar, the wizard puts code to create the bars in AppWizard Code for Toolbars and Status BarsWe'll start a new project and have the wizard create a toolbar and status bar for our frame. Start a new WTL project called WTLClock2. On the first AppWizard page, choose an SDI app and check Generate CPP files:
On the next page, uncheck Rebar so the wizard creates a normal toolbar:
After copying the clock code from the app in Part II, the new app looks like this:
How CMainFrame creates the barsThe AppWizard puts more code in 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; } The new code here is at the beginning. 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);
}
The parameters are:
The next call in 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);
}
This loads a string from the string table, which will be shown in the status bar. The parameters are:
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 version checks that a status bar has not been created yet, then calls Showing and hiding the bars
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; } This toggles the visible state of the bar, toggles the check mark next to the View|Toolbar menu item, then calls Built-in features of the barsMFC's framework provides some nice features in its toolbars and status bars, such as tooltips for toolbar buttons and flyby help for menu items. WTL has comparable features implemented in
Creating a toolbar with a different styleYou can change the style for the toolbar by passing the style bits as the second parameter to CreateSimpleToolBar ( 0, ATL_SIMPLE_TOOLBAR_STYLE |
TBSTYLE_FLAT | TBSTYLE_LIST );
Note that if you use a common controls v6 manifest in your app, you don't have a choice with the buttons when running on Windows XP or later - toolbars always use flat buttons even if you don't specify the The Toolbar EditorThe AppWizard creates several default buttons as we saw earlier. Only the About button is hooked up, however. You can edit the toolbar just as you do with an MFC project; the editor modifies the toolbar resource that
For our clock app, we'll add two buttons to change the colors in the view window, and two buttons that show/hide the toolbar and status bar. Here's our new toolbar:
The buttons are:
The first two buttons also have items on the View menu. They call a new function in the view class, UI Updating Toolbar ButtonsThe AppWizard-generated BEGIN_UPDATE_UI_MAP(CMainFrame)
UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP)
UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP)
END_UPDATE_UI_MAP()
Our clock app has toolbar buttons with those same IDs, so the first step is to add the 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()
There are two other functions to call to hook up toolbar button updating, but the wizard-generated code calls them, so if you build the project at this point, the menu items and toolbar buttons will both be updated. Enabling toolbar UI updatingIf you look in LRESULT CMainFrame::OnCreate( ... )
{
// ...
m_hWndClient = m_view.Create(...);
UIAddToolBar(m_hWndToolBar);
UISetCheck(ID_VIEW_TOOLBAR, 1);
UISetCheck(ID_VIEW_STATUS_BAR, 1);
// ...
}
BOOL CMainFrame::OnIdle()
{
UIUpdateToolBar();
return FALSE;
}
Recall that If you check out the sample project, it also shows how to UI update top-level menu items in the frame's menu bar. There is an item that executes the Start and Stop commands to start and stop the clock. While this is not a common (or even recommended) thing to do -- items in the menu bar should always be popups -- I included it for the sake of completeness in covering Using a Rebar Instead of a Plain Toolbar
The second sample project, WTLClock3, was made with this option checked. If you're following along in the sample code, open WTLClock3 now. The first thing you'll notice is that the code to create the toolbar is different. This makes sense since we're using a rebar in this app. Here 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);
// ...
}
It begins by creating a toolbar, but using a different style, The next line calls
If you want to have multiple toolbars, you can create them and call Multi-Pane Status BarsWTL has another status bar class that implements a bar with multiple panes, similar to the default MFC status bar that has CAPS LOCK and NUM LOCK indicators. The class is The first step is to declare a class CMainFrame : public ... { //... protected: CMultiPaneStatusBarCtrl m_wndStatusBar; }; Then in m_hWndStatusBar = m_wndStatusBar.Create ( *this );
UIAddStatusBar ( m_hWndStatusBar );
Notice that we store the status bar handle in The next step is to set up the panes by calling BOOL SetPanes(int* pPanes, int nPanes, bool bSetText = true); The parameters are:
The pane IDs can either be
Here's our call to // Create the status bar panes. int anPanes[] = { ID_DEFAULT_PANE, IDPANE_STATUS, IDPANE_CAPS_INDICATOR }; m_wndStatusBar.SetPanes ( anPanes, 3, false ); The string UI updating the panesIn order for us to update the pane text, we'll need entries in the update UI map: 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 in the macro is the index of the pane, not its ID. Watch out for this if you rearrange the panes - if not every pane has an entry in this map, you will need to update the numbers in the Since we pass false as the third parameter to // Set the initial text for the clock status pane. UISetText ( 1, _T("Running") ); Again, the first parameter is the index of the pane. Finally, we need to add a call to BOOL CMainFrame::OnIdle()
{
UIUpdateToolBar();
UIUpdateStatusBar();
return FALSE;
}
There is a problem in Finally, we need to check the state of the CAPS LOCK key and update pane 2 accordingly. This code can go right in BOOL CMainFrame::OnIdle()
{
// Check the current Caps Lock state, and if it is on, show the
// CAPS indicator in pane 2 of the status bar.
if ( GetKeyState(VK_CAPITAL) & 1 )
UISetText ( 2, CString(LPCTSTR(IDPANE_CAPS_INDICATOR)) );
else
UISetText ( 2, _T("") );
UIUpdateToolBar();
UIUpdateStatusBar();
return FALSE;
}
The first So after all that code, here's what the status bar looks like:
Up Next: All About DialogsIn Part IV, I'll cover dialogs (both the ATL classes and WTL enhancements), control wrappers, and more WTL message handling improvements that relate to dialogs and controls. References"How to use the WTL multipane status bar control" by Ed Gadziemski goes into more detail on the Copyright and licenseThis article is copyrighted material, (c)2003-2005 by Michael Dunn. I realize this isn't going to stop people from copying it all around the 'net, but I have to say it anyway. If you are interested in doing a translation of this article, please email me to let me know. I don't foresee denying anyone permission to do a translation, I would just like to be aware of the translation so I can post a link to it here. The demo code that accompanies this article is released to the public domain. I release it this way so that the code can benefit everyone. (I don't make the article itself public domain because having the article available only on CodeProject helps both my own visibility and the CodeProject site.) If you use the demo code in your own application, an email letting me know would be appreciated (just to satisfy my curiosity about whether folks are benefiting from my code) but is not required. Attribution in your own source code is also appreciated but not required. Revision History
Series Navigation: « Part II (WTL GUI Base Classes) | » Part IV (Dialogs and Controls) | ||||||||||||||||||||