?? wtl for mfc programmers, part iv.mht
字號:
you can use the MFC documentation whilst using the WTL wrappers. =
Failing=20
that, the F12 key comes in handy when you need to jump to the =
definition=20
of one of the classes.</P>
<P>Here are the wrapper classes for built-in controls:</P>
<UL>
<LI>User controls: <CODE>CStatic</CODE>, <CODE>CButton</CODE>,=20
<CODE>CListBox</CODE>, <CODE>CComboBox</CODE>, =
<CODE>CEdit</CODE>,=20
<CODE>CScrollBar</CODE>, <CODE>CDragListBox</CODE>=20
<LI>Common controls: <CODE>CImageList</CODE>, =
<CODE>CListViewCtrl</CODE>=20
(<CODE>CListCtrl</CODE> in MFC), <CODE>CTreeViewCtrl</CODE>=20
(<CODE>CTreeCtrl</CODE> in MFC), <CODE>CHeaderCtrl</CODE>,=20
<CODE>CToolBarCtrl</CODE>, <CODE>CStatusBarCtrl</CODE>,=20
<CODE>CTabCtrl</CODE>, <CODE>CToolTipCtrl</CODE>,=20
<CODE>CTrackBarCtrl</CODE> (<CODE>CSliderCtrl</CODE> in MFC),=20
<CODE>CUpDownCtrl</CODE> (<CODE>CSpinButtonCtrl</CODE> in MFC),=20
<CODE>CProgressBarCtrl</CODE>, <CODE>CHotKeyCtrl</CODE>,=20
<CODE>CAnimateCtrl</CODE>, <CODE>CRichEditCtrl</CODE>,=20
<CODE>CReBarCtrl</CODE>, <CODE>CComboBoxEx</CODE>,=20
<CODE>CDateTimePickerCtrl</CODE>, =
<CODE>CMonthCalendarCtrl</CODE>,=20
<CODE>CIPAddressCtrl</CODE>=20
<LI>Common control wrappers not in MFC: <CODE>CPagerCtrl</CODE>, =
<CODE>CFlatScrollBar</CODE>, <CODE>CLinkCtrl</CODE> (clickable=20
hyperlink, available on XP only) </LI></UL>
<P>There are also a few WTL-specific classes: =
<CODE>CBitmapButton</CODE>,=20
<CODE>CCheckListViewCtrl</CODE> (list view control with check =
boxes),=20
<CODE>CTreeViewCtrlEx</CODE> and <CODE>CTreeItem</CODE> (used =
together,=20
<CODE>CTreeItem</CODE> wraps an <CODE>HTREEITEM</CODE>),=20
<CODE>CHyperLink</CODE> (clickable hyperlink, available on all =
OSes)</P>
<P>One thing to note is that most of the wrapper classes are =
window=20
interface classes, like <CODE>CWindow</CODE>. They wrap an=20
<CODE>HWND</CODE> and provide wrappers around messages (for =
instance,=20
<CODE>CListBox::GetCurSel()</CODE> wraps =
<CODE>LB_GETCURSEL</CODE>). So=20
like <CODE>CWindow</CODE>, it is cheap to create a temporary =
control=20
wrapper and attach it to an existing control. Also like=20
<CODE>CWindow</CODE>, the control is not destroyed when the =
control=20
wrapper is destructed. The exceptions are =
<CODE>CBitmapButton</CODE>,=20
<CODE>CCheckListViewCtrl</CODE>, and <CODE>CHyperLink</CODE>.</P>
<P>Since these articles are aimed at experienced MFC programmers, =
I won't=20
be spending much time on the details of the wrapper classes that =
are=20
similar to their MFC counterparts. I will, however, be covering =
the new=20
classes in WTL; <CODE>CBitmapButton</CODE> is quite different from =
the MFC=20
class of the same name, and <CODE>CHyperLink</CODE> is completely =
new.</P>
<H2><A name=3Dappwizard></A>Creating a Dialog-Based App with the=20
AppWizard</H2>
<P>Fire up VC and start the WTL AppWizard. I'm sure you're as =
tired as I=20
am with clock apps, so let's call our next app =
<I>ControlMania1</I>. On=20
the first page of the AppWizard, click <I>Dialog Based</I>. We =
also have a=20
choice between making a modal or modeless dialog. The difference =
is=20
important and I will cover it in Part V, but for now let's go with =
the=20
simpler one, modal. Check <I>Modal Dialog</I> and <I>Generate .CPP =
Files</I> as shown here:</P>
<P><IMG height=3D387 alt=3D" [AppWizard page 1 - 21K] "=20
src=3D"http://www.codeproject.com/wtl/WTL4MFC4/appwiz1.png" =
width=3D477=20
align=3Dbottom border=3D0></P>
<P>All the options on the second page are only meaningful when the =
main=20
window is a frame window, so they are all disabled. Click =
<I>Finish</I>=20
and then <I>OK</I> to complete the wizard.</P>
<P>As you might expect, the AppWizard-generated code is much =
simpler for a=20
dialog-based app. ControlMania1.cpp has the =
<CODE>_tWinMain()</CODE>=20
function, here are the important parts:</P><PRE><SPAN =
class=3Dcpp-keyword>int</SPAN> WINAPI _tWinMain (=20
HINSTANCE hInstance, HINSTANCE <SPAN =
class=3Dcpp-comment>/*hPrevInstance*/</SPAN>,=20
LPTSTR lpstrCmdLine, <SPAN class=3Dcpp-keyword>int</SPAN> nCmdShow )
{
HRESULT hRes =3D ::CoInitialize(NULL);
=20
AtlInitCommonControls(ICC_COOL_CLASSES | ICC_BAR_CLASSES);
=20
hRes =3D _Module.Init(NULL, hInstance);
=20
<SPAN class=3Dcpp-keyword>int</SPAN> nRet =3D <SPAN =
class=3Dcpp-literal>0</SPAN>;
<SPAN class=3Dcpp-comment>// BLOCK: Run application</SPAN>
{
CMainDlg dlgMain;
nRet =3D dlgMain.DoModal();
}
=20
_Module.Term();
::CoUninitialize();
<SPAN class=3Dcpp-keyword>return</SPAN> nRet;
}</PRE>
<P>The code first initializes COM and creates a single-threaded =
apartment.=20
This is necessary for dialogs that host ActiveX controls. Next, =
the code=20
calls the WTL utility function =
<CODE>AtlInitCommonControls()</CODE>, which=20
is a wrapper for <CODE>InitCommonControlsEx()</CODE>. The global=20
<CODE>_Module</CODE> is initialized, and the main dialog is =
displayed.=20
(Note that ATL dialogs created with <CODE>DoModal()</CODE> =
actually are=20
modal, unlike MFC where all dialogs are modeless and MFC simulates =
modality by manually disabling the dialog's parent.) Finally,=20
<CODE>_Module</CODE> and COM are uninitialized, and the value =
returned by=20
<CODE>DoModal()</CODE> is used as the app's exit code.</P>
<BLOCKQUOTE>
<P>The block around the <CODE>CMainDlg</CODE> variable is =
important=20
because <CODE>CMainDlg</CODE> may have members that use ATL and =
WTL=20
features. Those members may also use ATL/WTL features in their=20
destructors. If the block were not present, the =
<CODE>CMainDlg</CODE>=20
destructor (and the destructors of the members) would run after =
the call=20
to <CODE>_Module.Term()</CODE> (which uninitializes ATL/WTL) and =
try to=20
use ATL/WTL features, which could cause a hard-to-diagnose =
crash. (As a=20
historical note, the WTL 3 AppWizard-generated code did not have =
a block=20
there, and some of my apps did crash.)</P></BLOCKQUOTE>
<P>You can build and run the app right away, although the dialog =
is pretty=20
bare:</P>
<P><IMG height=3D187 alt=3D" [Bare dialog - 4K] "=20
src=3D"http://www.codeproject.com/wtl/WTL4MFC4/bareapp.png" =
width=3D287=20
align=3Dbottom border=3D0></P>
<P>The code in <CODE>CMainDlg</CODE> handles =
<CODE>WM_INITDIALOG</CODE>,=20
<CODE>WM_CLOSE</CODE>, and all three buttons. Take a quick glance =
through=20
the code now if you like; you should be able to follow the=20
<CODE>CMainDlg</CODE> declaration, its message map, and its =
message=20
handlers.</P>
<P>This sample project will demonstrate how to hook up variables =
to the=20
controls. Here's the app with a couple more controls; you can =
refer back=20
to this diagram for the following discussions.</P>
<P><IMG height=3D227 alt=3D" [Add'l controls - 6K] "=20
src=3D"http://www.codeproject.com/wtl/WTL4MFC4/cm1ctrls.png" =
width=3D507=20
align=3Dbottom border=3D0></P>
<P>Since the app uses a list view control, the call to=20
<CODE>AtlInitCommonControls()</CODE> will need to be changed. =
Change it=20
to:</P><PRE> AtlInitCommonControls ( ICC_WIN95_CLASSES );</PRE>
<P>That registers more classes than necessary, but it saves us =
having to=20
remember to add <CODE>ICC_*</CODE> constants when we add different =
types=20
of controls to the dialog.</P>
<H2><A name=3Dusingwrap></A>Using the Control Wrapper Classes</H2>
<P>There are several ways to associate a member variable with a =
control.=20
Some use plain <CODE>CWindow</CODE>s (or another window interface =
class,=20
like <CODE>CListViewCtrl</CODE>), while others use a=20
<CODE>CWindowImpl</CODE>-derived class. Using a =
<CODE>CWindow</CODE> is=20
fine if you just need a temporary variable, while a=20
<CODE>CWindowImpl</CODE> is required if you need to subclass a =
control and=20
handle messages sent to it.</P>
<H3><A name=3Datl1></A>ATL Way 1 - Attaching a CWindow</H3>
<P>The simplest method is to declare a <CODE>CWindow</CODE> or =
other=20
window interface class, and call its <CODE>Attach()</CODE> method. =
You can=20
also use the <CODE>CWindow</CODE> constructor or assignment =
operator to=20
associate the variable with a control's <CODE>HWND</CODE>.</P>
<P>This code demonstrates all three methods of associating =
variables with=20
the list control:</P><PRE>HWND hwndList =3D GetDlgItem(IDC_LIST);
CListViewCtrl wndList1 (hwndList); <SPAN class=3Dcpp-comment>// use =
constructor</SPAN>
CListViewCtrl wndList2, wndList3;
=20
wndList2.Attach ( hwndList ); <SPAN class=3Dcpp-comment>// use =
Attach method</SPAN>
wndList3 =3D hwndList; <SPAN class=3Dcpp-comment>// use =
assignment operator</SPAN></PRE>
<P>Remember that the <CODE>CWindow</CODE> destructor does not =
destroy the=20
window, so there is no need to detach the variables before they go =
out of=20
scope. You can also use this technique with member variables if =
you wish -=20
you can attach the variables in the <CODE>OnInitDialog()</CODE>=20
handler.</P>
<H3><A name=3Datl2></A>ATL Way 2 - CContainedWindow</H3>
<P><CODE>CContainedWindow</CODE> is sort of halfway between using =
a=20
<CODE>CWindow</CODE> and a <CODE>CWindowImpl</CODE>. It lets you =
subclass=20
a control, then handle that control's messages <I>in the control's =
parent=20
window</I>. This lets you put all the message handlers in the =
dialog=20
class, and you don't have to write separate =
<CODE>CWindowImpl</CODE>=20
classes for each control. Note that you don't use=20
<CODE>CContainedWindow</CODE> to handle <CODE>WM_COMMAND</CODE>,=20
<CODE>WM_NOTIFY</CODE>, or other notification messages, because =
those are=20
always sent to the control's parent.</P>
<P>The actual class, <CODE>CContainedWindowT</CODE>, is a template =
class=20
that takes a window interface class name as its template =
parameter. There=20
is a specialization <CODE>CContainedWindowT<CWindow></CODE> =
that=20
works like a plain <CODE>CWindow</CODE>; this is typedef'ed to the =
shorter=20
name <CODE>CContainedWindow</CODE>. To use a different window =
interface=20
class, specify its name as the template parameter, for example=20
<CODE>CContainedWindowT<CListViewCtrl></CODE>.</P>
<P>To hook up a <CODE>CContainedWindow</CODE>, you do four =
things:</P>
<OL>
<LI>Create a <CODE>CContainedWindowT</CODE> member variable in =
the=20
dialog.=20
<LI>Put handlers in an <CODE>ALT_MSG_MAP</CODE> section of the =
dialog's=20
message map=20
<LI>In the dialog's constructor, call the =
<CODE>CContainedWindowT</CODE>=20
constructor and tell it which <CODE>ALT_MSG_MAP</CODE> section =
it should=20
route messages to.=20
<LI>In <CODE>OnInitDialog()</CODE>, call the=20
<CODE>CContainedWindowT::SubclassWindow()</CODE> method to =
associate a=20
variable with a control. </LI></OL>
<P>In ControlMania1, we'll use a <CODE>CContainedWindow</CODE> for =
each of=20
the three buttons. The dialog will handle =
<CODE>WM_SETCURSOR</CODE>=20
messages sent to each button, and change the cursor.</P>
<P>Let's go through the steps. First, we add =
<CODE>CContainedWindow</CODE>=20
members in <CODE>CMainDlg.</CODE></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;
};</PRE>
<P>Second, we add <CODE>ALT_MSG_MAP</CODE> sections. The <I>OK</I> =
button=20
will use section 1, while the <I>Exit</I> button will use section =
2. This=20
means that all messages sent to the <I>OK</I> button will be =
routed to the=20
<CODE>ALT_MSG_MAP(<SPAN class=3Dcpp-literal>1</SPAN>)</CODE> =
section, and=20
all messages sent to the <I>Exit</I> button will be routed to the=20
<CODE>ALT_MSG_MAP(<SPAN class=3Dcpp-literal>2</SPAN>)</CODE> =
section.</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> CMainDlg : <SPAN =
class=3Dcpp-keyword>public</SPAN> CDialogImpl<CMainDlg>
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
BEGIN_MSG_MAP_EX(CMainDlg)
MESSAGE_HANDLER(WM_INITDIALOG, OnInitDialog)
COMMAND_ID_HANDLER(ID_APP_ABOUT, OnAppAbout)
COMMAND_ID_HANDLER(IDOK, OnOK)
COMMAND_ID_HANDLER(IDCANCEL, OnCancel)
<B>ALT_MSG_MAP(<SPAN class=3Dcpp-literal>1</SPAN>)
MSG_WM_SETCURSOR(OnSetCursor_OK)
ALT_MSG_MAP(<SPAN class=3Dcpp-literal>2</SPAN>)
MSG_WM_SETCURSOR(OnSetCursor_Exit)</B>
END_MSG_MAP()
=20
<B>LRESULT OnSetCursor_OK(HWND hwndCtrl, UINT uHitTest, UINT =
uMouseMsg);
LRESULT OnSetCursor_Exit(HWND hwndCtrl, UINT uHitTest, UINT =
uMouseMsg);</B>
};</PRE>
<P>Third, we call the <CODE>CContainedWindow</CODE> constructor =
for each=20
member and tell it which <CODE>ALT_MSG_MAP</CODE> section to =
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -