?? wtl for mfc programmers, part iv - dialogs and controls - wtl.htm
字號:
<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<CButton> 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<CButtonImpl, CButton>
{
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<CMainDlg>
{
<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<CMainDlg>,
<B><SPAN class=cpp-keyword>public</SPAN> CWinDataExchange<CMainDlg></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<CEditImpl, CEdit>
{
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<CMainDlg>,
<SPAN class=cpp-keyword>public</SPAN> CWinDataExchange<CMainDlg>
{
<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 + -