⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wtl for mfc programmers, part iii - toolbars and status bars - wtl.htm

📁 WT教程中文版 内有详细的介绍 包括各个方面
💻 HTM
📖 第 1 页 / 共 2 页
字号:
      width=502 align=bottom border=0></P>
      
<H3><A name=diffstyles></A><font color="#FFFF66">创建不同样式的工具条</font></H3>
      
<P>如果你不喜欢在工具条上显示3D按钮(尽管从可用性观点来看平面的界面元素是件糟糕的事情),你可以通过改变CreateSimpleToolBar()函数的参数来改变工具条的样式。例如,你可以在CMainFrame::OnCreate()使用如下代码创建一个IE风格的工具条:</P>
<PRE> <font color="#0000FF">   CreateSimpleToolBar ( <SPAN class=cpp-literal>0</SPAN>, ATL_SIMPLE_TOOLBAR_STYLE | 
                               TBSTYLE_FLAT | TBSTYLE_LIST );</font></PRE>
      
<P>如果你使用向导为你的程序添加了manifest文件,它就会在Windows XP系统上使用6.0版的通用控件,你不能选择按钮的类型,工具条会自动使用平面按钮即使你创建工具条时没有添加TBSTYLE_FLAT风格。</P>
<H2> <A name=tbeditor></A><font color="#FFFF66">工具条编辑器</font></H2>
      
<P>正如我们前面所见,向导为我们的程序创建了几个默认的按钮,当然只有About按钮有事件处理。你可以像在MFC的工程中一样使用工具条编辑器修改工具条资源,CreateSimpleToolBarCtrl()用这个工具条资源创建工具条。下面是向导生成的工具条在编辑器中的样子:</P>
      
<P><IMG height=211 alt=" [default toolbar in the editor - 7K] " 
      src="images/tbeditor3.png" 
      width=490 align=bottom border=0></P>
      
<P>对于我们的时钟程序,我们添加四个按钮,两个按钮用来改变视图窗口的颜色,另外两个用来显示/隐藏工具条和状态条。下面是我们的新工具条:</P>
      
<P><IMG height=175 alt=" [New toolbar buttons - 5K] " 
      src="images/newtb3.png" 
      width=438 align=bottom border=0></P>
      
<P>这些按钮是:</P>
      <UL>
        <LI>IDC_CP_COLORS: 将视图窗口颜色改为CodeProject网站的颜色
        <LI>IDC_BW_COLORS: 将视图窗口颜色改为黑白颜色
        <LI>ID_VIEW_STATUS_BAR: 显示或隐藏状态条 
        <LI>ID_VIEW_TOOLBAR: 显示或隐藏工具条 </LI></UL>
      
<P>前两个按钮都有相应的菜单项,它们都调用视图类的一个新函数SetColor(),向这个函数传递前景颜色和背景颜色,视图窗口用这两个参数改变窗口的显示。响应这两个按钮的处理函数与响应相应的菜单项的处理函数在使用COMMAND_ID_HANDLER_EX宏上没有区别,你可以查看例子工程的代码了解这些消息处理的细节。在下一节我将介绍状态条和工具条按钮的UI状态更新,使它们能够反映工具条或状态条当前的状态。</P>
      
<H2><A name=uiudpatebtns></A><font color="#FFFF66">工具条按钮的UI状态更新</font></H2>
      
<P>向导生成的代码已经为CMainFrame添加了对View|Toolbar和View|Status Bar两个菜单项的Check和Uncheck的UI更新处理。这和第二章的程序一样:对CMainFrame类的两个命令使用UI更新的宏:</P>
<PRE><font color="#0000FF">BEGIN_UPDATE_UI_MAP(CMainFrame)
    UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP)
    UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP)
END_UPDATE_UI_MAP()</font></PRE>
      
<P>我们的时钟程序的工具条按钮与对应的菜单项有相同的ID,所以第一步就是为每个宏添加UPDUI_TOOLBAR标志:</P>
<PRE><font color="#0000FF">BEGIN_UPDATE_UI_MAP(CMainFrame)
    UPDATE_ELEMENT(ID_VIEW_TOOLBAR, UPDUI_MENUPOPUP <B>| UPDUI_TOOLBAR</B>)
    UPDATE_ELEMENT(ID_VIEW_STATUS_BAR, UPDUI_MENUPOPUP <B>| UPDUI_TOOLBAR</B>)
END_UPDATE_UI_MAP()</font></PRE>
      
<P>还需要添加两个函数响应工具条按钮的更新,但幸运的是向导已经为我们做了,所以如果此时编译这个程序,菜单项和工具条按钮都会更新。</P>
      <H3><A name=enabletbupdate></A><font color="#FFFF66">使一个工具条支持UI状态更新</font></H3>
      
