(转)WTL入门(3)---工具条和状态条

源代码下载:http://download.csdn.net/source/3522797

Toolbars and Status Bars in a Frame

CFrameWindowImpl包含三个HWND对象,其中一个m_hWndClient上节已经讲过,另外两个m_hWndToolBar用于表示工具条句柄,m_hWndStatusBar用于状态条句柄。
CFrameWindowImpl仅支持一个工具条,不能像MFC那样直接支持多个可停靠的工具条。如果想实现这样的效果,需要使用Rebar。
CFrameWindowImpl::OnSize()将调用UpdateLayout()做两件事情:1、定位bars;2、缩放view窗口以填充视图区域。UpdateLayout()调用UpdateBarsPosition()执行实际的工作,它仅仅发送WM_SIZE到已创建的工具条和状态条,默认处理是把工具条移动Frame窗口的顶端,把状态条移至Frame窗口的低端。
AppWizard可以自动生成工具条和状态条。

How CMainFrame creates the bars

AppWizard会自动生成一些代码,用于创建Bars以及告诉CUpdateUI更新toolbar的buttons。

[cpp]  view plain copy
  1. LRESULT OnCreate(UINT /*uMsg*/WPARAM /*wParam*/LPARAM /*lParam*/BOOL/*bHandled*/)  
  2. {  
  3.     // 通过工具条资源 IDR_MAINFRAME 创建新的工具条  
  4.     CreateSimpleToolBar();  
  5.   
  6.     CreateSimpleStatusBar();  
  7.   
  8.     m_hWndClient = m_view.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, WS_EX_CLIENTEDGE);  
  9.   
  10.     UIAddToolBar(m_hWndToolBar);  
  11.     UISetCheck(ID_VIEW_TOOLBAR, 1);  
  12.     UISetCheck(ID_VIEW_STATUS_BAR, 1);  
  13.   
  14.     // register object for message filtering and idle updates  
  15.     CMessageLoop* pLoop = _Module.GetMessageLoop();  
  16.     ATLASSERT(pLoop != NULL);  
  17.     pLoop->AddMessageFilter(this);  
  18.     pLoop->AddIdleHandler(this);  
  19.   
  20.     return 0;  
  21. }  

下面是CFrameWindowImpl::CreateSimpleToolBar()的源代码

[cpp]  view plain copy
  1.     BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)  
  2.     {  
  3.         if(nResourceID == 0)  
  4.             nResourceID = T::GetWndClassInfo().m_uCommonResourceID;  
  5. #ifndef _WIN32_WCE  
  6.         ATLASSERT(!::IsWindow(m_hWndToolBar));  
  7.         m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, dwStyle, nID);  
  8.         return (m_hWndToolBar != NULL);  
  9. #else // CE specific  
  10.         HWND hWnd= T::CreateSimpleToolBarCtrl(m_hWndCECommandBar, nResourceID, TRUE, dwStyle, nID);  
  11.         return (hWnd != NULL);  
  12. #endif // _WIN32_WCE  
  13.     }  
nResourceID
工具条资源ID。默认值0意味着用 DECLARE_FRAME_WND_CLASS macro指定的资源。即AppWizard自动生成的 IDR_MAINFRAME.
dwStyle
工具条风格。 默认值  ATL_SIMPLE_TOOLBAR_STYLE 表示普通可见的,鼠标放在按钮上时有toolTip。
nID
Window ID for the toolbar, you will usually use the default value.

CreateSimpleToolBar()检查这个工具条有没有已经被创建,然后调用 CreateSimpleToolBarCtrl() 创建控件,并返回控件句柄存入m_hWndToolBar。CreateSimpleToolBarCtrl() 读取资源并逐个创建按钮,然后返回toolbar窗口句柄。
以下是CreateSimpleToolBar的实现代码:

[cpp]  view plain copy
  1. BOOL CFrameWindowImpl::CreateSimpleStatusBar(  
  2.     LPCTSTR lpstrText,  
  3.     DWORD dwStyle = ... SBARS_SIZEGRIP,  
  4.     UINT nID = ATL_IDW_STATUS_BAR)  
  5. {  
  6.     ATLASSERT(!::IsWindow(m_hWndStatusBar));  
  7.     m_hWndStatusBar = ::CreateStatusWindow(dwStyle, lpstrText, m_hWnd, nID);  
  8.     return (m_hWndStatusBar != NULL);  
  9. }  

检查状态条是否已经创建,调用CreateStatusWindow创建状态条,并把状态条句柄存入hWndStatusBar。

Showing and hiding the bars

CMainFrame 在 “视图”菜单下有两个命令,用于显示 / 隐藏工具栏和状态栏。
其中工具栏的命令响应代码如下:

[cpp]  view plain copy
  1. // 切换工具栏显示或隐藏,切换命令栏显示菜单状态,调用UpdateLayout定位命令栏位置(显示时)并更新视图区域大小  
  2. LRESULT CMainFrame::OnViewToolBar(WORD /*wNotifyCode*/WORD /*wID*/,   
  3.                                   HWND /*hWndCtl*/BOOL/*bHandled*/)  
  4. {  
  5.     BOOL bVisible = !::IsWindowVisible(m_hWndToolBar);  
  6.     ::ShowWindow(m_hWndToolBar, bVisible ? SW_SHOWNOACTIVATE : SW_HIDE);  
  7.     UISetCheck(ID_VIEW_TOOLBAR, bVisible);  
  8.     UpdateLayout();  
  9.     return 0;  
  10. }  

Built-in features of the bars

MFC为工具栏和状态栏提供了一些好的特性。WTL的CFrameWindowImpl也实现了相应的特性,如tooltip和flyby help:

(转)WTL入门(3)---工具条和状态条_第1张图片(转)WTL入门(3)---工具条和状态条_第2张图片

CFrameWindowImplBase 有两个消息处理用于实现这些特性。OnMenuSelect() 处理消息WM_MENUSELECT,它像MFC一样查找flyby help字符串(从字符串资源中加载与当前选择的菜单项同ID的字符串,并搜索"\n"字符,用\n之前的字符串作为flyby help字符串)。OnToolTipTextA()和OnToolTipTextW()处理消息TTN_GETDISPINFOA 和TTN_GETDISPINFOW ,分别为工具栏按钮提供Tooltip 文本,它用与OnMenuSelect一样的方法加载字符串,但是它用\n之后的文字作为ToolTip text。
注意:在WTL7.0/7.1中,OnMenuSelect() 和 OnToolTipTextA() 不是DBCS(双字节字符集)安全的,在搜索\n字符时,它们不检查DBCS的lead/trail(前导/后继)字节。

Creating a toolbar with a different style

你可以通过改变CreateSimpleToolBar ()中第二个参数的值,实现改变工具栏的风格。

[cpp]  view plain copy
  1. CreateSimpleToolBar ( 0, ATL_SIMPLE_TOOLBAR_STYLE |   
  2.                                TBSTYLE_FLAT | TBSTYLE_LIST );  

The Toolbar Editor

AppWizard 会自动为我们生成一个工具条,只有帮助按钮是实现了的。我们可以向MFC工程一样修改工具条。此处略。
修改工具栏如下所示:

(转)WTL入门(3)---工具条和状态条_第3张图片

  • IDC_CP_COLORS: 改变视图颜色为CodeProject颜色
  • IDC_BW_COLORS: 改变视图为白色背景,黑色前景的颜色
  • ID_VIEW_STATUS_BAR: 显示或隐藏状态栏
  • ID_VIEW_TOOLBAR: 显示或隐藏工具栏

前两个按钮的ID是新添的,绑定命令消息要使用宏COMMAND_ID_HANDLER_EX 。

UI Updating Toolbar Buttons

AppWizard生成的CMainFrame已经包含了一部分的UI更新处理(选中和非选中工具栏和状态栏菜单按钮),如下:

[cpp]  view plain copy
  1. BEGIN_UPDATE_UI_MAP(CMainFrame)  
  2.     UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP)  
  3.     UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP)  
  4. END_UPDATE_UI_MAP()  

我们的时钟程序在工具栏上也有这两个ID,因此我们需要添加宏UPDUI_TOOLBAR,以绑定工具栏对应按钮的更新:

[cpp]  view plain copy
  1. BEGIN_UPDATE_UI_MAP(CMainFrame)  
  2.     UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP | UPDUI_TOOLBAR)  
  3.     UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP | UPDUI_TOOLBAR)  
  4. END_UPDATE_UI_MAP()  

