自从作为Windows 95的通用控件出现以来,工具条和状态条就变成了很普遍的事物。由于MFC支持浮动的工具条从而使它们更受欢迎。随着通用控件的更新,Rebars(最初被称为Coollbar)使得工具条有了另一种展示方式。在第三部分,我将介绍WTL对这些控制条的支持和如何在你的程序中使用它们。
主窗口的工具条和状态条 CFrameWindowImpl有三个HWND类型的成员变量在窗口创建时被初始化,我们已经见过m_hWndClient,它是填充主窗口客户区的“视图”窗口的句柄,现在我们遇到了另外两个:
·m_hWndToolBar: 工具条或Rebar的窗口句柄
·m_hWndStatusBar: 状态条的窗口句柄
CFrameWindowImpl只支持一个工具条,也没有像MFC那样的可多点停靠的工具条,如果你想使用多个工具条又不想修改CFrameWindowImpl的内部代码,你就需要使用Rebar。我将介绍它们二者并演示如何使用应用程序向导添加工具条和Rebar。
CFrameWindowImpl::OnSize()消息响应函数调用了UpdateLayout(),UpdateLayout()做两件事:从新定位所有控制条和改变视图窗口的大小使之填充整个客户区。实际工作是由UpdateBarsPosition()完成的,UpdateLayout()只是调用了该函数。实现的代码相当简单,向工具条和状态条发送WM_SIZE消息,由这些控制条的默认窗口处理过程将它们定位到主窗口的顶部或底部。
当你告诉应用程序向导给你的窗口添加工具条和状态条时,向导就在CMainFrame::OnCreate()中添加了创建它们的代码。现在我们来看看这些代码,当然是为了再写一个时钟程序。
向导为工具条和状态条生成得代码 我们将开始一个新的工程,让向导为主窗口创建工具条和状态条。首先创建一个名为WTLClock2的新工程,在向导的第一页,选SDI并使“生成CPP文件”检查框被选中:
在第二页,取消Rebar使向导仅仅创建一个普通的工具条:
从第二部分的程序中复制相应的代码,新程序看起来是这样的:
CMainFraCMainFrame 如何创建工具条和状态条 在这个例子中,向导向CMainFrame::OnCreate()函数添加了更多的代码,这些代码的作用就是创建控制条并通知CUpdateUI更新工具条上的按钮。
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; } |
这是新添加的代码的开始部分,CFrameWindowImpl::CreateSimpleToolBar()函数使用资源IDR_MAINFRAME创建工具条并将其句柄赋值给m_hWndToolBar,下面是CreateSimpleToolBar()函数的代码:
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); } |
参数:
·nResourceID
工具条资源得ID。如果使用默认值0作为参数,程序将使用DECLARE_FRAME_WND_CLASS宏指定得资源,这里使用的IDR_MAINFRAME是向导生成的代码。
·dwStyle
工具条的类型或样式。默认值ATL_SIMPLE_TOOLBAR_STYLE被定义为TBSTYLE_TOOLTIPS,子窗口和可见三种风格的结合,这使得鼠标移到按钮上时工具条会弹出工具提示。
·nID
工具条的窗口ID,通常都会使用默认值。
CreateSimpleToolBar()首先检查是否已经创建了一个工具条,然后调用CreateSimpleToolBarCtrl()函数创建工具条控制,CreateSimpleToolBarCtrl()返回的工具条控制句柄保存在m_hWndToolBar中。CreateSimpleToolBarCtrl()负责读出资源并创建相应的工具条按钮,然后返回工具条窗口的句柄。这部分的代码相当长,我不在这里做具体介绍,如果你对此感兴趣得话何以在atlframe.h中找到这些代码。
OnCreate()函数接下来会调用CFrameWindowImpl::CreateSimpleStatusBar()函数,此函数创建状态条并将句柄存在m_hWndStatusBar,下面是该函数的代码:
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); } |
显示在状态条的文字是从字符串资源中装载的,这个函数的参数是:
·nTextID
用于在状态条上显示的字符串的资源ID,向导生成的ATL_IDS_IDLEMESSAGE对应的字符串是“Ready”。
·dwStyle
状态条的样式。默认值包含了SBARS_SIZEGRIP风格,这使得状态条的右下角会显示一个改变窗口大小的标志。
·nID
状态条的窗口ID,通常都会使用默认值。
CreateSimpleStatusBar()调用另外一个重载函数创建状态条:
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); } |
这个重载的版本首先检查是否已经创建了状态条,然后调用CreateStatusWindow()创建状态条,状态条的句柄存放在m_hWndStatusBar中。