<P>如果查看CMainFrame::OnCreate()的代码你就会发现一段新的代码,这段代码设置了两个菜单项的初始状态:</P>
<PRE><font color="#0000FF">LRESULT CMainFrame::OnCreate( ... )
{
<SPAN class=cpp-comment>// ...</SPAN>
    m_hWndClient = m_view.Create(...);
 
    UIAddToolBar(m_hWndToolBar);
    UISetCheck(ID_VIEW_TOOLBAR, <SPAN class=cpp-literal>1</SPAN>);
    UISetCheck(ID_VIEW_STATUS_BAR, <SPAN class=cpp-literal>1</SPAN>);
<SPAN class=cpp-comment>// ...</SPAN>
}</font></PRE>
      
<P>UIAddToolBar()将工具条的窗口句柄传给CUpdateUI,所以当需要更新按钮的状态时CUpdateUI会向这个窗口发消息。另一个重要的调用位于OnIdle()中:</P>
<PRE><font color="#0000FF">BOOL CMainFrame::OnIdle()
{
    UIUpdateToolBar();
    <SPAN class=cpp-keyword>return</SPAN> FALSE;
}</font></PRE>
      
<P>当消息队列中没有消息等待时CMessageLoop::Run()就会调用OnIdle(),UIUpdateToolBar()遍历UI更新表,寻找那些带有UPDUI_TOOLBAR标志又被UISetCheck()之类的函数改变了状态的的界面元素(当然是工具条),相应的改变按钮的状态。需要注意得是如果更新弹出式菜单的状态就不需要做以上两步,因为CUpdateUI响应WM_INITMENUPOPUP消息,只有接到此消息时才更新菜单状态。</P>
      
<P>如果查看例子代码就会发现它也演示了如何更新框架窗口的菜单条上的顶级菜单项的状态。有一个菜单项是执行Start和Stop命令,起到开始和停止时钟的作用,当然这需要做一些不平常的事情:菜单条上的菜单项总是处于弹出状态。为了完整的介绍CUpdateUI我将它们也加进例子代码中,要了解它们可以查找对UIAddMenuBar()和UIUpdateMenuBar()两个函数的调用。</P> 
<H2><A name=userebar></A><font color="#FFFF66">使用Rebar代替简单的工具条</font></H2>
      
<P>CFrameWindowImpl也支持使用Rebar控件,使你的程序看起来像IE,使用Rebar也是在程序中使用多个工具条的一个方法(译者加:前面讲过,另一个方法就是修改WTL的源代码)。要使用Rebar需要在向导的第二页选上支持Rebar的检查框,如下所示:</P>
      
<P><IMG height=387 alt=" [AppWizard pg 2 with rebar checked - 21K] " 
      src="images/appwiz33.png" 
      width=477 align=bottom border=0></P>
      
<P>第二个例子工程WTLClock3就使用了Rebar控件,如果你正在跟着例子代码学习,那现在就打开WTLClock3。</P>
      
<P>你首先会注意到创建工具条的代码有些不同,出现这种感觉是因为我们在程序中使用了rebar。以下是相关的代码:</P>
<PRE><font color="#0000FF">LRESULT CMainFrame::OnCreate(...)
{
    HWND hWndToolBar = CreateSimpleToolBarCtrl ( m_hWnd, 
                           IDR_MAINFRAME, FALSE, 
                           ATL_SIMPLE_TOOLBAR_PANE_STYLE );
 
    CreateSimpleReBar(ATL_SIMPLE_REBAR_NOBORDER_STYLE);
    AddSimpleReBarBand(hWndToolBar);
<SPAN class=cpp-comment>// ...</SPAN>
}</font></PRE>
      
<P>代码从创建工具条开始,只是使用了不同的风格,也就是ATL_SIMPLE_TOOLBAR_PANE_STYLE,它定义在atlframe.h文件中,与ATL_SIMPLE_TOOLBAR_STYLE风格相似,只是附加了一些诸如CCS_NOPARENTALIGN之类的风格,这是使工具条作为Rebar的子窗口能够正常工作所必需的风格。</P>
<p>下一行代码是调用CreateSimpleReBar()函数,该函数创建Rebar控件并将句柄存到m_hWndToolBar中。接下来调用AddSimpleReBarBand()函数为Rebar创建一个条位并告诉Rebar这个条位上是一个工具条。<br>
</p>
<P><IMG height=206 alt=" [App with rebar - 4K] " 
      src="images/rebar3.png" 
      width=252 align=bottom border=0></P>
      
<P>CMainFrame::OnViewToolBar()函数也有些不同,它只隐藏Rebar上工具条所在的条位而不是隐藏m_hWndToolBar(如果隐藏m_hWndToolBar将隐藏整个Rebar而不仅仅是工具条)。</P>
      
<P>如果你使用多个工具条,只需像向导为我们生成的关于第一个工具条的代码那在OnCreate()创建它们并调用AddSimpleReBarBand()添加到Rebar就行了。CFrameWindowImpl使用标准的Rebar控件,不像MFC那样支持可停靠的工具条,你所能作得就是排列这些工具条在Rebar中的位置。</P>
<H2><A name=multipanesb></A><font color="#FFFF66">多窗格的状态条</font></H2>
      
<P>WTL另有一个状态条类实现多窗格的状态条,与MFC的默认的状态条一样有CAPS,LOCK和NUM LOCK指示器,这个类就是CMultiPaneStatusBarCtrl,在WTLClock3例子工程中演示了如何使用这个类。这个类支持有限的UI更新,当弹出式菜单被显示时有“Default”属性的窗格会延伸到整个状态条的宽度用于显示菜单的掠过式帮助。</P>
<p>第一步就是在CMainFrame中声明一个CMultiPaneStatusBarCtrl类型的成员变量:</p>
<PRE><SPAN class=cpp-keyword><font color="#0000FF">class</font></SPAN><font color="#0000FF"> CMainFrame : <SPAN class=cpp-keyword>public</SPAN> ...
{
<SPAN class=cpp-comment>//...</SPAN>
<SPAN class=cpp-keyword>protected</SPAN>:
    CMultiPaneStatusBarCtrl m_wndStatusBar;
};</font></PRE>
      
<P>接着在OnCreate()中创建状态条并这只UI更新:</P>
<PRE><font color="#0000FF">    m_hWndStatusBar = m_wndStatusBar.Create ( *<SPAN class=cpp-keyword>this</SPAN> );
    UIAddStatusBar ( m_hWndStatusBar );</font></PRE>
      
<P>就像CreateSimpleStatusBar()函数做得那样,我们也将状态条的句柄存放在m_hWndStatusBar中。</P>
      
<P>下一步就是调用CMultiPaneStatusBarCtrl::SetPanes()函数建立窗格:</P>
<PRE><font color="#0000FF">    BOOL SetPanes(<SPAN class=cpp-keyword>int</SPAN>* pPanes, <SPAN class=cpp-keyword>int</SPAN> nPanes, <SPAN class=cpp-keyword>bool</SPAN> bSetText = <SPAN class=cpp-keyword>true</SPAN>);</font></PRE>
      
<P>参数:</P>
      <DL>
        <DT>pPanes 
        <DD>存放窗格ID的数组 
        <DT>nPanes 
        <DD>窗格ID数组中元素的个数(译者加:就是窗格数) 
        <DT>bSetText 
        <DD>如果是true,所有的窗格被立即设置文字,这一点将在下面解释。 </DD></DL>
      
<P>窗格ID可以是ID_DEFAULT_PANE,此ID用于创建支持掠过式帮助的窗格,窗格ID也可以是字符串资源ID。对于非默认的窗格WTL装载这个ID对应的字符串并计算宽度,并将窗格设置为相应的宽度,这和MFC使用的逻辑是一样的。</P>
<p>bSetText控制着窗格是否立即显示相关的字符串,如果是true,SetPanes()显示每个窗格的字符串,否则窗格就被置空。</p>
<p>下面是我们对SetPanes()的调用:</p>
<PRE>    <font color="#0000FF"><SPAN class=cpp-comment>// Create the status bar panes.</SPAN>
<SPAN class=cpp-keyword>int</SPAN> anPanes[] = { ID_DEFAULT_PANE, IDPANE_STATUS, 
                  IDPANE_CAPS_INDICATOR };
 
    m_wndStatusBar.SetPanes ( anPanes, <SPAN class=cpp-literal>3</SPAN>, <SPAN class=cpp-keyword>false</SPAN> );</font></PRE>
      
<P>IDPANE_STATUS对应的字符串是“@@@@”,这样应该有足够的宽度(希望是)显示两个时钟状态字符串“Running”和“Stopped”。和MFC一样,你需要自己估算窗格的宽度,IDPANE_CAPS_INDICATOR对应的字符串是“CAPS”。</P>
      
<H3><A name=uiupdatesb></A><font color="#FFFF66">窗格的UI状态更新</font></H3>
      
<P>为了更新窗格上的文本,我们需要将相应的窗格添加到UI更新表:</P>
<PRE><font color="#0000FF">    BEGIN_UPDATE_UI_MAP(CMainFrame)
        <SPAN class=cpp-comment>//...</SPAN>
        UPDATE_ELEMENT(<SPAN class=cpp-literal>1</SPAN>, UPDUI_STATUSBAR)  <SPAN class=cpp-comment>// clock status</SPAN>
        UPDATE_ELEMENT(<SPAN class=cpp-literal>2</SPAN>, UPDUI_STATUSBAR)  <SPAN class=cpp-comment>// CAPS indicator</SPAN>
    END_UPDATE_UI_MAP()</font></PRE>
<P>这个宏的第一个参数是窗格的索引而不是ID,这很不幸,因为如果你重新排列了窗格,你要记得更新UI更新表。</P>
<p>由于我们在调用SetPanes()是第三个参数是false,所以窗格初始是空的。我们下一步要做得就是将时钟状态窗格的初始文本设为“Running”</p>
<PRE>    <font color="#0000FF"><SPAN class=cpp-comment>// Set the initial text for the clock status pane.</SPAN>
    UISetText ( <SPAN class=cpp-literal>1</SPAN>, _T(<SPAN class=cpp-string>"Running"</SPAN>) );</font></PRE>
      
<P>和前面一样,第一个参数是窗格的索引。UISetText()是状态条唯一支持的UI更新函数。</P>
      
<P>最后,在CMainFrame::OnIdle()中添加对UIUpdateStatusBar()函数的调用,使状态条的窗格能够在空闲时间被更新:</P>
<PRE><font color="#0000FF">BOOL CMainFrame::OnIdle()
{
    UIUpdateToolBar();
    <B>UIUpdateStatusBar();</B>
    <SPAN class=cpp-keyword>return</SPAN> FALSE;
}</font></PRE>
      
<P>当你使用UIUpdateStatusBar()时CUpdateUI的一个问题就暴露出来了--菜单项的文本在调用UISetText()后没有改变!如果你在看WTLClock3工程的代码,时钟的开始/停止菜单项被移到了Clock菜单,在菜单项命令的响应处理函数中设置菜单项的文本。无论如何,如果当前调用的是UIUpdateStatusBar(),那么对UISetText()的调用就不会起作用。我没有研究这个问题是否可以被修复,所以如果你打算改变菜单的文本,你需要留意这个地方。</P>
<p>最后,我们需要检查CAPS LOCK键的状态,更新相应的两个窗格。这些代码是通过OnIdle()被调用的,所以程序会在每次空闲时间检查它们的状态。
<PRE><font color="#0000FF">BOOL CMainFrame::OnIdle()
{
    <B><SPAN class=cpp-comment>// Check the current Caps Lock state, and if it is on, show the</SPAN>
    <SPAN class=cpp-comment>// CAPS indicator in pane 2 of the status bar.</SPAN>
    <SPAN class=cpp-keyword>if</SPAN> ( GetKeyState(VK_CAPITAL) &amp; <SPAN class=cpp-literal>1</SPAN> )
        UISetText ( <SPAN class=cpp-literal>2</SPAN>, CString(LPCTSTR(IDPANE_CAPS_INDICATOR)) );
    <SPAN class=cpp-keyword>else</SPAN>
        UISetText ( <SPAN class=cpp-literal>2</SPAN>, _T(<SPAN class=cpp-string>""</SPAN>) );</B>
 
    UIUpdateToolBar();
    UIUpdateStatusBar();
    <SPAN class=cpp-keyword>return</SPAN> FALSE;
}</font></PRE>
      
<P>第一次调用UISetText()时将从字符串资源中装载“CAPS”字符串,但是在CString的构造函数中使用了一个机灵的窍门(有充分的文档说明)。</P>
<p>在完成所有的代码之后,状态条看起来是这个样子:</p>
<P><IMG height=218 alt=" [Multipane status bar - 4K] " 
      src="images/multipanesb3.png" 
      width=265 align=bottom border=0></P>
      
<H2><A name=upnext></A><font color="#FFFF66">承上启下:有关对话框的话题</font></H2>
      
<P>在第四章我将介绍对话框的用法(包括ATL的类和WTL的增强功能),控件的包装类和WTL有关对话框消息处理的改进。</P>
      <H2><A name=references></A><font color="#FFFF66">引用和参考</font> </H2>
      
<P><A href="http://www.codeproject.com/wtl/multipanestatusbar.asp">"How to use 
  the WTL multipane status bar control"</A> by Ed Gadziemski 更详细的介绍了CMultiPaneStatusBarCtrl类的用法。
<H2><A name=revisionhistory></A><font color="#FFFF66">修改记录</font></H2>
      
<P>2003年4月11日,本文第一次发表。</P>
</body>
</html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -