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

📄 wtl for mfc programmers, part ii - wtl gui base classes - wtl.htm

📁 WT教程中文版 内有详细的介绍 包括各个方面
💻 HTM
📖 第 1 页 / 共 3 页
字号:
<html>
<head>
<title>WTL for MFC Programmers, Part II - WTL GUI Base Classes - WTL</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 II - WTL GUI Base Classes</font></b><br>
  <br>
</p>
<p align="left">原作 :<b><font color="#CC3366">Michael Dunn</font></b> [<a href="http://www.codeproject.com/wtl/WTL4MFC2.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/WTL4MFC2_demo.zip">下载演示程序代码</a></p>
<H2><font color="#FFFF66">本章内容</font></H2>
<UL>
  <LI><A 
        href="#intopart2">对第二部分的介绍</A> 
  <LI><A 
        href="#wtloverview">WTL 的总体印象</A> 
  <LI><A 
        href="#beginningexe">开始写WTL程序</A> 
  <LI><A href="#wtlmsgmap">WTL 对消息映射链的增强</A> 
  <LI><A href="#appwizard">从WTL的应用程序生成向导能得到什么</A> 
    <UL>
      <LI><A 
          href="#thruwizard">使用向导的整个过程</A> 
      <LI><A 
          href="#examinecode">查看生成的代码</A> </LI>
    </UL>
  <LI><A 
        href="#msgloopinternals">CMessageLoop 的内部实现</A> 
  <LI><A 
        href="#frameinternals">CFrameWindowImpl 的内部实现</A> 
  <LI><A 
        href="#backtotheclock">回到前面的时钟程序</A> 
  <LI><A href="#uiupdating">UI状态的自动更新</A> 
    <UL>
      <LI><A 
          href="#newmenuitems">添加控制时钟的菜单</A> 
      <LI><A 
          href="#callinguienable">使用UIEnable()函数</A> </LI>
    </UL>
  <LI><A 
        href="#fixclassview"> 消息映射链(Message Maps)中最后需要注意的地方</A> 
  <LI><A href="#nextup">下一站,1995</A> 
  <LI><A 
        href="#revisionhistory">修改记录</A> </LI>
</UL>
      <P>
      
<H2><A name=intopart2></A><font color="#FFFF66">对第二部分的介绍</font></H2>
      
<P>好了,现在正式开始介绍WTL!在这一部分我讲的内容包括生成一个基本的主窗口和WTL提供的一些友好的改进,比如UI界面的更新(如菜单上的选择标记)和更好的消息映射机制。为了更好地掌握本章的内容,你应该安装WTL并将WTL库的头文件目录添加到VC的搜索目录中,还要将WTL的应用程序生成向导复制到正确的位置。WTL的发布版本中有文档具体介绍如何做这些设置,如果遇到困难可以查看这些文档。</P>
<H2><A name=wtloverview></A><font color="#FFFF66">WTL 总体印象</font></H2>
      
<P>WTL的类大致可以分为几种类型:</P>
      
<OL>
  <LI>主框架窗口的实现<CODE>-</CODE> CFrameWindowImpl, CMDIFrameWindowImpl 
  <LI>控件的封装- CButton, CListViewCtrl
  <LI>GDI 对象的封装- CDC, CMenu
  <LI>一些特殊的界面特性 - CSplitterWindow, CUpdateUI, CDialogResize, CCustomDraw
  <LI>实用的工具类和宏- CString, CRect, BEGIN_MSG_MAP_EX</LI>
</OL>
      
<P>本篇文章将深入地介绍框架窗口类,还将简要地讲一下有关的界面特性类和工具类,这些界面特性类和工具类中绝大多数都是独立的类,尽管有一些是嵌入类,例如:CDialogResize。</P>
<H2><A name=beginningexe></A><font color="#FFFF66">开始写WTL程序</font></H2>
<P>如果你没有用WTL的应用程序生成向导也没关系(我将在后面介绍这个向导的用法), WTL的程序的代码结构很像ATL的程序,本章使用的例子代码有别于第一章的例子,主要是为了显示WTL的特性,没有什么实用价值。</P>
      
<P>这一节我们将在WTL生成的代码基础上添加代码,生成一个新的程序,程序主窗口的客户区显示当前的时间。stdafx.h的代码如下:</P>
<PRE><SPAN class=cpp-preprocessor><font color="#0000FF">#define STRICT</font></SPAN>
<font color="#0000FF"><SPAN class=cpp-preprocessor>#define WIN32_LEAN_AND_MEAN</SPAN>
<SPAN class=cpp-preprocessor>#define _WTL_USE_CSTRING</SPAN>
 
<SPAN class=cpp-preprocessor>#include &lt;atlbase.h&gt;       // 基本的ATL类</SPAN>
<SPAN class=cpp-preprocessor>#include &lt;atlapp.h&gt;        // 基本的WTL类
</SPAN><SPAN class=cpp-keyword>extern</SPAN> CAppModule _Module; <SPAN class=cpp-comment>// WTL 派生的CComModule版本</SPAN>
<SPAN class=cpp-preprocessor>#include &lt;atlwin.h&gt;        // ATL 窗口类</SPAN>
<SPAN class=cpp-preprocessor>#include &lt;atlframe.h&gt;      // WTL 主框架窗口类</SPAN>
<SPAN class=cpp-preprocessor>#include &lt;atlmisc.h&gt;       // WTL 实用工具类,例如:CString</SPAN>
<SPAN class=cpp-preprocessor>#include &lt;atlcrack.h&gt;      // WTL 增强的消息宏</SPAN></font></PRE>
<P>atlapp.h 是你的工程中第一个包含的头文件,这个文件内定义了有关消息处理的类和CAppModule,CAppModule是从CComModule派生的类。如果你打算使用CString类,你需要手工定义_WTL_USE_CSTRING标号,因为CString类是在atlmisc.h中定义的,而许多包含在atlmisc.h之前的头文件都会用到CString,定义_WTL_USE_CSTRING之后,atlapp.h就会向前声明CString类,其他的头文件就知道CString类的存在,从而避免编译器为此大惊小怪。<br>
</P>
      
<P>接下来定义框架窗口。我们的SDI窗口是从CFrameWindowImpl派生的,在定义窗口类时使用DECLARE_FRAME_WND_CLASS代替前面使用的DECLARE_WND_CLASS。下面时MyWindow.h中窗口定义的开始部分:</P>
<PRE><SPAN class=cpp-keyword><font color="#0000FF">class</font></SPAN><font color="#0000FF"> CMyWindow : <SPAN class=cpp-keyword>public</SPAN> CFrameWindowImpl&lt;CMyWindow&gt;
{
<SPAN class=cpp-keyword>public</SPAN>:
    DECLARE_FRAME_WND_CLASS(_T(<SPAN class=cpp-string>"First WTL window"</SPAN>), IDR_MAINFRAME);

    BEGIN_MSG_MAP(CMyWindow)
        CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMyWindow&gt;)
    END_MSG_MAP()
};</font></PRE>
      
<P>DECLARE_FRAME_WND_CLASS有两个参数,窗口类名(类名可以是NULL,ATL会替你生成一个类名)和资源ID,创建窗口时WTL用这个ID装载图标,菜单和加速键表。我们还要象CFrameWindowImpl中的消息处理(例如WM_SIZE和WM_DESTROY消息)那样将消息链入窗口的消息中。</P>
      
<P>现在来看看WinMain()函数,它和第一部分中的例子代码中的WinMain()函数几乎一样,只是创建窗口部分的代码略微不同。</P>
<PRE>// main.cpp:<br><font color="#0000FF">#include &quot;stdafx.h&quot;<br>#include &quot;MyWindow.h&quot;<br> <br>CAppModule _Module;<br> <br>int APIENTRY WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,<br>                       LPSTR lpCmdLine, int nCmdShow )<br>{<br>    _Module.Init ( NULL, hInstance );<br> <br>CMyWindow wndMain;<br>MSG msg;<br> <br>    // Create the main window<br>    if ( NULL == wndMain.CreateEx() )<br>        return 1;       // Window creation failed<br> <br>    // Show the window<br>    wndMain.ShowWindow ( nCmdShow );<br>    wndMain.UpdateWindow();<br> <br>    // Standard Win32 message loop<br>    while ( GetMessage ( &amp;msg, NULL, 0, 0 ) &gt; 0 )<br>        {<br>        TranslateMessage ( &amp;msg );<br>        DispatchMessage ( &amp;msg );<br>        }<br> <br>    _Module.Term();<br>    return msg.wParam;<br>}</font></PRE>
<P>CFrameWindowImpl中的CreateEx()函数的参数使用了常用的默认值,所以我们不需要特别指定任何参数。正如前面介绍的,CFrameWindowImpl会处理资源的装载,你只需要使用IDR_MAINFRAME作为ID定义你的资源就行了(译者注:主要是图标,菜单和加速键表),你也可以直接使用本章的例子代码。</P>
      
<P>如果你现在就运行程序,你会看到主框架窗口,事实上它没有做任何事情。我们需要手工添加一些消息处理,所以现在是介绍WTL的消息映射宏的最佳时间。</P>
<H2><A name=wtlmsgmap></A><font color="#FFFF66">WTL 对消息映射的增强</font></H2>
      
<P>将Win32 API通过消息传递过来的WPARAM和LPARAM数据还原出来是一件麻烦的事情并且很容易出错,不幸得是ATL并没有为我们提供更多的帮助,我们仍然需要从消息中还原这些数据,当然WM_COMMAND和WM_NOTIFY消息除外。但是WTL的出现拯救了这一切!</P>
      
<P>WTL的增强消息映射宏定义在atlcrack.h中。(这个名字来源于“消息解密者”,是一个与windowsx.h的宏所使用的相同术语)首先将BEGIN_MSG_MAP改为BEGIN_MSG_MAP_EX,带_EX的版本产生“解密”消息的代码。</P>
<PRE><SPAN class=cpp-keyword><font color="#0000FF">class</font></SPAN><font color="#0000FF"> CMyWindow : <SPAN class=cpp-keyword>public</SPAN> CFrameWindowImpl&lt;CMyWindow&gt;
{
<SPAN class=cpp-keyword>public</SPAN>:</font>
    <FONT color=red>BEGIN_MSG_MAP_EX(CMyWindow)</FONT>
<font color="#0000FF">        CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMyWindow&gt;)
    END_MSG_MAP()
};</font></PRE>
      
<P>对于我们的时钟程序,我们需要处理WM_CREATE消息来设置定时器,WTL的消息处理使用MSG_作为前缀,后面是消息名称,例如MSG_WM_CREATE。这些宏只是代表消息响应处理的名称,现在我们来添加对WM_CREATE消息的响应:</P>
<PRE><SPAN class=cpp-keyword><font color="#0000FF">class</font></SPAN><font color="#0000FF"> CMyWindow : <SPAN class=cpp-keyword>public</SPAN> CFrameWindowImpl&lt;CMyWindow&gt;
{
<SPAN class=cpp-keyword>public</SPAN>:
    BEGIN_MSG_MAP_EX(CMyWindow)</font><FONT color=red>
        MSG_WM_CREATE(OnCreate)</FONT>
<font color="#0000FF">        CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMyWindow&gt;)
    END_MSG_MAP()
 
    <SPAN class=cpp-comment>// OnCreate(...) ?</SPAN>
};</font></PRE>
      
<P>WTL的消息响应处理看起来有点象MFC,每一个处理函数根据消息传递的参数不同也有不同的原型。由于我们没有向导自动添加消息响应,所以我们需要自己查找正确的消息处理函数。幸运的是VC可以帮我们的忙,将鼠标光标移到“MSG_WM_CREATE”宏的文字上按F12键就可以来到这个宏的定义代码处。如果是第一次使用这个功能,VC会要求从新编译全部文件以建立浏览信息数据库(browse 
  info database),建立了这个数据库之后,VC会打开atlcrack.h并将代码定位到MSG_WM_CREATE的定义位置:</P>
<PRE><SPAN class=cpp-preprocessor><font color="#0000FF">#define MSG_WM_CREATE(func) \</font></SPAN>
    <font color="#0000FF"><SPAN class=cpp-keyword>if</SPAN> (uMsg == WM_CREATE) \
    { \
        SetMsgHandled(TRUE); \</font>
        <FONT color=red>lResult = (LRESULT)func((LPCREATESTRUCT)lParam); \</FONT>
        <font color="#0000FF"><SPAN class=cpp-keyword>if</SPAN>(IsMsgHandled()) \
            <SPAN class=cpp-keyword>return</SPAN> TRUE; \
    }</font></PRE>
<P>标记为红色的那一行非常重要,就是在这里调用实际的消息响应函数,他告诉我们消息响应函数有一个<code>LPCREATESTRUCT</code>类型的参数,返回值的类型是LRESULT。请注意这里没有ATL的宏所用的 
  bHandled 参数,<code>SetMsgHandled()</code>函数代替了这个参数,我会对此作些简要的介绍。</P>
      
<P>现在为我们的窗口类添加OnCreate()响应函数:</P>
<PRE><SPAN class=cpp-keyword><font color="#0000FF">class</font></SPAN><font color="#0000FF"> CMyWindow : <SPAN class=cpp-keyword>public</SPAN> CFrameWindowImpl&lt;CMyWindow&gt;
{
<SPAN class=cpp-keyword>public</SPAN>:
    BEGIN_MSG_MAP_EX(CMyWindow)
        MSG_WM_CREATE(OnCreate)
        CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMyWindow&gt;)
    END_MSG_MAP()</font>
 
    <FONT color=red>LRESULT OnCreate(LPCREATESTRUCT lpcs)
    {
        SetTimer ( <SPAN class=cpp-literal>1</SPAN>, <SPAN class=cpp-literal>1000</SPAN> );
        SetMsgHandled(<SPAN class=cpp-keyword>false</SPAN>);
        <SPAN class=cpp-keyword>return</SPAN> <SPAN class=cpp-literal>0</SPAN>;
    }</FONT>
<font color="#0000FF">};</font></PRE>
      
<P>CFrameWindowImpl 是直接从CWindow类派生的, 所以它继承了所有CWindow类的方法,如SetTimer()。这使得对窗口API的调用有点象MFC的代码,只是MFC使用CWnd类包装这些API。</P>
      
<P>我们使用SetTimer()函数创建一个定时器,它每隔一秒钟(1000毫秒)触发一次。由于我们需要让CFrameWindowImpl也处理WM_CREATE消息,所以我们调用SetMsgHandled(false),让消息通过CHAIN_MSG_MAP宏链入基类,这个调用代替了ATL宏使用的bHandled参数。(即使CFrameWindowImpl类不需要处理WM_CREATE消息,调用SetMsgHandled(false)让消息流入基类是个好的习惯,因为这样我们就不必总是记着哪个消息需要基类处理那些消息不需要基类处理,这和VC的类向导产生的代码相似,多数的派生类的消息处理函数的开始或结尾都会调用基类的消息处理函数)</P>
      
<P>为了能够停止定时器我们还需要响应WM_DESTROY消息,添加消息响应的过程和前面一样,MSG_WM_DESTROY宏的定义是这样的:</P>
<PRE><SPAN class=cpp-preprocessor><font color="#0000FF">#define MSG_WM_DESTROY(func) \</font></SPAN>
    <font color="#0000FF"><SPAN class=cpp-keyword>if</SPAN> (uMsg == WM_DESTROY) \
    { \
        SetMsgHandled(TRUE); \</font>
        <FONT color=red>func(); \</FONT>
<font color="#0000CC">        lResult = <SPAN class=cpp-literal>0</SPAN>; \
        <SPAN class=cpp-keyword>if</SPAN>(IsMsgHandled()) \
            <SPAN class=cpp-keyword>return</SPAN> TRUE; \
    }</font></PRE>
      
<P>OnDestroy()函数没有参数也没有返回值,CFrameWindowImpl也要处理WM_DESTROY消息,所以还要调用SetMsgHandled(false):<br>
</P>
<PRE><SPAN class=cpp-keyword><font color="#0000FF">class</font></SPAN><font color="#0000FF"> CMyWindow : <SPAN class=cpp-keyword>public</SPAN> CFrameWindowImpl&lt;CMyWindow&gt;
{
<SPAN class=cpp-keyword>public</SPAN>:
    BEGIN_MSG_MAP_EX(CMyWindow)
        MSG_WM_CREATE(OnCreate)</font>
        <FONT color=red>MSG_WM_DESTROY(OnDestroy)</FONT>
<font color="#0000CC">        CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMyWindow&gt;)
    END_MSG_MAP()<BR><BR></font><BR>
    <FONT color=red><SPAN class=cpp-keyword>void</SPAN> OnDestroy()
    {
        KillTimer(<SPAN class=cpp-literal>1</SPAN>);
        SetMsgHandled(<SPAN class=cpp-keyword>false</SPAN>);

⌨️ 快捷键说明

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