?? wtl for mfc programmers, part iv.mht
字號:
use.</P><PRE>CMainDlg::CMainDlg() : m_wndOKBtn(<SPAN =
class=3Dcpp-keyword>this</SPAN>, <SPAN class=3Dcpp-literal>1</SPAN>),=20
m_wndExitBtn(<SPAN =
class=3Dcpp-keyword>this</SPAN>, <SPAN class=3Dcpp-literal>2</SPAN>)
{
}</PRE>
<P>The constructor parameters are a <CODE>CMessageMap*</CODE> and =
an=20
<CODE>ALT_MSG_MAP</CODE> section number. The first parameter will =
usually=20
be <CODE><SPAN class=3Dcpp-keyword>this</SPAN></CODE>, meaning =
that the=20
dialog's own message map will be used, and the second parameter =
tells the=20
object which <CODE>ALT_MSG_MAP</CODE> section it should send its =
messages=20
to.</P>
<P>Finally, we associate each <CODE>CContainedWindow</CODE> with a =
control.</P><PRE>LRESULT CMainDlg::OnInitDialog(...)
{
<SPAN class=3Dcpp-comment>// ...</SPAN>
<SPAN class=3Dcpp-comment>// Attach CContainedWindows to OK and Exit =
buttons</SPAN>
m_wndOKBtn.SubclassWindow ( GetDlgItem(IDOK) );
m_wndExitBtn.SubclassWindow ( GetDlgItem(IDCANCEL) );
=20
<SPAN class=3Dcpp-keyword>return</SPAN> TRUE;
}</PRE>
<P>Here are the new <CODE>WM_SETCURSOR</CODE> =
handlers:</P><PRE>LRESULT CMainDlg::OnSetCursor_OK (
HWND hwndCtrl, UINT uHitTest, UINT uMouseMsg )
{
<SPAN class=3Dcpp-keyword>static</SPAN> HCURSOR hcur =3D LoadCursor ( =
NULL, IDC_HAND );
=20
<SPAN class=3Dcpp-keyword>if</SPAN> ( NULL !=3D hcur )
{
SetCursor ( hcur );
<SPAN class=3Dcpp-keyword>return</SPAN> TRUE;
}
<SPAN class=3Dcpp-keyword>else</SPAN>
{
SetMsgHandled(<SPAN class=3Dcpp-keyword>false</SPAN>);
<SPAN class=3Dcpp-keyword>return</SPAN> FALSE;
}
}
=20
LRESULT CMainDlg::OnSetCursor_Exit (
HWND hwndCtrl, UINT uHitTest, UINT uMouseMsg )
{
<SPAN class=3Dcpp-keyword>static</SPAN> HCURSOR hcur =3D LoadCursor ( =
NULL, IDC_NO );
=20
<SPAN class=3Dcpp-keyword>if</SPAN> ( NULL !=3D hcur )
{
SetCursor ( hcur );
<SPAN class=3Dcpp-keyword>return</SPAN> TRUE;
}
<SPAN class=3Dcpp-keyword>else</SPAN>
{
SetMsgHandled(<SPAN class=3Dcpp-keyword>false</SPAN>);
<SPAN class=3Dcpp-keyword>return</SPAN> FALSE;
}
}</PRE>
<P>If you wanted to use <CODE>CButton</CODE> features, you could =
declare=20
the variables as:</P><PRE> CContainedWindowT<CButton> =
m_wndOKBtn;</PRE>
<P>and then the <CODE>CButton</CODE> methods would be =
available.</P>
<P>You can see the <CODE>WM_SETCURSOR</CODE> handlers in action =
when you=20
move the cursor over the buttons:</P>
<P><IMG height=3D220 alt=3D" [OK button cursor - 5K] "=20
src=3D"http://www.codeproject.com/wtl/WTL4MFC4/okbtncur.png" =
width=3D333=20
align=3Dbottom border=3D0> <IMG height=3D220 alt=3D" [Exit button =
cursor - 5K] "=20
src=3D"http://www.codeproject.com/wtl/WTL4MFC4/exitbtncur.png" =
width=3D333=20
align=3Dbottom border=3D0></P>
<H3><A name=3Datl3></A>ATL Way 3 - Subclassing</H3>
<P>Method 3 involves creating a <CODE>CWindowImpl</CODE>-derived =
class and=20
using it to subclass a control. This is similar to method 2, =
however the=20
message handlers go in the <CODE>CWindowImpl</CODE> class instead =
of the=20
dialog class.</P>
<P>ControlMania1 uses this method to subclass the <I>About</I> =
button in=20
the main dialog. Here is the <CODE>CButtonImpl</CODE> class, which =
is=20
derived from <CODE>CWindowImpl</CODE> and handles=20
<CODE>WM_SETCURSOR</CODE>:</P><PRE><SPAN =
class=3Dcpp-keyword>class</SPAN> CButtonImpl : <SPAN =
class=3Dcpp-keyword>public</SPAN> CWindowImpl<CButtonImpl, =
CButton>
{
BEGIN_MSG_MAP_EX(CButtonImpl)
MSG_WM_SETCURSOR(OnSetCursor)
END_MSG_MAP()
=20
LRESULT OnSetCursor(HWND hwndCtrl, UINT uHitTest, UINT uMouseMsg)
{
<SPAN class=3Dcpp-keyword>static</SPAN> HCURSOR hcur =3D LoadCursor =
( NULL, IDC_SIZEALL );
=20
<SPAN class=3Dcpp-keyword>if</SPAN> ( NULL !=3D hcur )
{
SetCursor ( hcur );
<SPAN class=3Dcpp-keyword>return</SPAN> TRUE;
}
<SPAN class=3Dcpp-keyword>else</SPAN>
{
SetMsgHandled(<SPAN class=3Dcpp-keyword>false</SPAN>);
<SPAN class=3Dcpp-keyword>return</SPAN> FALSE;
}
}
};</PRE>
<P>Then in the main dialog, we declare a <CODE>CButtonImpl</CODE> =
member=20
variable:</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> CMainDlg =
: <SPAN class=3Dcpp-keyword>public</SPAN> CDialogImpl<CMainDlg>
{
<SPAN class=3Dcpp-comment>// ...</SPAN>
<SPAN class=3Dcpp-keyword>protected</SPAN>:
CContainedWindow m_wndOKBtn, m_wndExitBtn;
<B>CButtonImpl m_wndAboutBtn;</B>
};</PRE>
<P>And finally, in <CODE>OnInitDialog()</CODE>, we subclass the=20
button.</P><PRE>LRESULT CMainDlg::OnInitDialog(...)
{
<SPAN class=3Dcpp-comment>// ...</SPAN>
<SPAN class=3Dcpp-comment>// Attach CContainedWindows to OK and Exit =
buttons</SPAN>
m_wndOKBtn.SubclassWindow ( GetDlgItem(IDOK) );
m_wndExitBtn.SubclassWindow ( GetDlgItem(IDCANCEL) );
=20
<B><SPAN class=3Dcpp-comment>// CButtonImpl: subclass the About =
button</SPAN>
m_wndAboutBtn.SubclassWindow ( GetDlgItem(ID_APP_ABOUT) );</B>
=20
<SPAN class=3Dcpp-keyword>return</SPAN> TRUE;
}</PRE>
<H3><A name=3Dwtlway></A>The WTL Way - DDX</H3>
<P>WTL's DDX (dialog data exchange) support works a lot like =
MFC's, and it=20
can rather painlessly connect a variable to a control. To begin, =
you need=20
a <CODE>CWindowImpl</CODE>-derived class as in the previous =
example. We'll=20
be using a new class this time, <CODE>CEditImpl</CODE>, since this =
example=20
will subclass the edit control. You also need to #include atlddx.h =
in=20
stdafx.h to get the DDX code.</P>
<P>To add DDX support to <CODE>CMainDlg</CODE>, add=20
<CODE>CWinDataExchange</CODE> to the inheritance =
list:</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> CMainDlg : <SPAN =
class=3Dcpp-keyword>public</SPAN> CDialogImpl<CMainDlg>,=20
<B><SPAN class=3Dcpp-keyword>public</SPAN> =
CWinDataExchange<CMainDlg></B>
{
<SPAN class=3Dcpp-comment>//...</SPAN>
};</PRE>
<P>Next you create a DDX map in the class, which is similar to the =
<CODE>DoDataExchange()</CODE> function that the ClassWizard =
generates in=20
MFC apps. There are several <CODE>DDX_*</CODE> macros for varying =
types of=20
data; the one we'll use here is <CODE>DDX_CONTROL</CODE> to =
connect a=20
variable with a control. This time, we'll use =
<CODE>CEditImpl</CODE> that=20
handles <CODE>WM_CONTEXTMENU</CODE> to do something when you =
right-click=20
in the control.</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> =
CEditImpl : <SPAN class=3Dcpp-keyword>public</SPAN> =
CWindowImpl<CEditImpl, CEdit>
{
BEGIN_MSG_MAP_EX(CEditImpl)
MSG_WM_CONTEXTMENU(OnContextMenu)
END_MSG_MAP()
=20
<SPAN class=3Dcpp-keyword>void</SPAN> OnContextMenu ( HWND hwndCtrl, =
CPoint ptClick )
{
MessageBox(<SPAN class=3Dcpp-string>"Edit control handled =
WM_CONTEXTMENU"</SPAN>);
}
};
=20
<SPAN class=3Dcpp-keyword>class</SPAN> CMainDlg : <SPAN =
class=3Dcpp-keyword>public</SPAN> CDialogImpl<CMainDlg>,=20
<SPAN class=3Dcpp-keyword>public</SPAN> =
CWinDataExchange<CMainDlg>
{
<SPAN class=3Dcpp-comment>//...</SPAN>
=20
<B>BEGIN_DDX_MAP(CMainDlg)
DDX_CONTROL(IDC_EDIT, m_wndEdit)
END_DDX_MAP()</B>
=20
<SPAN class=3Dcpp-keyword>protected</SPAN>:
CContainedWindow m_wndOKBtn, m_wndExitBtn;
CButtonImpl m_wndAboutBtn;<B>
</B> <B>CEditImpl m_wndEdit;</B>
};</PRE>
<P>Finally, in <CODE>OnInitDialog()</CODE>, we call the=20
<CODE>DoDataExchange()</CODE> function that is inherited from=20
<CODE>CWinDataExchange</CODE>. The first time=20
<CODE>DoDataExchange()</CODE> is called, it subclasses controls as =
necessary. So in this example, <CODE>DoDataExchange()</CODE> will =
subclass=20
the control with ID IDC_EDIT, and connect it to the variable=20
<CODE>m_wndEdit</CODE>.</P><PRE>LRESULT =
CMainDlg::OnInitDialog(...)
{
<SPAN class=3Dcpp-comment>// ...</SPAN>
<SPAN class=3Dcpp-comment>// Attach CContainedWindows to OK and Exit =
buttons</SPAN>
m_wndOKBtn.SubclassWindow ( GetDlgItem(IDOK) );
m_wndExitBtn.SubclassWindow ( GetDlgItem(IDCANCEL) );
=20
<SPAN class=3Dcpp-comment>// CButtonImpl: subclass the About =
button</SPAN>
m_wndAboutBtn.SubclassWindow ( GetDlgItem(ID_APP_ABOUT) );
=20
<B><SPAN class=3Dcpp-comment>// First DDX call, hooks up variables =
to controls.</B></SPAN>
<B>DoDataExchange(<SPAN class=3Dcpp-keyword>false</SPAN>);</B>
=20
<SPAN class=3Dcpp-keyword>return</SPAN> TRUE;
}</PRE>
<P>The parameter to <CODE>DoDataExchange()</CODE> has the same =
meaning as=20
the parameter to MFC's <CODE>UpdateData()</CODE> function. We'll =
cover=20
that in more detail in the next section.</P>
<P>If you run the ControlMania1 project, you can see all this =
subclassing=20
in action. Right-clicking in the edit box will pop up the message =
box, and=20
the cursor will change shape over the buttons as shown =
earlier.</P>
<H2><A name=3Dmoreddx></A>More on DDX</H2>
<P>DDX can, of course, actually do data exchange too. WTL supports =
exchanging string data between an edit box and a string variable. =
It can=20
also parse a string as a number, and transfer that data between an =
integer=20
or floating-point variable. And it also supports transferring the =
state of=20
a check box or group of radio buttons to/from an <CODE><SPAN=20
class=3Dcpp-keyword>int</SPAN></CODE>.</P>
<H3><A name=3Dddxmacros></A>DDX macros</H3>
<P>There are six macros used in DDX. Each one expands to a=20
<CODE>CWinDataExchange</CODE> method call that does the work. The =
macros=20
all have the general form: <CODE>DDX_FOO(controlID, =
variable)</CODE>. Each=20
macro takes a different type of variable, and some like=20
<CODE>DDX_TEXT</CODE> are overloaded to accept many types.</P>
<DL>
<DT><CODE>DDX_TEXT</CODE>=20
<DD>Transfers text data to/from an edit box. The variable can be =
a=20
<CODE>CString</CODE>, <CODE>BSTR</CODE>, <CODE>CComBSTR</CODE>, =
or=20
statically-allocated character array. Using an array allocated =
with=20
<CODE><SPAN class=3Dcpp-keyword>new</SPAN></CODE> will not work. =
<DT><CODE>DDX_INT</CODE>=20
<DD>Transfers numerical data between an edit box and an =
<CODE><SPAN=20
class=3Dcpp-keyword>int</SPAN></CODE>.=20
<DT><CODE>DDX_UINT</CODE>=20
<DD>Transfers numerical data between an edit box and an =
<CODE><SPAN=20
class=3Dcpp-keyword>unsigned</SPAN> <SPAN=20
class=3Dcpp-keyword>int</SPAN></CODE>.=20
<DT><CODE>DDX_FLOAT</CODE>=20
<DD>Transfers numerical data between an edit box and a =
<CODE><SPAN=20
class=3Dcpp-keyword>float</SPAN></CODE> or <CODE><SPAN=20
class=3Dcpp-keyword>double</SPAN></CODE>.=20
<DT><CODE>DDX_CHECK</CODE>=20
<DD>Transfers the state of a check box to/from an <CODE><SPAN=20
class=3Dcpp-keyword>int</SPAN></CODE>.=20
<DT><CODE>DDX_RADIO</CODE>=20
<DD>Transfers the state of a group of radio buttons to/from an=20
<CODE><SPAN class=3Dcpp-keyword>int</SPAN></CODE>. </DD></DL>
<P>A note about using <CODE>DDX_FLOAT</CODE>: When you use this in =
your=20
app, you need to add a #define to stdafx.h, before any WTL headers =
are=20
included:</P><PRE><SPAN class=3Dcpp-preprocessor>#define =
_ATL_USE_DDX_FLOAT</SPAN></PRE>
<P>This is necessary because by default, floating-point support is =
disabled as a size optimization.</P>
<H3><A name=3Dmoreddx></A>More about DoDataExchange()</H3>
<P>You call the <CODE>DoDataExchange()</CODE> method just as you =
call=20
<CODE>UpdateData()</CODE> in MFC. The prototype for=20
<CODE>DoDataExchange()</CODE> is:</P><PRE>BOOL DoDataExchange ( =
BOOL bSaveAndValidate =3D FALSE,=20
UINT nCtlID =3D (UINT)-<SPAN =
class=3Dcpp-literal>1</SPAN> );</PRE>
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -