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

📄 wtl for mfc programmers, part iv - dialogs and controls - wtl.htm

📁 WT教程中文版 内有详细的介绍 包括各个方面
💻 HTM
📖 第 1 页 / 共 3 页
字号:
    <SPAN class=cpp-keyword>return</SPAN> TRUE;
}</font></PRE>
      
<P>下面是新的WM_SETCURSOR消息处理函数:</P>
<PRE><font color="#0033FF">LRESULT CMainDlg::OnSetCursor_OK (HWND hwndCtrl, UINT uHitTest, UINT uMouseMsg )
{
<SPAN class=cpp-keyword>static</SPAN> HCURSOR hcur = LoadCursor ( NULL, IDC_HAND );
 
    <SPAN class=cpp-keyword>if</SPAN> ( NULL != hcur )
        {
        SetCursor ( hcur );
        <SPAN class=cpp-keyword>return</SPAN> TRUE;
        }
    <SPAN class=cpp-keyword>else</SPAN>
        {
        SetMsgHandled(<SPAN class=cpp-keyword>false</SPAN>);
        <SPAN class=cpp-keyword>return</SPAN> FALSE;
        }
}
 
LRESULT CMainDlg::OnSetCursor_Exit ( HWND hwndCtrl, UINT uHitTest, UINT uMouseMsg )
{
<SPAN class=cpp-keyword>static</SPAN> HCURSOR hcur = LoadCursor ( NULL, IDC_NO );
 
    <SPAN class=cpp-keyword>if</SPAN> ( NULL != hcur )
        {
        SetCursor ( hcur );
        <SPAN class=cpp-keyword>return</SPAN> TRUE;
        }
    <SPAN class=cpp-keyword>else</SPAN>
        {
        SetMsgHandled(<SPAN class=cpp-keyword>false</SPAN>);
        <SPAN class=cpp-keyword>return</SPAN> FALSE;
        }
}</font></PRE>
      
<P>如果你还想使用按钮类的特性,你需要这样声明变量:</P>
<PRE>    <font color="#0033FF">CContainedWindowT&lt;CButton&gt; m_wndOKBtn;</font></PRE>
      
<P>这样就可以使用CButton类的方法。</P>
<p>当你把鼠标光标移到这些按钮上就可以看到WM_SETCURSOR消息处理函数的作用结果:</p>
<P><IMG height=220 alt=" [OK button cursor - 5K] " 
      src="images/okbtncur4.png" 
      width=333 align=bottom border=0> <IMG height=220 
      alt=" [Exit button cursor - 5K] " 
      src="images/exitbtncur4.png" 
      width=333 align=bottom border=0></P>
      
<H3><A name=atl3></A><font color="#FFFF66">ATL 方式 3 - 子类化(Subclassing)</font></H3>
      
<P>第三种方法创建一个CWindowImpl派生类并用它子类化一个控件。这和第二种方法有些相似,只是消息处理放在CWindowImpl类内部而不是对话框类中。</P>
<p>ControlMania1使用这种方法子类化主对话框的About按钮。下面是CButtonImpl类,他从CWindowImpl类派生,处理WM_SETCURSOR消息:</p>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">class</font></SPAN><font color="#0033FF"> CButtonImpl : <SPAN class=cpp-keyword>public</SPAN> CWindowImpl&lt;CButtonImpl, CButton&gt;
{
    BEGIN_MSG_MAP_EX(CButtonImpl)
        MSG_WM_SETCURSOR(OnSetCursor)
    END_MSG_MAP()
 
    LRESULT OnSetCursor(HWND hwndCtrl, UINT uHitTest, UINT uMouseMsg)
    {
    <SPAN class=cpp-keyword>static</SPAN> HCURSOR hcur = LoadCursor ( NULL, IDC_SIZEALL );
 
        <SPAN class=cpp-keyword>if</SPAN> ( NULL != hcur )
            {
            SetCursor ( hcur );
            <SPAN class=cpp-keyword>return</SPAN> TRUE;
            }
        <SPAN class=cpp-keyword>else</SPAN>
            {
            SetMsgHandled(<SPAN class=cpp-keyword>false</SPAN>);
            <SPAN class=cpp-keyword>return</SPAN> FALSE;
            }
    }
};</font></PRE>
      
<P>接着在主对话框声明一个CButtonImpl成员变量:</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">class</font></SPAN><font color="#0033FF"> CMainDlg : <SPAN class=cpp-keyword>public</SPAN> CDialogImpl&lt;CMainDlg&gt;
{
<SPAN class=cpp-comment>// ...</SPAN>
<SPAN class=cpp-keyword>protected</SPAN>:
    CContainedWindow m_wndOKBtn, m_wndExitBtn;
    <B>CButtonImpl m_wndAboutBtn;</B>
};</font></PRE>
      
<P>最后,在OnInitDialog()种子类化About按钮。</P>
<PRE><font color="#0033FF">LRESULT CMainDlg::OnInitDialog(...)
{
<SPAN class=cpp-comment>// ...</SPAN>
    <SPAN class=cpp-comment>// Attach CContainedWindows to OK and Exit buttons</SPAN>
    m_wndOKBtn.SubclassWindow ( GetDlgItem(IDOK) );
    m_wndExitBtn.SubclassWindow ( GetDlgItem(IDCANCEL) );
 
    <B><SPAN class=cpp-comment>// CButtonImpl: subclass the About button</SPAN>
    m_wndAboutBtn.SubclassWindow ( GetDlgItem(ID_APP_ABOUT) );</B>
 
    <SPAN class=cpp-keyword>return</SPAN> TRUE;
}</font></PRE>
<H3><A name=wtlway></A><font color="#FFFF66">WTL 方式 - 对话框数据交换(DDX)</font></H3>
      
<P>WTL的DDX(对话框数据交换)很像MFC,可以使用很简单的方法将变量和控件关联起来。首先,和前面的例子一样你需要从CWindowImpl派生一个新类,这次我们使用一个新类CEditImpl,因为这次我们使用得是Edit控件。你还需要将#include 
  atlddx.h 添加到stdafx.h中,这样就可以使用DDX代码。</P>
<p>要使主对话框支持DDX,需要将CWinDataExchange添加到继承列表中:</p>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">class</font></SPAN><font color="#0033FF"> CMainDlg : <SPAN class=cpp-keyword>public</SPAN> CDialogImpl&lt;CMainDlg&gt;, 
                 <B><SPAN class=cpp-keyword>public</SPAN> CWinDataExchange&lt;CMainDlg&gt;</B>
{
<SPAN class=cpp-comment>//...</SPAN>
};</font></PRE>
      
<P>接着在对话框类中添加DDX链,这和MFC的类向导使用的DoDataExchange()函数功能相似。对于不同类型的数据可以使用不同的DDX宏,我们使用DDX_CONTROL用来连接变量和控件,这次我们使用CEditImpl处理WM_CONTEXTMENU消息,使它能够在你右键单控件时做一些事情。</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">class</font></SPAN><font color="#0033FF"> CEditImpl : <SPAN class=cpp-keyword>public</SPAN> CWindowImpl&lt;CEditImpl, CEdit&gt;
{
    BEGIN_MSG_MAP_EX(CEditImpl)
        MSG_WM_CONTEXTMENU(OnContextMenu)
    END_MSG_MAP()
 
    <SPAN class=cpp-keyword>void</SPAN> OnContextMenu ( HWND hwndCtrl, CPoint ptClick )
    {
        MessageBox(<SPAN class=cpp-string>"Edit control handled WM_CONTEXTMENU"</SPAN>);
    }
};
 
<SPAN class=cpp-keyword>class</SPAN> CMainDlg : <SPAN class=cpp-keyword>public</SPAN> CDialogImpl&lt;CMainDlg&gt;, 
                 <SPAN class=cpp-keyword>public</SPAN> CWinDataExchange&lt;CMainDlg&gt;
{
<SPAN class=cpp-comment>//...</SPAN>
 
    <B>BEGIN_DDX_MAP(CMainDlg)
        DDX_CONTROL(IDC_EDIT, m_wndEdit)
    END_DDX_MAP()</B>
 
<SPAN class=cpp-keyword>protected</SPAN>:
    CContainedWindow m_wndOKBtn, m_wndExitBtn;
    CButtonImpl m_wndAboutBtn;<B>
</B>    <B>CEditImpl   m_wndEdit;</B>
};</font></PRE>
      
<P>最后,在OnInitDialog()中调用DoDataExchange()函数,这个函数是继承自CWinDataExchange。DoDataExchange()第一次被调用时完成相关控件的子类化工作,所以在这个例子中,DoDataExchange()子类化ID为IDC_EDIT的控件,将其与m_wndEdit建立关联。</P>
<PRE><font color="#0033FF">LRESULT CMainDlg::OnInitDialog(...)
{
<SPAN class=cpp-comment>// ...</SPAN>
    <SPAN class=cpp-comment>// Attach CContainedWindows to OK and Exit buttons</SPAN>
    m_wndOKBtn.SubclassWindow ( GetDlgItem(IDOK) );
    m_wndExitBtn.SubclassWindow ( GetDlgItem(IDCANCEL) );
 
    <SPAN class=cpp-comment>// CButtonImpl: subclass the About button</SPAN>
    m_wndAboutBtn.SubclassWindow ( GetDlgItem(ID_APP_ABOUT) );
 
    <B><SPAN class=cpp-comment>// First DDX call, hooks up variables to controls.</span></B>
    <B>DoDataExchange(<SPAN class=cpp-keyword>false</SPAN>);</B>
 
    <SPAN class=cpp-keyword>return</SPAN> TRUE;
}</font></PRE>
      
<P>DoDataExchange()的参数与MFC的UpdateData()函数的参数意义相同,我会在下一节详细介绍。</P>
<p>现在运行ControlMania1程序,可以看到子类化的效果。鼠标右键单击编辑框将弹出消息框,当鼠标通过按钮上时鼠标形状会改变。</p>
<H2><A name=moreddx></A><font color="#FFFF66">DDX的详细内容</font></H2>
      
<P>当然,DDX是用来做数据交换的,WTL支持在Edit控件和字符串之间交换数据,也可以将字符串解析成数字,转换成整型或浮点型变量,还支持Check box和Radio 
  button组的状态与int型变量之间的转换。</P>
<H3><A name=ddxmacros></A><font color="#FFFF66">DDX 宏</font></H3>
      
<P>DDX可以使用6种宏,每一种宏都对应一个CWinDataExchange类的方法支持其工作,每一种宏都用相同的形式:DDX_FOO(控件ID, 变量),每一种宏都可以支持多种类型的变量,例如DDX_TEXT的重载就支持多种类型的数据。</P>
      
<DL> 
  <DT>DDX_TEXT 
  <DD>在字符串和edit box控件之间传输数据,变量类型可以是CString, BSTR, CComBSTR或者静态分配的字符串数组,但是不能使用new动态分配的数组。
  <DT>DDX_INT 
  <DD>在edit box控件和数字变量之间传输int型数据。
  <DT>DDX_UINT 
  <DD>在edit box控件和数字变量之间传输无符号int型数据。
  <DT>DDX_FLOAT 
  <DD>在edit box控件和数字变量之间传输浮点型(float)数据或双精度型数据(double)。
  <DT>DDX_CHECK 
  <DD>在check box控件和int型变量之间转换check box控件的状态。
  <DT>DDX_RADIO 
  <DD>在radio buttons控件组和int型变量之间转换radio buttons控件组的状态。</DD>
</DL>
      
<P>DDX_FLOAT宏有一些特殊,要使用DDX_FLOAT宏需要在stdafx.h文件的所有WTL头文件包含之前添加一行定义:</P>
<PRE><SPAN class=cpp-preprocessor><font color="#0033FF">#define _ATL_USE_DDX_FLOAT</font></SPAN></PRE>
      
<P>这个定义是必要的,因为默认状态为了优化程序的大小而不支持浮点数。</P>
      
<H3><A name=moreddx></A><font color="#FFFF66">有关 DoDataExchange()的详细内容</font></H3>
      
<P>调用DoDataExchange()方法和在MFC中使用UpdateData()一样,DoDataExchange()的函数原型是:</P>
<PRE><font color="#0033FF">BOOL DoDataExchange ( BOOL bSaveAndValidate = FALSE, UINT nCtlID = (UINT)-<SPAN class=cpp-literal>1</SPAN> );</font></PRE>
<P>参数:</P>
      
<DL> 
  <DT>bSaveAndValidate
  <DD>指示数据传输方向的标志。TRUE表示将数据从控件传输给变量,FALSE表示将数据从变量传输给控件。需要注意得是这个参数的默认值是FALSE,而MFC的UpdateData()函数的默认值是TRUE。为了方便记忆,你可以使用DDX_SAVE 
    和 DDX_LOAD标号(它们分别被定义为TRUE和FALSE)。
  <DT>nCtlID 
  <DD>使用-1可以更新所有控件,如果只想DDX宏作用于一个控件就使用控件的ID。</DD>
</DL>
      
<P>如果控件更新成功DoDataExchange()会返回TRUE,如果失败就返回FALSE,对话框类有两个重载函数处理数据交换错误。一个是OnDataExchangeError(),无论什么原因的错误都会调用这个函数,这个函数的默认实现在CWinDataExchange中,它仅仅是驱动PC喇叭发出一声蜂鸣并将出错的控件设为当前焦点。另一个函数是OnDataValidateError(),但是要到本文的第五章介绍DDV时才用得到。</P>
      
<H3><A name=usingddx></A><font color="#FFFF66">使用DDX</font></H3>
      
<P>在CMainDlg中添加几个变量,演示DDX的使用方法。</P>
<PRE><SPAN class=cpp-keyword><font color="#0033FF">class</font></SPAN><font color="#0033FF"> CMainDlg : <SPAN class=cpp-keyword>public</SPAN> ...
{
<SPAN class=cpp-comment>//...</SPAN>
    BEGIN_DDX_MAP(CMainDlg)
        DDX_CONTROL(IDC_EDIT, m_wndEdit)
        <B>DDX_TEXT(IDC_EDIT, m_sEditContents)
        DDX_INT(IDC_EDIT, m_nEditNumber)</B>
    END_DDX_MAP()
 
<SPAN class=cpp-keyword>protected</SPAN>:
    <SPAN class=cpp-comment>// DDX variables</SPAN>
    CString m_sEditContents;
    <SPAN class=cpp-keyword>int</SPAN>     m_nEditNumber;
};</font></PRE>
<P>在OK按钮的处理函数中,我们首先调用DoDataExchange()将将edit控件的数据传送给我们刚刚添加的两个变量,然后将结果显示在列表控件中。</P>
<PRE><font color="#0033FF">LRESULT CMainDlg::OnOK ( UINT uCode, <SPAN class=cpp-keyword>int</SPAN> nID, HWND hWndCtl )
{
CString str;
 
    <SPAN class=cpp-comment>// Transfer data from the controls to member variables.</SPAN>
    <SPAN class=cpp-keyword>if</SPAN> ( !DoDataExchange(<SPAN class=cpp-keyword>true</SPAN>) )
        <SPAN class=cpp-keyword>return</SPAN>;
 
    m_wndList.DeleteAllItems();
 
    m_wndList.InsertItem ( <SPAN class=cpp-literal>0</SPAN>, _T(<SPAN class=cpp-string>"DDX_TEXT"</SPAN>) );
    m_wndList.SetItemText ( <SPAN class=cpp-literal>0</SPAN>, <SPAN class=cpp-literal>1</SPAN>, m_sEditContents );
 
    str.Format ( _T(<SPAN class=cpp-string>"%d"</SPAN>), m_nEditNumber );
    m_wndList.InsertItem ( <SPAN class=cpp-literal>1</SPAN>, _T(<SPAN class=cpp-string>"DDX_INT"</SPAN>) );
    m_wndList.SetItemText ( <SPAN class=cpp-literal>1</SPAN>, <SPAN class=cpp-literal>1</SPAN>, str );
}</font></PRE>
      
<P><IMG height=246 alt=" [DDX results - 5K] " 
      src="images/ddxok4.png" 
      width=333 align=bottom border=0></P>

⌨️ 快捷键说明

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