另外,还有两个函数用于更新工具栏按钮,AppWizard生成的代码会调用它们的。 

Enabling toolbar UI updating

CMainFrame::OnCreate()函数里,你可以看到一块代码用于初始化工具栏和状态栏菜单状态:

[cpp]  view plain copy
  1. LRESULT CMainFrame::OnCreate( ... )  
  2. {  
  3. // ...  
  4.     m_hWndClient = m_view.Create(...);  
  5.    
  6.     UIAddToolBar(m_hWndToolBar);  
  7.     UISetCheck(ID_VIEW_TOOLBAR, 1);  
  8.     UISetCheck(ID_VIEW_STATUS_BAR, 1);  
  9. // ...  
  10. }  

其中UIAddToolBar()把工具栏的句柄传递给CUpdateUI,因此当需要更新按钮状态时它知道往哪个窗口发送消息。另一个重要的调用是OnIdle() :

[cpp]  view plain copy
  1. BOOL CMainFrame::OnIdle()  
  2. {  
  3.     UIUpdateToolBar();  
  4.     return FALSE;  
  5. }  

当消息队列中没有消息时,CMessageLoop::Run() 将重复调用OnIdle() 。UIUpdateToolBar() 通过Update UI map,搜索带UPDUI_TOOLBAR 标志的那些调用UISetCheck()改变的元素,并且因此改变按钮状态。注意:我们仅仅更新了push menu元素的状态,不需要去做这两步,因为CUpdateUI 处理消息WM_INITMENUPOPUP 并且当消息送达时直接更新了菜单状态。
对于菜单栏的更新,要使用
UIAddMenuBar() 和 UIUpdateMenuBar()。

Using a Rebar Instead of a Plain Toolbar

CFrameWindowImpl 支持使用Rebar使我们的程序看起来像Internet Explorer。(在用Appwizard创建新工程时,选择使用Rebar)
(转)WTL入门(3)---工具条和状态条_第4张图片
下面是AppWizard生成的创建Rebar的相关代码:

[cpp]  view plain copy
  1. LRESULT CMainFrame::OnCreate(...)  
  2. {  
  3.     HWND hWndToolBar = CreateSimpleToolBarCtrl ( m_hWnd,   
  4.                            IDR_MAINFRAME, FALSE,   
  5.                            ATL_SIMPLE_TOOLBAR_PANE_STYLE );  
  6.    
  7.     CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);  
  8.     AddSimpleReBarBand(hWndToolBar);  
  9. // ...  
  10. }  

它首先使用一个不同的风格ATL_SIMPLE_TOOLBAR_PANE_STYLE创建一个toolbar,与ATL_SIMPLE_TOOLBAR_STYLE相比,ATL_SIMPLE_TOOLBAR_PANE_STYLE增加了CCS_NOPARENTALIGN,它是必须的。
CreateSimpleReBar()创建一个Rebar,并把其句柄存入m_hWndToolBar,然后调用AddSimpleReBarBand()为这个Rebar添加一个Band,并且告诉Rebar,这个Band已经包含了这个工具栏。
CMainFrame::OnViewToolBar() 也是不一样的。它隐藏包含这个工具栏的Band,而不是这个Rebar(这样会隐藏整个rebar,而不仅仅是这一个Toolbar)。
如果你想有多个工具条,就像Appwizard生成的代码一样,在OnCreate()中调用AddSimpleReBarBand()。既然CFrameWindowImpl使用标准的Rebar控件,它不支持可停靠的工具栏。

Multi-Pane Status Bars

WTL提供了一个实现多面板的状态栏类CMultiPaneStatusBarCtrl。它支持有限的UI更新,当PopUP 菜单显示时,默认面板会被拉伸到与状态栏同宽以显示flyby help文字。
首先要在CMainFrame类中声明一个变量

[cpp]  view plain copy
  1. class CMainFrame : public ...  
  2. {  
  3. //...  
  4. protected:  
  5.     CMultiPaneStatusBarCtrl m_wndStatusBar;  
  6. };  

然后,在OnCreate()中创建bar并设置UI更新

[cpp]  view plain copy
  1. m_hWndStatusBar = m_wndStatusBar.Create ( *this );  
  2.     UIAddStatusBar ( m_hWndStatusBar );  

CreateSimpleStatusBar()一样,我们同样把句柄存到m_hWndStatusBar。
下一步,调用CMultiPaneStatusBarCtrl::SetPanes()设置面板:

[cpp]  view plain copy
  1. BOOL SetPanes(int* pPanes, int nPanes, bool bSetText = true);  

参数描述如下:
pPanes :面板ID数组
nPanes :面板个数   
bSetText :如果为true, 所有盘子立即显示字符串. 解释如下. 
面板IDs,既可以是ID_DEFAULT_PANE来创建用于显示flyby help 的面板,也可以是字符串表中的一组字符串的IDs. 对于无默认面板的情况,WTL加载匹配ID的字符串并计算它们的宽度,然后为其对应的面板设置同样的宽度。与MFC使用的逻辑相同。
bSetText 控制面板是否立即显示字符串。 如果为true, SetPanes() 在每一个盘子里都显示字符串, 否则留空.

[cpp]  view plain copy
  1. // Create the status bar panes.  
  2. int anPanes[] = { ID_DEFAULT_PANE, IDPANE_STATUS,   
  3.                   IDPANE_CAPS_INDICATOR };  
  4.    
  5.     m_wndStatusBar.SetPanes ( anPanes, 3, false );  

IDPANE_STATUS的字符串是“@@@@”,它用于使这个盘子有足够的宽度显示时钟状态:“Running”或“Stopped”。就像MFC一样,首先需要计算你的这个盘子需要多大的空间。IDPANE_CAPS_INDICATOR用于显示“CAPS”

UI updating the panes

为了更新状态栏文字,需要写入UI更新路由:

[cpp]  view plain copy
  1. BEGIN_UPDATE_UI_MAP(CMainFrame)  
  2.         //...  
  3.         UPDATE_ELEMENT(1, UPDUI_STATUSBAR)  // clock status  
  4.         UPDATE_ELEMENT(2, UPDUI_STATUSBAR)  // CAPS indicator  
  5.     END_UPDATE_UI_MAP()  

第一个参数是盘子的索引,不是ID。如果你需要重排列这些盘子,你需要更新设个参数以适应其对应的顺序。
我们在SetPanes的第三个参数传入的是false,因此所有盘子初始化均为空。下一步为指定盘子设置初始文字。

[cpp]  view plain copy
  1. // Set the initial text for the clock status pane.  
  2.     UISetText ( 1, _T("Running") );  

UISetText() 是唯一一个状态条UI更新函数。
最后,我们需要在CMainFrame::OnIdle() 中添加调用UIUpdateStatusBar() ,使状态栏能够在空闲时间更新。

[cpp]  view plain copy
  1. BOOL CMainFrame::OnIdle()  
  2. {  
  3.     // ...  
  4.     UIUpdateToolBar();  
  5.     UIUpdateStatusBar();  
  6.     return FALSE;  
  7. }  

当使用UIUpdateStatusBar() 时CUpdateUI 会出现一个问题:在使用UISetText()后菜单文字并没有被更新。这个问题在WTL7.1中还存在。
最后,我们需要检查Caps Lock状态并更新2号盘的文字,在OnIdle()中实现,只要程序处在空闲时间就去检查此状态。

[cpp]  view plain copy
  1. BOOL CMainFrame::OnIdle()  
  2. {  
  3.     // Check the current Caps Lock state, and if it is on, show the  
  4.     // CAPS indicator in pane 2 of the status bar.  
  5.     if ( GetKeyState(VK_CAPITAL) & 1 )  
  6.         UISetText ( 2, CString(LPCTSTR(IDPANE_CAPS_INDICATOR)) );  
  7.     else  
  8.         UISetText ( 2, _T("") );  
  9.    
  10.     UIUpdateToolBar();  
  11.     UIUpdateStatusBar();  
  12.     return FALSE;  
  13. }  

第一个UISetText()使用从字符表中加载的“CAPS”字符串,使用CString以实现多格式支持。

原文:WTL for MFC Programmers, Part III - Toolbars and Status Bars


转自:http://blog.csdn.net/wcyoot/article/details/6645176

你可能感兴趣的:((转)WTL入门(3)---工具条和状态条)