📄 wtl for mfc programmers, part iii - toolbars and status bars - wtl.htm
字号:
<html>
<head>
<title>WTL for MFC Programmers, Part III - Toolbars and Status Bars</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<body bgcolor="#33CCCC" text="#000000">
<p align="center"><b><font style="FONT-SIZE: 16pt" size="4" color="#0033CC">WTL
for MFC Programmers, Part III - Toolbars and Status Bars</font></b><br>
<br>
</p>
<p align="left">原作 :<b><font color="#CC3366">Michael Dunn</font></b> [<a href="http://www.codeproject.com/wtl/WTL4MFC3.asp">英文原文</a>]<br>
翻译 :<a href="mailto:inte2000@163.com">Orbit(桔皮干了)</a> [<a href="http://www.winmsg.com/cn/orbit.htm">http://www.winmsg.com/cn/orbit.htm</a>]</p>
<p align="left"><a href="demo/WTL4MFC3_demo.zip">下载演示程序代码</a></p>
<H2><font color="#FFFF66">本章内容</font></H2>
<UL>
<LI><A
href="#intro">介绍</A>
<LI><A
href="#barsinframe">主窗口的工具条和状态条(Toolbars和Status Bars)</A>
<LI><A
href="#appwiztb">向导为工具条和状态条生成的代码</A>
<UL>
<LI><A href="#createbars">CMainFrame 如何创建工具条和状态条</A>
<LI><A
href="#barsshowhide">显示和隐藏工具条和状态条</A>
<LI><A
href="#builtins">工具条和状态条的内在特征</A>
<LI><A
href="#diffstyles">创建不同样式的工具条</A> </LI>
</UL>
<LI><A href="#tbeditor">工具条编辑器</A>
<LI><A
href="#uiudpatebtns">工具条按钮的UI状态更新(UI Updating)</A>
<UL>
<LI><A
href="#enabletbupdate">使一个工具条支持UI状态更新</A> </LI>
</UL>
<LI><A href="#userebar">使用Rebar代替简单的工具条</A>
<LI><A
href="#multipanesb">多窗格的状态条</A>
<UL>
<LI><A
href="#uiupdatesb">窗格的UI状态更新</A> </LI>
</UL>
<LI><A href="#upnext">承上启下:有关对话框的话题</A>
<LI><A
href="#references">引用和参考</A>
<LI><A
href="#revisionhistory">修改记录</A> </LI>
</UL>
<H2><A name=intro></A><font color="#FFFF66">对第三部分的介绍</font></H2>
<P>自从作为Windows 95的通用控件出现以来,工具条和状态条就变成了很普遍的事物。由于MFC支持浮动的工具条从而使它们更受欢迎。随着通用控件的更新,Rebars(最初被称为Coollbar)使得工具条有了另一种展示方式。在第三部分,我将介绍WTL对这些控制条的支持和如何在你的程序中使用它们。</P>
<H2><A name=barsinframe></A><font color="#FFFF66">主窗口的工具条和状态条</font></H2>
<P>CFrameWindowImpl有三个HWND类型的成员变量在窗口创建时被初始化,我们已经见过m_hWndClient,它是填充主窗口客户区的“视图”窗口的句柄,现在我们遇到了另外两个:</P>
<UL>
<LI>m_hWndToolBar: 工具条或Rebar的窗口句柄
<LI>m_hWndStatusBar: 状态条的窗口句柄</LI>
</UL>
<P>CFrameWindowImpl只支持一个工具条,也没有像MFC那样的可多点停靠的工具条,如果你想使用多个工具条又不想修改CFrameWindowImpl的内部代码,你就需要使用Rebar。我将介绍它们二者并演示如何使用应用程序向导添加工具条和Rebar。<br>
</P>
<P>CFrameWindowImpl::OnSize()消息响应函数调用了UpdateLayout(),UpdateLayout()做两件事:从新定位所有控制条和改变视图窗口的大小使之填充整个客户区。实际工作是由UpdateBarsPosition()完成的,UpdateLayout()只是调用了该函数。实现的代码相当简单,向工具条和状态条发送WM_SIZE消息,由这些控制条的默认窗口处理过程将它们定位到主窗口的顶部或底部。<br>
</P>
<P>当你告诉应用程序向导给你的窗口添加工具条和状态条时,向导就在CMainFrame::OnCreate()中添加了创建它们的代码。现在我们来看看这些代码,当然是为了再写一个时钟程序。</P>
<H2><A name=appwiztb></A><font color="#FFFF66">向导为工具条和状态条生成得代码</font></H2>
<P>我们将开始一个新的工程,让向导为主窗口创建工具条和状态条。首先创建一个名为WTLClock2的新工程,在向导的第一页,选SDI并使“生成CPP文件”检查框被选中:</P>
<P><IMG height=387 alt=" [AppWizard pg 1 - 22K] "
src="images/appwiz31.png"
width=477 align=bottom border=0></P>
<P>在第二页,取消Rebar使向导仅仅创建一个普通的工具条:</P>
<P><IMG height=387 alt=" [AppWizard pg 2 - 21K] "
src="images/appwiz32.png"
width=477 align=bottom border=0></P>
<P>从第二部分的程序中复制相应的代码,新程序看起来是这样的:<br>
</P>
<P><img height=187 alt=" [default toobar - 5K] "
src="images/defaultapp3.png"
width=267 align=bottom border=0></P>
<H3><A name=createbars></A><font color="#FFFF66">CMainFraCMainFrame 如何创建工具条和状态条</font></H3>
<P><br>
在这个例子中,向导向CMainFrame::OnCreate()函数添加了更多的代码,这些代码的作用就是创建控制条并通知CUpdateUI更新工具条上的按钮。</P>
<PRE><font color="#0000FF">LRESULT CMainFrame::OnCreate(UINT <SPAN class=cpp-comment>/*uMsg*/</SPAN>, WPARAM <SPAN class=cpp-comment>/*wParam*/</SPAN>,
LPARAM <SPAN class=cpp-comment>/*lParam*/</SPAN>, BOOL& <SPAN class=cpp-comment>/*bHandled*/</SPAN>)
{
CreateSimpleToolBar();
CreateSimpleStatusBar();
m_hWndClient = m_view.Create(...);
<SPAN class=cpp-comment>// ...</SPAN>
<SPAN class=cpp-comment>// register object for message filtering and idle updates</SPAN>
CMessageLoop* pLoop = _Module.GetMessageLoop();
ATLASSERT(pLoop != NULL);
pLoop->AddMessageFilter(<SPAN class=cpp-keyword>this</SPAN>);
pLoop->AddIdleHandler(<SPAN class=cpp-keyword>this</SPAN>);
<SPAN class=cpp-keyword>return</SPAN> <SPAN class=cpp-literal>0</SPAN>;
}</font></PRE>
<P>这是新添加的代码的开始部分,CFrameWindowImpl::CreateSimpleToolBar()函数使用资源IDR_MAINFRAME创建工具条并将其句柄赋值给m_hWndToolBar,下面是CreateSimpleToolBar()函数的代码:</P>
<PRE><font color="#0000FF">BOOL CFrameWindowImpl::CreateSimpleToolBar(
UINT nResourceID = <SPAN class=cpp-literal>0</SPAN>,
DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE,
UINT nID = ATL_IDW_TOOLBAR)
{
ATLASSERT(!::IsWindow(m_hWndToolBar));
<SPAN class=cpp-keyword>if</SPAN>(nResourceID == <SPAN class=cpp-literal>0</SPAN>)
nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
m_hWndToolBar = T::CreateSimpleToolBarCtrl(m_hWnd, nResourceID, TRUE, <BR> dwStyle, nID);
<SPAN class=cpp-keyword>return</SPAN> (m_hWndToolBar != NULL);
}</font></PRE>
<P>参数:</P>
<DL>
<DT><font color="#FF6600">nResourceID</font>
<DD>工具条资源得ID。如果使用默认值0作为参数,程序将使用DECLARE_FRAME_WND_CLASS宏指定得资源,这里使用的IDR_MAINFRAME是向导生成的代码。
<DT><font color="#FF6633">dwStyle </font>
<DD>工具条的类型或样式。默认值ATL_SIMPLE_TOOLBAR_STYLE被定义为TBSTYLE_TOOLTIPS,子窗口和可见三种风格的结合,这使得鼠标移到按钮上时工具条会弹出工具提示。
<DT><font color="#FF9966">nID </font>
<DD>工具条的窗口ID,通常都会使用默认值。</DD>
</DL>
<P>CreateSimpleToolBar()首先检查是否已经创建了一个工具条,然后调用CreateSimpleToolBarCtrl()函数创建工具条控制,CreateSimpleToolBarCtrl()返回的工具条控制句柄保存在m_hWndToolBar中。CreateSimpleToolBarCtrl()负责读出资源并创建相应的工具条按钮,然后返回工具条窗口的句柄。这部分的代码相当长,我不在这里做具体介绍,如果你对此感兴趣得话何以在atlframe.h中找到这些代码。</P>
<P>OnCreate()函数接下来会调用CFrameWindowImpl::CreateSimpleStatusBar()函数,此函数创建状态条并将句柄存在m_hWndStatusBar,下面是该函数的代码:</P>
<PRE><font color="#0000FF">BOOL CFrameWindowImpl::CreateSimpleStatusBar(
UINT nTextID = ATL_IDS_IDLEMESSAGE,
DWORD dwStyle = ... SBARS_SIZEGRIP,
UINT nID = ATL_IDW_STATUS_BAR)
{
TCHAR szText[<SPAN class=cpp-literal>128</SPAN>]; <SPAN class=cpp-comment>// max text lentgth is 127 for status bars</SPAN>
szText[<SPAN class=cpp-literal>0</SPAN>] = <SPAN class=cpp-literal>0</SPAN>;
::LoadString(_Module.GetResourceInstance(), nTextID, szText, <SPAN class=cpp-literal>128</SPAN>);
<SPAN class=cpp-keyword>return</SPAN> CreateSimpleStatusBar(szText, dwStyle, nID);
}</font></PRE>
<P>显示在状态条的文字是从字符串资源中装载的,这个函数的参数是:</P>
<DL>
<DT><font color="#FF6633">nTextID</font>
<DD>用于在状态条上显示的字符串的资源ID,向导生成的ATL_IDS_IDLEMESSAGE对应的字符串是“Ready”。
<DT><font color="#FF6633">dwStyle </font>
<DD>状态条的样式。默认值包含了SBARS_SIZEGRIP风格,这使得状态条的右下角会显示一个改变窗口大小的标志。
<DT><font color="#FF6666">nID</font>
<DD>状态条的窗口ID,通常都会使用默认值。</DD>
</DL>
<P>CreateSimpleStatusBar()调用另外一个重载函数创建状态条:</P>
<PRE><font color="#0000FF">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);
<SPAN class=cpp-keyword>return</SPAN> (m_hWndStatusBar != NULL);
}</font></PRE>
<P>这个重载的版本首先检查是否已经创建了状态条,然后调用CreateStatusWindow()创建状态条,状态条的句柄存放在m_hWndStatusBar中。</P>
<H3><A name=barsshowhide></A><font color="#FFFF66">显示和隐藏工具条和状态条</font></H3>
<P>CMainFrame类也有一个视图菜单,它有两个命令:显示/隐藏工具条和状态条,它们的ID是ID_VIEW_TOOLBAR和ID_VIEW_STATUS_BAR。CMainFrame类有这两个命令的响应函数,分别显示和隐藏相应的控制条,下面是OnViewToolBar()函数的代码:</P>
<PRE><font color="#0000FF">LRESULT CMainFrame::OnViewToolBar(WORD <SPAN class=cpp-comment>/*wNotifyCode*/</SPAN>, WORD <SPAN class=cpp-comment>/*wID*/</SPAN>,
HWND <SPAN class=cpp-comment>/*hWndCtl*/</SPAN>, BOOL& <SPAN class=cpp-comment>/*bHandled*/</SPAN>)
{
BOOL bVisible = !::IsWindowVisible(m_hWndToolBar);
::ShowWindow(m_hWndToolBar, bVisible ? SW_SHOWNOACTIVATE : SW_HIDE);
UISetCheck(ID_VIEW_TOOLBAR, bVisible);
UpdateLayout();
<SPAN class=cpp-keyword>return</SPAN> <SPAN class=cpp-literal>0</SPAN>;
}</font></PRE>
<P>这些代码翻转控制条的显示状态,相应的翻转View|Toolbar菜单上的检查标记,然后调用UpdateLayout()重新定位控制条并改变视图窗口的大小。</P>
<H3><A name=builtins></A><font color="#FFFF66">工具条和状态条的内在特征</font></H3>
<P>MFC的框架提供了很多好的特性,例如工具条按钮的工具提示和菜单项的掠过式帮助。WTL中相对应的功能实现在CFrameWindowImpl类中。下面的屏幕截图显示了工具提示和掠过式帮助。</P>
<P><IMG height=233 alt=" [Toolbar button tooltip - 4K] "
src="images/tbtooltip3.png"
width=291 align=bottom border=0> <IMG height=233
alt=" [Status bar flyby help - 5K] "
src="images/tbflyby3.png"
width=291 align=bottom border=0></P>
<P>CFrameWindowImplBase类有两个消息相应函数用来实现这些功能,OnMenuSelect()处理WM_MENUSELECT消息,它像MFC那样查找掠过式帮助的字符串:首先装载与菜单资源ID相同的字符串资源,在字符串中查找
\n 字符,使用\n之前的内容作为掠过帮助的内容。OnToolTipTextA() 和 OnToolTipTextW() 函数分别响应 TTN_GETDISPINFOA消息和TTN_GETDISPINFOW消息,提供工具条按钮的工具提示。这两个处理函数和OnMenuSelect()函数一样装载相应的字符串,只是使用\n后面的字符串。(边注:OnMenuSelect()和OnToolTipTextA()函数对于DBCS字符是不安全的,因为它在查找\n字符时没有检查DBCS字符串的头部和尾部)下面是工具条及其关联的帮助字符串的例子:</P>
<P><IMG height=320 alt=" [Toolbar button and help string - 9K] "
src="images/tbbtntext3.png"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -