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

📄 wtl for mfc programmers, part ii.mht

📁 大家知道wtl是window UI库
💻 MHT
📖 第 1 页 / 共 5 页
字号:
        T* pT =3D <SPAN =
class=3Dcpp-keyword>static_cast</SPAN>&lt;T*&gt;(<SPAN =
class=3Dcpp-keyword>this</SPAN>);
        pT-&gt;UpdateLayout();
    }
=20
    bHandled =3D FALSE;
    <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>1</SPAN>;
}</PRE>
      <P>This checks that the window is not being minimized. If not, it=20
      delegates to <CODE>UpdateLayout()</CODE>. Here is=20
      <CODE>UpdateLayout()</CODE>:</P><PRE><SPAN =
class=3Dcpp-keyword>void</SPAN> UpdateLayout(BOOL bResizeBars =3D TRUE)
{
RECT rect;
=20
    GetClientRect(&amp;rect);
=20
    <SPAN class=3Dcpp-comment>// position bars and offset their =
dimensions</SPAN>
    UpdateBarsPosition(rect, bResizeBars);
=20
    <SPAN class=3Dcpp-comment>// resize client window</SPAN>
    <SPAN class=3Dcpp-keyword>if</SPAN>(m_hWndClient !=3D NULL)
        ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top,
            rect.right - rect.left, rect.bottom - rect.top,
            SWP_NOZORDER | SWP_NOACTIVATE);
}</PRE>
      <P>Notice how the code is referencing <CODE>m_hWndClient</CODE>. =
Since=20
      <CODE>m_hWndClient</CODE> is a plain <CODE>HWND</CODE>, it can be =
any=20
      window at all. There is no restriction on what kind of window it =
can be,=20
      unlike MFC where some features (like splitter windows) require a=20
      <CODE>CView</CODE>-derived class. If you go back to=20
      <CODE>CMainFrame::OnCreate()</CODE>, you'll see that it creates a =
view=20
      window and stores its handle in <CODE>m_hWndClient</CODE>, which =
ensures=20
      that the view will be resized properly.</P>
      <H2><A name=3Dbacktotheclock></A>Back to the Clock Program</H2>
      <P>Now that we've seen some of the frame window class details, =
let's get=20
      back to our clock app. The view window can handle the timer and =
drawing,=20
      just as <CODE>CMyWindow</CODE> did in the previous sample. Here's =
a=20
      partial class definition:</P><PRE><SPAN =
class=3Dcpp-keyword>class</SPAN> CWTLClockView : <SPAN =
class=3Dcpp-keyword>public</SPAN> CWindowImpl&lt;CWTLClockView&gt;
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    DECLARE_WND_CLASS(NULL)
=20
    BOOL PreTranslateMessage(MSG* pMsg);
=20
    BEGIN_MSG_MAP_EX(CWTLClockView)
        MESSAGE_HANDLER(WM_PAINT, OnPaint)
        MSG_WM_CREATE(OnCreate)
        MSG_WM_DESTROY(OnDestroy)
        MSG_WM_TIMER(OnTimer)
        MSG_WM_ERASEBKGND(OnEraseBkgnd)
    END_MSG_MAP()
};</PRE>
      <P>Note that it's fine to mix the ATL message map macros with the =
WTL=20
      versions, as long as you change <CODE>BEGIN_MSG_MAP</CODE> to=20
      <CODE>BEGIN_MSG_MAP_EX</CODE>. <CODE>OnPaint()</CODE> has all the =
drawing=20
      code that was in <CODE>OnEraseBkgnd()</CODE> in the previous =
sample.=20
      Here's what the new window looks like:</P>
      <P><IMG height=3D215 alt=3D" [Clock app w/view window - 3K] "=20
      src=3D"http://www.codeproject.com/wtl/WTL4MFC2/clockapp.png" =
width=3D277=20
      align=3Dbottom border=3D0></P>
      <P>The last thing we'll add to this app is UI updating. To =
demonstrate=20
      this, we'll add a new top-level menu item with <I>Start</I> and=20
      <I>Stop</I> commands to stop and start the clock. The <I>Start</I> =
and=20
      <I>Stop</I> menu items will be enabled and disabled as =
appropriate.</P>
      <H2><A name=3Duiupdating></A>UI Updating</H2>
      <P>Several things work together to provide idle-time UI updating: =
a=20
      <CODE>CMessageLoop</CODE> object, the mix-in classes=20
      <CODE>CIdleHandler</CODE> and <CODE>CUpdateUI</CODE> that=20
      <CODE>CMainFrame</CODE> inherits from, and the =
<CODE>UPDATE_UI_MAP</CODE>=20
      in <CODE>CMainFrame</CODE>. <CODE>CUpdateUI</CODE> can operate on =
five=20
      different types of elements: top-level menu items (in the menu bar =

      itself), menu items in popup menus, toolbar buttons, status bar =
panes, and=20
      child windows (such as dialog controls). Each type of element has =
a=20
      corresponding constant in <CODE>CUpdateUIBase</CODE>:</P>
      <UL>
        <LI>menu bar items: <CODE>UPDUI_MENUBAR</CODE>=20
        <LI>popup menu items: <CODE>UPDUI_MENUPOPUP</CODE>=20
        <LI>toolbar buttons: <CODE>UPDUI_TOOLBAR</CODE>=20
        <LI>status bar panes: <CODE>UPDUI_STATUSBAR</CODE>=20
        <LI>child windows: <CODE>UPDUI_CHILDWINDOW</CODE> </LI></UL>
      <P><CODE>CUpdateUI</CODE> can set the enabled state, checked =
state, and=20
      text of items (but of course not all items support all states; you =
can't=20
      check a child window that's an edit box). It can also set a popup =
menu=20
      item to the default state so the text appears in bold.</P>
      <P>To hook up UI updating, we need to do four things:</P>
      <OL>
        <LI>Derive the frame window class from <CODE>CUpdateUI</CODE> =
and=20
        <CODE>CIdleHandler</CODE>=20
        <LI>Chain messages from <CODE>CMainFrame</CODE> to=20
        <CODE>CUpdateUI</CODE>=20
        <LI>Add the frame window to the module's list of idle handlers=20
        <LI>Fill in the frame window's <CODE>UPDATE_UI_MAP</CODE> =
</LI></OL>
      <P>The AppWizard-generated code takes care of the first three =
parts for=20
      us, so all that's left is to decide which menu items we'll update, =
and=20
      when they will be enabled or disabled.</P>
      <H3><A name=3Dnewmenuitems></A>New menu items to control the =
clock</H3>
      <P>Let's add a new <I>Clock</I> menu to the menu bar, with two =
items:=20
      <CODE>IDC_START</CODE> and <CODE>IDC_STOP</CODE>:</P>
      <P><IMG height=3D103 alt=3D" [Clock menu - 2K] "=20
      src=3D"http://www.codeproject.com/wtl/WTL4MFC2/clockmenu.png" =
width=3D169=20
      align=3Dbottom border=3D0></P>
      <P>Then we add an entry in the <CODE>UPDATE_UI_MAP</CODE> for each =
menu=20
      item:</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> CMainFrame : =
<SPAN class=3Dcpp-keyword>public</SPAN> ...
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    <SPAN class=3Dcpp-comment>// ...</SPAN>
    BEGIN_UPDATE_UI_MAP(CMainFrame)
        <FONT color=3Dred>UPDATE_ELEMENT(IDC_START, UPDUI_MENUPOPUP)
        UPDATE_ELEMENT(IDC_STOP, UPDUI_MENUPOPUP)</FONT>
    END_UPDATE_UI_MAP()
    <SPAN class=3Dcpp-comment>// ...</SPAN>
};</PRE>
      <P>Then whenever we want to change the enabled state of either =
item, we=20
      call <CODE>CUpdateUI::UIEnable()</CODE>. <CODE>UIEnable()</CODE> =
takes the=20
      ID of the item, and a <CODE><SPAN =
class=3Dcpp-keyword>bool</SPAN></CODE>=20
      that indicates the enabled state (<CODE><SPAN=20
      class=3Dcpp-keyword>true</SPAN></CODE> for enabled, <CODE><SPAN=20
      class=3Dcpp-keyword>false</SPAN></CODE> for disabled).</P>
      <P>This system works backwards from MFC's=20
      <CODE>ON_UPDATE_COMMAND_UI</CODE> system. In MFC, we write =
handlers that=20
      MFC calls when it is about to show a menu and needs to know the =
state of=20
      the items in the menu. In WTL, we tell WTL when the logical state =
of an=20
      item changes. However, in both libraries, the library waits until =
just=20
      before the menu is shown to apply the state changes to the =
menu.</P>
      <H3><A name=3Dcallinguienable></A>Calling UIEnable()</H3>
      <P>Let's go back to the <CODE>OnCreate()</CODE> function and see =
how we=20
      set up the initial state of the <I>Clock</I> menu =
items.</P><PRE>LRESULT CMainFrame::OnCreate(UINT <SPAN =
class=3Dcpp-comment>/*uMsg*/</SPAN>, WPARAM <SPAN =
class=3Dcpp-comment>/*wParam*/</SPAN>,=20
                             LPARAM <SPAN =
class=3Dcpp-comment>/*lParam*/</SPAN>, BOOL&amp; <SPAN =
class=3Dcpp-comment>/*bHandled*/</SPAN>)
{
    m_hWndClient =3D m_view.Create(...);
 =20
    <SPAN class=3Dcpp-comment>// register object for message filtering =
and idle updates</SPAN>
    <SPAN class=3Dcpp-comment>// [omitted for clarity]</SPAN>
=20
    <FONT color=3Dred><SPAN class=3Dcpp-comment>// Set the initial state =
of the Clock menu items:</SPAN>
    UIEnable ( IDC_START, <SPAN class=3Dcpp-keyword>false</SPAN> );
    UIEnable ( IDC_STOP, <SPAN class=3Dcpp-keyword>true</SPAN> );</FONT>
=20
    <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}</PRE>
      <P>And here's what the Clock menu looks like when the app is =
started:</P>
      <P><IMG height=3D216 alt=3D" [Start item disabled - 4K] "=20
      src=3D"http://www.codeproject.com/wtl/WTL4MFC2/startdisabled.png" =
width=3D294=20
      align=3Dbottom border=3D0></P>
      <P><CODE>CMainFrame</CODE> now needs handlers for our two new =
items. The=20
      handlers will flip the states of the menu items, then call methods =
in the=20
      view class to start and stop the clock. This is one area where =
MFC's=20
      built-in message routing is sorely missed; if this were an MFC =
app, all=20
      the UI updating and command handling could be put entirely in the =
view=20
      class. However, in WTL, the frame and view classes have to =
communicate in=20
      some way; the menu is owned by the frame window, so the frame gets =

      menu-related messages and is responsible for either acting on them =
or=20
      sending them to the view class.</P>
      <P>The communication <I>could</I> be done through=20
      <CODE>PreTranslateMessage()</CODE>, however the =
<CODE>UIEnable()</CODE>=20
      calls still have to be done from <CODE>CMainFrame</CODE>.=20
      <CODE>CMainFrame</CODE> could get around this by passing its =
<CODE><SPAN=20
      class=3Dcpp-keyword>this</SPAN></CODE> pointer to the view class, =
so the=20
      view could call <CODE>UIEnable()</CODE> through that pointer. For =
this=20
      sample, I have chosen the solution that results in a =
tightly-coupled frame=20
      and view, since I find it easier to understand (and =
explain!).</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> CMainFrame : =
<SPAN class=3Dcpp-keyword>public</SPAN> ...
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    BEGIN_MSG_MAP_EX(CMainFrame)
        <SPAN class=3Dcpp-comment>// ...</SPAN>
        COMMAND_ID_HANDLER_EX(IDC_START, OnStart)
        COMMAND_ID_HANDLER_EX(IDC_STOP, OnStop)
    END_MSG_MAP()
=20
    <SPAN class=3Dcpp-comment>// ...</SPAN>
    <SPAN class=3Dcpp-keyword>void</SPAN> OnStart(UINT uCode, <SPAN =
class=3Dcpp-keyword>int</SPAN> nID, HWND hwndCtrl);
    <SPAN class=3Dcpp-keyword>void</SPAN> OnStop(UINT uCode, <SPAN =
class=3Dcpp-keyword>int</SPAN> nID, HWND hwndCtrl);
};
=20
<SPAN class=3Dcpp-keyword>void</SPAN> CMainFrame::OnStart(UINT uCode, =
<SPAN class=3Dcpp-keyword>int</SPAN> nID, HWND hwndCtrl)
{
    <SPAN class=3Dcpp-comment>// Enable Stop and disable Start</SPAN>
    UIEnable ( IDC_START, <SPAN class=3Dcpp-keyword>false</SPAN> );
    UIEnable ( IDC_STOP, <SPAN class=3Dcpp-keyword>true</SPAN> );
=20
    <SPAN class=3Dcpp-comment>// Tell the view to start its =
clock.</SPAN>
    m_view.StartClock();
}
=20
<SPAN class=3Dcpp-keyword>void</SPAN> CMainFrame::OnStop(UINT uCode, =
<SPAN class=3Dcpp-keyword>int</SPAN> nID, HWND hwndCtrl)
{
    <SPAN class=3Dcpp-comment>// Enable Start and disable Stop</SPAN>
    UIEnable ( IDC_START, <SPAN class=3Dcpp-keyword>true</SPAN> );
    UIEnable ( IDC_STOP, <SPAN class=3Dcpp-keyword>false</SPAN> );
=20
    <SPAN class=3Dcpp-comment>// Tell the view to stop its clock.</SPAN>
    m_view.StopClock();
}</PRE>
      <P>Each handler updates the <I>Clock</I> menu, then calls a method =
in the=20
      view, since the view is the class that controls the clock. The=20
      <CODE>StartClock()</CODE> and <CODE>StopClock()</CODE> methods are =
not=20
      shown here, but you can find them in the sample project.</P>
      <H2><A name=3Dfixclassview></A>One Last Note on Message Maps</H2>
      <P>If you are using VC 6, you might have noticed that when you =
change=20
      <CODE>BEGIN_MSG_MAP</CODE> to <CODE>BEGIN_MSG_MAP_EX</CODE>, =
ClassView=20
      goes haywire:</P>
      <P><IMG height=3D248 alt=3D" [Messed-up ClassView - 6K] "=20
      src=3D"http://www.codeproject.com/wtl/WTL4MFC2/classview.png" =
width=3D350=20
      align=3Dbottom border=3D0></P>
      <P>This happens because ClassView doesn't understand=20
      <CODE>BEGIN_MSG_MAP_EX</CODE>, and it thinks that all the WTL =
message map=20
      macros are actually functions. You can fix this by changing the =
macros=20
      back to <CODE>BEGIN_MSG_MAP</CODE> and adding these lines at the=20
      <B>end</B> of stdafx.h:</P><PRE><SPAN =
class=3Dcpp-preprocessor>#undef BEGIN_MSG_MAP</SPAN>
<SPAN class=3Dcpp-preprocessor>#define BEGIN_MSG_MAP(x) =
BEGIN_MSG_MAP_EX(x)</SPAN></PRE>
      <H2><A name=3Dnextup></A>Next Stop, 1995</H2>
      <P>We've only just begun to scratch the surface of WTL. In the =
next=20
      article, I'll bring our sample clock app up to 1995 UI standards =
and=20
      introduce toolbars and status bars. In the meantime, experiment a =
bit with=20
      the <CODE>CUpdateUI</CODE> methods; for example, try calling=20
      <CODE>UISetCheck()</CODE> instead of <CODE>UIEnable()</CODE> to =
see the=20
      different ways the menu items can be changed.</P>
      <H2><A name=3Drevisionhistory></A>Revision 

⌨️ 快捷键说明

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