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

📄 wtl for mfc programmers, part vii - splitter windows - wtl.htm

📁 MFC程序员的WTL指南,非常具体,WTL入门最好的书
💻 HTM
📖 第 1 页 / 共 3 页
字号:
      src="images/panecont7.png" 
      width=356 align=bottom border=0></P>
      
<H3><A name=pcclosebtn></A><font color="#FFFF66">关闭按钮和消息处理</font></H3>
      
<P>当用户用鼠标单击Close按钮时,窗格容器向父窗口发送一个WM_COMMAND消息,命令的ID是ID_PANE_CLOSE。如果你在分隔窗口中使用了窗格容器,你需要响应整个消息,调用SetSinglePaneMode()隐藏这个窗格。(但是,不要忘了提供用户一个重新显示窗格的方法!)</P>
<p>CPaneContainer的消息链也用到了FORWARD_NOTIFICATIONS()宏,和CSplitterWindow一样,窗格容器在客户窗口和它的父窗口之间传递通知消息。在ClipSpy这个例子中,在list控件和主框架窗口之间隔了两个窗口(窗格容器和分隔窗口),但是FORWARD_NOTIFICATIONS()宏可以确保所有的通知消息被送到主框架窗口。
<H2><A name=advancedsplitter></A><font color="#FFFF66">高级功能</font></H2>
      
<P>在这一节,我将介绍一些如何使用WTL的高级界面特性。</P>
      <H3><A name=nested></A><font color="#FFFF66">嵌套的分隔窗口</font></H3>
      
<P>如果你要编写一个email的客户端程序,你可能需要使用嵌套的分隔条,一个水平的和一个垂直的分隔条。使用WTL很容易做到这一点:创建一个分隔窗口作为另一个分隔窗口的子窗口。</P>
<p>为了演示这种效果,我将为ClipSpy添加一个水平分隔窗口。首先,添加一个名为m_wndHorzSplitter的CHorSplitterWindow类型的成员,像创建垂直分隔窗口m_wndVertSplitter那样创建这个水平分隔窗口,使水平分隔窗口m_wndHorzSplitter成为顶层窗口,将m_wndVertSplitter创建成m_wndHorzSplitter的子窗口。最后将m_hWndClient设置为m_wndHorzSplitter,因为现在水平分隔窗口占据整个主框架窗口的客户区。</p>
<PRE><font color="#0033FF">LRESULT CMainFrame::OnCreate()
{
<SPAN class=cpp-comment>//...</SPAN>
    <SPAN class=cpp-comment>// Create the splitter windows.</SPAN>
    <B>m_wndHorzSplit.Create ( *<SPAN class=cpp-keyword>this</SPAN>, rcDefault, NULL, 
                           dwSplitStyle, dwSplitExStyle );
 
    m_wndVertSplit.Create ( m_wndHorzSplit, rcDefault, NULL, 
                           dwSplitStyle, dwSplitExStyle );</B>
<SPAN class=cpp-comment>//...</SPAN>
<B>    <SPAN class=cpp-comment>// Set the horizontal splitter as the client area window.</SPAN>
    m_hWndClient = m_wndHorzSplit;

    <SPAN class=cpp-comment>// Set up the splitter panes</SPAN>
    m_wndPaneContainer.SetClient ( m_wndFormatList );
    m_wndHorzSplit.SetSplitterPane ( SPLIT_PANE_TOP, m_wndVertSplit );
    m_wndVertSplit.SetSplitterPanes ( m_wndPaneContainer, m_wndDataViewer );
</B><SPAN class=cpp-comment>//...</SPAN>
}</font></PRE>
<P>最终的结果是这个样子的:</P>
      
<P><IMG height=323 alt=" [Horz splitter w/empty pane - 5K] " 
      src="images/emptyhsplit7.png" 
      width=388 align=bottom border=0></P>
      
<H3><A name=axinpane></A><font color="#FFFF66">在窗格中使用ActiveX控件</font></H3>
      
<P>在分隔窗口的窗格中使用ActiveX控件与在对话框中使用ActiveX控件类似,使用CAxWindow类的方法在运行是创建控件,然后将这个CAxWindow指定给分隔窗口的窗格。下面演示了如何在水平分隔窗口下面的窗格中使用浏览器控件:</P>
<PRE>    <font color="#0033FF"><B><SPAN class=cpp-comment>// Create the bottom pane (browser)</SPAN>
CAxWindow wndIE;
<SPAN class=cpp-keyword>const</SPAN> DWORD dwIEStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN |
                        WS_HSCROLL | WS_VSCROLL;

    wndIE.Create ( m_wndHorzSplit, rcDefault, 
                  _T(<SPAN class=cpp-string>"http://www.codeproject.com"</SPAN>), dwIEStyle );
</B>
    <SPAN class=cpp-comment>// Set the horizontal splitter as the client area window.</SPAN>
    m_hWndClient = m_wndHorzSplit;

    <SPAN class=cpp-comment>// Set up the splitter panes</SPAN>
    m_wndPaneContainer.SetClient ( m_wndFormatList );
    <B>m_wndHorzSplit.SetSplitterPanes ( m_wndVertSplit, wndIE );
</B>    m_wndVertSplit.SetSplitterPanes ( m_wndPaneContainer, m_wndDataViewer );</font></PRE>
<H3><A name=specialdraw></A><font color="#FFFF66">特殊绘制</font></H3>
      
<P>如果你想改变分隔条的外观,例如在上面使用一些材质,你可以从CSplitterWindowImpl派生新类并重载DrawSplitterBar()函数。如果你只是想调整一下分隔条的外观,可以复制CSplitterWindowImpl类的函数,然后稍做修改。下面的例子就在分隔条中使用了斜交叉线图案。</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">template</font></SPAN> <font color="#0033FF">&lt;<SPAN class=cpp-keyword>bool</SPAN> t_bVertical = <SPAN class=cpp-keyword>true</SPAN>&gt;
<SPAN class=cpp-keyword>class</SPAN> CMySplitterWindowT : 
    <SPAN class=cpp-keyword>public</SPAN> CSplitterWindowImpl&lt;CMySplitterWindowT&lt;t_bVertical&gt;, t_bVertical&gt;
{
<SPAN class=cpp-keyword>public</SPAN>:
    DECLARE_WND_CLASS_EX(_T(<SPAN class=cpp-string>"My_SplitterWindow"</SPAN>), 
                         CS_DBLCLKS, COLOR_WINDOW)
 
    <SPAN class=cpp-comment>// Overrideables</SPAN>
    <SPAN class=cpp-keyword>void</SPAN> DrawSplitterBar(CDCHandle dc)
    {
    RECT rect;
 
        <SPAN class=cpp-keyword>if</SPAN> ( m_br.IsNull() )
            m_br.CreateHatchBrush ( HS_DIAGCROSS, 
                                    t_bVertical ? RGB(<SPAN class=cpp-literal>255</SPAN>,<SPAN class=cpp-literal>0</SPAN>,<SPAN class=cpp-literal>0</SPAN>) 
                                                : RGB(<SPAN class=cpp-literal>0</SPAN>,<SPAN class=cpp-literal>0</SPAN>,<SPAN class=cpp-literal>255</SPAN>) );
 
        <SPAN class=cpp-keyword>if</SPAN> ( GetSplitterBarRect ( &amp;rect ) )
        {
            dc.FillRect ( &amp;rect, m_br );
 
            <SPAN class=cpp-comment>// draw 3D edge if needed</SPAN>
            <SPAN class=cpp-keyword>if</SPAN> ( (GetExStyle() &amp; WS_EX_CLIENTEDGE) != <SPAN class=cpp-literal>0</SPAN>)
                dc.DrawEdge(&amp;rect, EDGE_RAISED, 
                            t_bVertical ? (BF_LEFT | BF_RIGHT) 
                                        : (BF_TOP | BF_BOTTOM));
        }
    }
 
<SPAN class=cpp-keyword>protected</SPAN>:
    CBrush m_br;
};
 
<SPAN class=cpp-keyword>typedef</SPAN> CMySplitterWindowT&lt;<SPAN class=cpp-keyword>true</SPAN>&gt;    CMySplitterWindow;
<SPAN class=cpp-keyword>typedef</SPAN> CMySplitterWindowT&lt;<SPAN class=cpp-keyword>false</SPAN>&gt;   CMyHorSplitterWindow;</font></PRE>
      
<P>这就是结果(将分隔条变宽是为了更容易看到效果):</P>
      
<P><IMG height=349 alt=" [custom drawn bars - 14K] " 
      src="images/custombars7.png" 
      width=413 align=bottom border=0></P>
      
<H2><A name=pcoverrides></A><font color="#FFFF66">窗格容器内的特殊绘制</font></H2>
      
<P>CPaneContainer也有几个函数可以重载,用来改变窗格容器的外观。你可以从CPaneContainerImpl派生新类并重载你需要的方法,例如:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">class</font></SPAN><font color="#0033FF"> CMyPaneContainer :
    <SPAN class=cpp-keyword>public</SPAN> CPaneContainerImpl&lt;CMyPaneContainer&gt;
{
<SPAN class=cpp-keyword>public</SPAN>:
    DECLARE_WND_CLASS_EX(_T(<SPAN class=cpp-string>"My_PaneContainer"</SPAN>), <SPAN class=cpp-literal>0</SPAN>, -<SPAN class=cpp-literal>1</SPAN>)
<SPAN class=cpp-comment>//... overrides here ...</SPAN>
};</font></PRE>
      
<P>一些更有意思的方法是:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">void</font></SPAN><font color="#0033FF"> CalcSize()</font></PRE>
      
<P>调用CalcSize()函数只是为了设置m_cxyHeader,这个变量控制着窗格容器的顶部区域的宽度和高度。不过SetPaneContainerExtendedStyle()函数中有一个BUG,导致窗格从水平切换到垂直时没有调用派生类的CalcSize()方法,你可以将CalcSize()调用改为pT-&gt;CalcSize()来修补这个BUG。</P>
<PRE><font color="#0033FF">HFONT GetTitleFont()</font></PRE>
      
<P>这个方法返回一个HFONT,它被用来画顶部区域的文字,默认的值是调用GetStockObject(DEFAULT_GUI_FONT)得到的字体,也就是MS 
  Sans Serif。如果你想改称更现代的Tahoma字体,你可以重载GetTitleFont()方法,返回你创建的Tahoma字体。</P>
<PRE><font color="#0033FF">BOOL GetToolTipText(LPNMHDR lpnmh)</font></PRE>
      
<P>重载这个方法提供鼠标移到Close按钮时弹出的提示信息,这个函数实际上是TTN_GETDISPINFO的相应函数,你可以将lpnmh转换成NMTTDISPINFO*,并设置这个数据结构内相应的成员变量。记住一点,你必须检查通知代码,它可能是TTN_GETDISPINFO或TTN_GETDISPINFOW,你需要有区别的访问这两个数据结构。</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">void</font></SPAN><font color="#0033FF"> DrawPaneTitle(CDCHandle dc)</font></PRE>
      
<P>你可以重载这个方法自己画顶部区域,你可以用GetClientRect()和m_cxyHeader来计算顶部区域的范围。下面的例子演示了在水平容器的顶部区域画一个渐变填充的背景:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">void</font></SPAN><font color="#0033FF"> CMyPaneContainer::DrawPaneTitle ( CDCHandle dc )
{
RECT rect;
 
    GetClientRect(&amp;rect);
 
TRIVERTEX tv[] = { 
    { rect.left, rect.top, <SPAN class=cpp-literal>0xff00</SPAN> },
    { rect.right, rect.top + m_cxyHeader, <SPAN class=cpp-literal>0</SPAN>, <SPAN class=cpp-literal>0xff00</SPAN> } 
};
GRADIENT_RECT gr = { <SPAN class=cpp-literal>0</SPAN>, <SPAN class=cpp-literal>1</SPAN> };
 
    dc.GradientFill ( tv, <SPAN class=cpp-literal>2</SPAN>, &amp;gr, <SPAN class=cpp-literal>1</SPAN>, GRADIENT_FILL_RECT_H );
}</font></PRE>
      
<P>例子工程代码中演示了对这几个方法的重载,使得结果看起来是这个样子的:</P>
      
<P><IMG height=282 alt=" [Custom drawing in a pane cont. - 6K] " 
      src="images/custompc7.png" 
      width=383 align=bottom border=0></P>
      
<P>从上面的图中可以看到,这个演示程序有一个Splitters菜单,通过它可以在各种风格的分隔条(包括自画风格)和窗格容器之间切换,比较它们之间的异同。你还可以锁定分隔条的位置,这是通过设置和取消SPLIT_NONINTERACTIVE扩展风格来实现的。</P>
      
<H2><A name=bonus></A><font color="#FFFF66">在状态栏显示进度条</font></H2>
      
<P>正如我在前几篇文章中做得保证那样,新的ClipSpy也演示了如何在状态条上创建进展条,它和MFC版本得功能一样,几个相关得步骤是:</P>
      
<OL>
  <LI>得到状态条第一个窗格得坐标范围RECT
  <LI>创建一个进展条作为状态条得子窗口,窗口大小就是哪个状态条窗格得大小
  <LI>随着edit控件被填充的同时更新进展条的位置</LI>
</OL>
      
<P>这些代码在CMainFrame::CreateProgressCtrlInStatusBar()函数中。</P>
             
<H2><A name=upnext></A><font color="#FFFF66">继续</font></H2>
      
<P>在第八章我将介绍属性页和向导对话框的用法</P>

<H2><A name=references></A>参考</H2>
      <P><A href="http://www.codeproject.com/wtl/SplitPane.asp">WTL Splitters and Pane Containers</A> by Ed Gadziemski</P>   

<H2><A name=revisionhistory></A><font color="#FFFF66">修改记录</font></H2>
      
<P>July 9, 2003: 文章第一次发布。 
</body>
</html>

⌨️ 快捷键说明

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