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

📄 wtl for mfc programmers, part i.mht

📁 大家知道wtl是window UI库
💻 MHT
📖 第 1 页 / 共 5 页
字号:
    DECLARE_WND_CLASS(_T(<SPAN class=3Dcpp-string>"My Window =
Class"</SPAN>))
};</PRE>
      <P>Next comes the message map. ATL message maps are much simpler =
than MFC=20
      maps. An ATL map expands into a big switch statement; the switch =
looks for=20
      the right handler and calls the corresponding function. The macros =
for the=20
      message map are <CODE>BEGIN_MSG_MAP</CODE> and =
<CODE>END_MSG_MAP</CODE>.=20
      Let's add an empty map to our window.</P><PRE><SPAN =
class=3Dcpp-keyword>class</SPAN> CMyWindow : <SPAN =
class=3Dcpp-keyword>public</SPAN> CWindowImpl&lt;CMyWindow&gt;
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    DECLARE_WND_CLASS(_T(<SPAN class=3Dcpp-string>"My Window =
Class"</SPAN>))
=20
    BEGIN_MSG_MAP(CMyWindow)
    END_MSG_MAP()
};</PRE>
      <P>I'll cover how to add handlers to the map in the next section. =
Finally,=20
      we need to define the <I>window traits</I> for our class. Window =
traits=20
      are a combination of window styles and extended window styles that =
are=20
      used when creating the window. The styles are specified as =
template=20
      parameters so the caller doesn't have to be bothered with getting =
the=20
      styles right when it creates our window. Here's a sample traits =
definition=20
      using the ATL class <CODE>CWinTraits</CODE>:</P><PRE><SPAN =
class=3Dcpp-keyword>typedef</SPAN> CWinTraits&lt;WS_OVERLAPPEDWINDOW | =
WS_CLIPCHILDREN,
                   WS_EX_APPWINDOW&gt; CMyWindowTraits;
=20
<SPAN class=3Dcpp-keyword>class</SPAN> CMyWindow : <SPAN =
class=3Dcpp-keyword>public</SPAN> CWindowImpl&lt;CMyWindow, CWindow, =
CMyWindowTraits&gt;
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    DECLARE_WND_CLASS(_T(<SPAN class=3Dcpp-string>"My Window =
Class"</SPAN>))
=20
    BEGIN_MSG_MAP(CMyWindow)
    END_MSG_MAP()
};</PRE>
      <P>The caller <I>can</I> override the styles in the=20
      <CODE>CMyWindowTraits</CODE> definition, but generally this is not =

      necessary. ATL also has a few predefined <CODE>CWinTraits</CODE>=20
      specializations, one of which is perfect for top-level windows =
like ours,=20
      <CODE>CFrameWinTraits</CODE>:</P><PRE><SPAN =
class=3Dcpp-keyword>typedef</SPAN> CWinTraits&lt;WS_OVERLAPPEDWINDOW | =
WS_CLIPCHILDREN |
                     WS_CLIPSIBLINGS,
                   WS_EX_APPWINDOW | WS_EX_WINDOWEDGE&gt;
        CFrameWinTraits;</PRE>
      <H3><A name=3Dmsgmap></A>Filling in the message map</H3>
      <P>The ATL message map is one area that is lacking in=20
      developer-friendliness, and one area that WTL greatly improves on. =

      ClassView does at least give you the ability to add message =
handers,=20
      however ATL doesn't have message-specific macros and automatic =
parameter=20
      unpacking like MFC does. In ATL, there are just three types of =
message=20
      handlers, one for <CODE>WM_NOTIFY</CODE>, one for =
<CODE>WM_COMMAND</CODE>,=20
      and one for everything else. Let's start by adding handlers for=20
      <CODE>WM_CLOSE</CODE> and <CODE>WM_DESTROY</CODE> to our =
window.</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> CMyWindow : <SPAN =
class=3Dcpp-keyword>public</SPAN> CWindowImpl&lt;CMyWindow, CWindow, =
CFrameWinTraits&gt;
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    DECLARE_WND_CLASS(_T(<SPAN class=3Dcpp-string>"My Window =
Class"</SPAN>))
=20
    BEGIN_MSG_MAP(CMyWindow)
        MESSAGE_HANDLER(WM_CLOSE, OnClose)
        MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
    END_MSG_MAP()
=20
    LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; =
bHandled)
    {
        DestroyWindow();
        <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
    }
=20
    LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; =
bHandled)
    {
        PostQuitMessage(<SPAN class=3Dcpp-literal>0</SPAN>);
        <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
    }
};</PRE>
      <P>You'll notice that the handlers get the raw <CODE>WPARAM</CODE> =
and=20
      <CODE>LPARAM</CODE> values; you have to unpack them yourself when =
a=20
      message uses those parameters. There is also a fourth parameter,=20
      <CODE>bHandled</CODE>. This parameter is set to <CODE>TRUE</CODE> =
by ATL=20
      before the handler is called. If you want ATL's default=20
      <CODE>WindowProc()</CODE> to handle the message as well after your =
handler=20
      returns, you set <CODE>bHandled</CODE> to <CODE>FALSE</CODE>. This =
is=20
      different than MFC, where you have to explicitly call the =
base-class=20
      implementation of a message handler.</P>
      <P>Let's add a <CODE>WM_COMMAND</CODE> handler as well. Assuming =
our=20
      window's menu has an About item with ID =
<CODE>IDC_ABOUT</CODE>:</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> =
CMyWindow : <SPAN class=3Dcpp-keyword>public</SPAN> =
CWindowImpl&lt;CMyWindow, CWindow, CFrameWinTraits&gt;
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    DECLARE_WND_CLASS(_T(<SPAN class=3Dcpp-string>"My Window =
Class"</SPAN>))
=20
    BEGIN_MSG_MAP(CMyWindow)
        MESSAGE_HANDLER(WM_CLOSE, OnClose)
        MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
        COMMAND_ID_HANDLER(IDC_ABOUT, OnAbout)
    END_MSG_MAP()
=20
    LRESULT OnClose(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; =
bHandled)
    {
        DestroyWindow();
        <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
    }
=20
    LRESULT OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL&amp; =
bHandled)
    {
        PostQuitMessage(<SPAN class=3Dcpp-literal>0</SPAN>);
        <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
    }
=20
    LRESULT OnAbout(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL&amp; =
bHandled)
    {
        MessageBox ( _T(<SPAN class=3Dcpp-string>"Sample ATL =
window"</SPAN>), _T(<SPAN class=3Dcpp-string>"About MyWindow"</SPAN>) );
        <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
    }
};</PRE>
      <P>Notice that the <CODE>COMMAND_HANDLER</CODE> macro does unpack =
the=20
      message parameters for you. The <CODE>NOTIFY_HANDLER</CODE> macro =
is=20
      similar, and unpacks the <CODE>WM_NOTIFY</CODE> message =
parameters.</P>
      <H2><A name=3Dadvmsgmap></A>Advanced Message Maps and Mix-in =
Classes</H2>
      <P>One major difference in ATL is that <I>any</I> C++ class can =
handle=20
      messages, unlike MFC where message-handling duties are split =
between=20
      <CODE>CWnd</CODE> and <CODE>CCmdTarget</CODE>, plus several =
classes that=20
      have a <CODE>PreTranslateMessage()</CODE> method. This ability =
lets us=20
      write what are commonly called "mix-in" classes, so that we can =
add=20
      features to our window simply by adding classes to the inheritance =

      list.</P>
      <P>A base class with a message map is usually a template that =
takes the=20
      derived class name as a template parameter, so it can access =
members of=20
      the derived class like <CODE>m_hWnd</CODE> (the <CODE>HWND</CODE> =
member=20
      in <CODE>CWindow</CODE>). Let's look at a mix-in class that paints =
the=20
      window background by handling =
<CODE>WM_ERASEBKGND</CODE>.</P><PRE><SPAN =
class=3Dcpp-keyword>template</SPAN> &lt;<SPAN =
class=3Dcpp-keyword>class</SPAN> T, COLORREF t_crBrushColor&gt;
<SPAN class=3Dcpp-keyword>class</SPAN> CPaintBkgnd : <SPAN =
class=3Dcpp-keyword>public</SPAN> CMessageMap
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    CPaintBkgnd() { m_hbrBkgnd =3D CreateSolidBrush(t_crBrushColor); }
    ~CPaintBkgnd() { DeleteObject ( m_hbrBkgnd ); }
=20
    BEGIN_MSG_MAP(CPaintBkgnd)
        MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBkgnd)
    END_MSG_MAP()
=20
    LRESULT OnEraseBkgnd(UINT uMsg, WPARAM wParam, LPARAM lParam, =
BOOL&amp; bHandled)
    {
    T*   pT =3D <SPAN =
class=3Dcpp-keyword>static_cast</SPAN>&lt;T*&gt;(<SPAN =
class=3Dcpp-keyword>this</SPAN>);
    HDC  dc =3D (HDC) wParam;
    RECT rcClient;
=20
        pT-&gt;GetClientRect ( &amp;rcClient );
        FillRect ( dc, &amp;rcClient, m_hbrBkgnd );
        <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>1</SPAN>;    <SPAN class=3Dcpp-comment>// we painted =
the background</SPAN>
    }
=20
<SPAN class=3Dcpp-keyword>protected</SPAN>:
    HBRUSH m_hbrBkgnd;
};</PRE>
      <P>Let's go through this new class. First, =
<CODE>CPaintBkgnd</CODE> has=20
      two template parameters: the name of the derived class that is =
using=20
      <CODE>CPaintBkgnd</CODE>, and a color to use for the background. =
(The=20
      <CODE>t_</CODE> prefix is often used for template parameters that =
are=20
      plain values.) <CODE>CPaintBkgnd</CODE> also derived from the ATL =
class=20
      <CODE>CMessageMap</CODE>. This is not strictly necessary, as the=20
      <CODE>BEGIN_MSG_MAP</CODE> macro is all that is required for the =
class to=20
      handle messages, so when you see other code samples you might not =
see that=20
      used as a base class.</P>
      <P>The constructor and destructor are pretty simple, they create =
and=20
      destroy a brush of the color passed as =
<CODE>t_crBrushColor</CODE>. Next=20
      comes the message map, which handles <CODE>WM_ERASEBKGND</CODE>. =
Finally,=20
      there's the <CODE>OnEraseBkgnd()</CODE> handler which fills in the =
window=20
      with the brush created in the constructor. There are two things of =
note=20
      going on in <CODE>OnEraseBkgnd()</CODE>. First, it uses the =
derived=20
      class's window functions (namely <CODE>GetClientRect()</CODE>). =
How do we=20
      know that there even <I>is</I> a <CODE>GetClientRect()</CODE> in =
the=20
      derived class? The code wouldn't compile if there isn't! The =
compiler=20
      ensures that the derived class <CODE>T</CODE> is derived from=20
      <CODE>CWindow</CODE>. Second, <CODE>OnEraseBkgnd()</CODE> has to =
unpack=20
      the device context from <CODE>wParam</CODE>. (WTL takes care of =
this,=20
      we'll get there eventually, promise!)</P>
      <P>To use this mix-in class with our window, we do two things. =
First, we=20
      add it to the inheritance list:</P><PRE><SPAN =
class=3Dcpp-keyword>class</SPAN> CMyWindow : <SPAN =
class=3Dcpp-keyword>public</SPAN> CWindowImpl&lt;CMyWindow, CWindow, =
CFrameWinTraits&gt;,
                  <FONT color=3Dred><SPAN =
class=3Dcpp-keyword>public</SPAN> CPaintBkgnd&lt;CMyWindow, RGB(<SPAN =
class=3Dcpp-literal>0</SPAN>,<SPAN class=3Dcpp-literal>0</SPAN>,<SPAN =
class=3Dcpp-literal>255</SPAN>)&gt;</FONT></PRE>
      <P>Second, we need to get <CODE>CMyWindow</CODE> to pass messages =
along to=20
      <CODE>CPaintBkgnd</CODE>. This is called <I>chaining</I> message =
maps. In=20
      the <CODE>CMyWindow</CODE> message map, we add the=20
      <CODE>CHAIN_MSG_MAP</CODE> macro:</P><PRE><SPAN =
class=3Dcpp-keyword>class</SPAN> CMyWindow : <SPAN =
class=3Dcpp-keyword>public</SPAN> CWindowImpl&lt;CMyWindow, CWindow, =
CFrameWinTraits&gt;,
                  <SPAN class=3Dcpp-keyword>public</SPAN> =
CPaintBkgnd&lt;CMyWindow, RGB(<SPAN class=3Dcpp-literal>0</SPAN>,<SPAN =
class=3Dcpp-literal>0</SPAN>,<SPAN class=3Dcpp-literal>255</SPAN>)&gt;=20
{
...
<FONT color=3Dred><SPAN class=3Dcpp-keyword>typedef</SPAN> =
CPaintBkgnd&lt;CMyWindow, RGB(<SPAN class=3Dcpp-literal>0</SPAN>,<SPAN =
class=3Dcpp-literal>0</SPAN>,<SPAN class=3Dcpp-literal>255</SPAN>)&gt; =
CPaintBkgndBase;</FONT>
=20
    BEGIN_MSG_MAP(CMyWindow)
        MESSAGE_HANDLER(WM_CLOSE, OnClose)
        MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
        COMMAND_HANDLER(IDC_ABOUT, OnAbout)
        <FONT color=3Dred>CHAIN_MSG_MAP(CPaintBkgndBase)</FONT>
    END_MSG_MAP()
...
};</PRE>
      <P>Any messages that get through the <CODE>CMyWindow</CODE> map =
unhandled=20
      are then passed on to the map in <CODE>CPaintBkgnd</CODE>. Note =
that=20
      <CODE>WM_CLOSE</CODE>, <CODE>WM_DESTROY</CODE>, and =
<CODE>IDC_ABOUT</CODE>=20
      will <B>not</B> be chained, because once those are handled, the =
message=20
      map search ends. The typedef is necessary because=20
      <CODE>CHAIN_MSG_MAP</CODE> is a preprocessor macro that takes one=20
      parameter; if we wrote <CODE>CPaintBkgnd&lt;CMyWindow, RGB(<SPAN=20
      class=3Dcpp-literal>0</SPAN>,<SPAN =
class=3Dcpp-literal>0</SPAN>,<SPAN=20
      class=3Dcpp-literal>255</SPAN>)&gt;</CODE> as the parameter, the =
commas=20
      would make the preprocessor think that we're calling it with more =
than one=20
      parameter.</P>
      <P>You could conceivably have several mix-in classes in the =

⌨️ 快捷键说明

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