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

📄 wtl for mfc programmers, part ii.mht

📁 大家知道wtl是window UI库
💻 MHT
📖 第 1 页 / 共 5 页
字号:
client=20
      area.</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> CMyWindow : =
<SPAN class=3Dcpp-keyword>public</SPAN> =
CFrameWindowImpl&lt;CMyWindow&gt;
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    BEGIN_MSG_MAP_EX(CMyWindow)<FONT color=3Dred>
</FONT>        MSG_WM_CREATE(OnCreate)
        MSG_WM_DESTROY(OnDestroy)<FONT color=3Dred>
</FONT>        MSG_WM_TIMER(OnTimer)<FONT color=3Dred>
        MSG_WM_ERASEBKGND(OnEraseBkgnd)
</FONT>        CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMyWindow&gt;)
    END_MSG_MAP()
=20
<FONT color=3Dred>    LRESULT OnEraseBkgnd ( HDC hdc )
    {
    CDCHandle  dc(hdc);
    CRect      rc;
    SYSTEMTIME st;
    CString    sTime;
=20
        <SPAN class=3Dcpp-comment>// Get our window's client =
area.</SPAN>
        GetClientRect ( rc );
=20
        <SPAN class=3Dcpp-comment>// Build the string to show in the =
window.</SPAN>
        GetLocalTime ( &amp;st );
        sTime.Format ( _T(<SPAN class=3Dcpp-string>"The time is =
%d:%02d:%02d"</SPAN>),=20
                       st.wHour, st.wMinute, st.wSecond );
=20
        <SPAN class=3Dcpp-comment>// Set up the DC and draw the =
text.</SPAN>
        dc.SaveDC();
=20
        dc.SetBkColor ( RGB(<SPAN class=3Dcpp-literal>255</SPAN>,<SPAN =
class=3Dcpp-literal>153</SPAN>,<SPAN class=3Dcpp-literal>0</SPAN>);
        dc.SetTextColor ( RGB(<SPAN class=3Dcpp-literal>0</SPAN>,<SPAN =
class=3Dcpp-literal>0</SPAN>,<SPAN class=3Dcpp-literal>0</SPAN>) );
        dc.ExtTextOut ( <SPAN class=3Dcpp-literal>0</SPAN>, <SPAN =
class=3Dcpp-literal>0</SPAN>, ETO_OPAQUE, rc, sTime,=20
                        sTime.GetLength(), NULL );
=20
        <SPAN class=3Dcpp-comment>// Restore the DC.</SPAN>
        dc.RestoreDC(-<SPAN class=3Dcpp-literal>1</SPAN>);
        <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>1</SPAN>;    <SPAN class=3Dcpp-comment>// We erased =
the background (ExtTextOut did it)</SPAN>
    }
</FONT>};</PRE>
      <P>This handler demonstrates one of the GDI wrappers,=20
      <CODE>CDCHandle</CODE>, as well as <CODE>CRect</CODE> and=20
      <CODE>CString</CODE>. All I need to say about <CODE>CString</CODE> =
is,=20
      it's identical to MFC's <CODE>CString</CODE>. I'll cover the =
wrapper=20
      classes later on, but for now you can think of =
<CODE>CDCHandle</CODE> as a=20
      simple wrapper around an <CODE>HDC</CODE>, similar to MFC's=20
      <CODE>CDC</CODE>, although when the <CODE>CDCHandle</CODE> goes =
out of=20
      scope, it doesn't destroy the underlying device context.</P>
      <P>So after all that, here's what our window looks like:</P>
      <P><IMG height=3D208 alt=3D" [clock window - 4K] "=20
      src=3D"http://www.codeproject.com/wtl/WTL4MFC2/firstwin.png" =
width=3D283=20
      align=3Dbottom border=3D0></P>
      <P>The sample code also has <CODE>WM_COMMAND</CODE> handlers for =
the menu=20
      items; I won't cover those here, but you can check out the sample =
project=20
      and see the WTL macro <CODE>COMMAND_ID_HANDLER_EX</CODE> in =
action.</P>
      <H2><A name=3Dappwizard></A>What You Get with the WTL =
AppWizard</H2>
      <P>The WTL distribution comes with a very nice AppWizard, so let's =
see=20
      what features it puts in an SDI app.</P>
      <H3><A name=3Dthruwizard></A>Going through the wizard</H3>
      <P>Click <I>File|New</I> in VC and select <I>ATL/WTL AppWizard</I> =
from=20
      the list. We'll be rewriting the clock app, so enter =
<I>WTLClock</I> for=20
      the project name:</P>
      <P><IMG height=3D403 alt=3D" [AppWiz screen 1 - 14K] "=20
      src=3D"http://www.codeproject.com/wtl/WTL4MFC2/appwiz1.png" =
width=3D561=20
      align=3Dbottom border=3D0></P>
      <P>The next page is where you select an SDI, MDI, or dialog-based =
app,=20
      along with some other options. Select the options as shown here =
and click=20
      <I>Next</I>:</P>
      <P><IMG height=3D387 alt=3D" [AppWiz screen 2 - 22K] "=20
      src=3D"http://www.codeproject.com/wtl/WTL4MFC2/appwiz2.png" =
width=3D477=20
      align=3Dbottom border=3D0></P>
      <P>The last page is where we can choose to have a toolbar, rebar, =
and=20
      status bar. To keep this app simple, uncheck all those and click=20
      <I>Finish</I>.</P>
      <P><IMG height=3D387 alt=3D" [AppWiz screen 3 - 21K] "=20
      src=3D"http://www.codeproject.com/wtl/WTL4MFC2/appwiz3.png" =
width=3D477=20
      align=3Dbottom border=3D0></P>
      <H3><A name=3Dexaminecode></A>Examining the generated code</H3>
      <P>After finishing the wizard, you'll see three classes in the =
generated=20
      code: <CODE>CMainFrame</CODE>, <CODE>CAboutDlg</CODE>, and=20
      <CODE>CWTLClockView</CODE>. From the names, you can guess what the =
purpose=20
      of each class is. While there is a "view" class, it is strictly a =
"plain"=20
      window derived from <CODE>CWindowImpl</CODE>; there is no =
framework at all=20
      like MFC's doc/view architecture.</P>
      <P>There is also a <CODE>_tWinMain()</CODE>, which initializes =
COM, the=20
      common controls, and <CODE>_Module</CODE>, and then calls a global =

      <CODE>Run()</CODE> function. <CODE>Run()</CODE> handles creating =
the main=20
      window and starting the message pump. It also uses a new class,=20
      <CODE>CMessageLoop</CODE>. <CODE>Run()</CODE> calls=20
      <CODE>CMessageLoop::Run()</CODE> which actually contains the =
message pump.=20
      I'll cover <CODE>CMessageLoop</CODE> in more detail in the next=20
      section.</P>
      <P><CODE>CAboutDlg</CODE> is a simple =
<CODE>CDialogImpl</CODE>-derived=20
      class that is associated with a dialog with ID =
<CODE>IDD_ABOUTBOX</CODE>.=20
      I covered dialogs in Part I, so you should be able to understand =
the code=20
      in <CODE>CAboutDlg</CODE>.</P>
      <P><CODE>CWTLClockView</CODE> is our app's "view" class. This =
works like=20
      an MFC view, in that it is a captionless window that occupies the =
client=20
      area of the main frame. <CODE>CWTLClockView</CODE> has a=20
      <CODE>PreTranslateMessage()</CODE> function, which works just like =
the MFC=20
      function of the same name, and a <CODE>WM_PAINT</CODE> handler. =
Neither=20
      function does anything significant yet, but we'll fill in the=20
      <CODE>OnPaint()</CODE> method to show the time.</P>
      <P>Finally, we have <CODE>CMainFrame</CODE>, which has lots of =
interesting=20
      new stuff. Here is an abbreviated version of the class =
definition:</P><PRE><SPAN class=3Dcpp-keyword>class</SPAN> CMainFrame : =
<SPAN class=3Dcpp-keyword>public</SPAN> =
CFrameWindowImpl&lt;CMainFrame&gt;,
                   <SPAN class=3Dcpp-keyword>public</SPAN> =
CUpdateUI&lt;CMainFrame&gt;,
                   <SPAN class=3Dcpp-keyword>public</SPAN> =
CMessageFilter,
                   <SPAN class=3Dcpp-keyword>public</SPAN> CIdleHandler
{
<SPAN class=3Dcpp-keyword>public</SPAN>:
    DECLARE_FRAME_WND_CLASS(NULL, IDR_MAINFRAME)

    CWTLClockView m_view;

    <SPAN class=3Dcpp-keyword>virtual</SPAN> BOOL =
PreTranslateMessage(MSG* pMsg);
    <SPAN class=3Dcpp-keyword>virtual</SPAN> BOOL OnIdle();

    BEGIN_UPDATE_UI_MAP(CMainFrame)
    END_UPDATE_UI_MAP()

    BEGIN_MSG_MAP(CMainFrame)
        <SPAN class=3Dcpp-comment>// ...</SPAN>
        CHAIN_MSG_MAP(CUpdateUI&lt;CMainFrame&gt;)
        CHAIN_MSG_MAP(CFrameWindowImpl&lt;CMainFrame&gt;)
    END_MSG_MAP()
};</PRE>
      <P><CODE>CMessageFilter</CODE> is a mix-in class that provides=20
      <CODE>PreTranslateMessage()</CODE>, and <CODE>CIdleHandler</CODE> =
is=20
      another mix-in that provides <CODE>OnIdle()</CODE>.=20
      <CODE>CMessageLoop</CODE>, <CODE>CIdleHandler</CODE>, and=20
      <CODE>CUpdateUI</CODE> work together to provide UI updating that =
works=20
      like <CODE>ON_UPDATE_COMMAND_UI</CODE> in MFC.</P>
      <P><CODE>CMainFrame::OnCreate()</CODE> creates the view window and =
saves=20
      its window handle, so that the view will be resized when the frame =
window=20
      is resized. <CODE>OnCreate()</CODE> also adds the =
<CODE>CMainFrame</CODE>=20
      object to lists of message filters and idle handlers kept by the=20
      <CODE>CAppModule</CODE>; I will cover those later.</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(m_hWnd, rcDefault, NULL, |
                                 WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS =
|
                                   WS_CLIPCHILDREN, WS_EX_CLIENTEDGE);
=20
    <SPAN class=3Dcpp-comment>// register object for message filtering =
and idle updates</SPAN>
    CMessageLoop* pLoop =3D _Module.GetMessageLoop();
    pLoop-&gt;AddMessageFilter(<SPAN class=3Dcpp-keyword>this</SPAN>);
    pLoop-&gt;AddIdleHandler(<SPAN class=3Dcpp-keyword>this</SPAN>);
=20
    <SPAN class=3Dcpp-keyword>return</SPAN> <SPAN =
class=3Dcpp-literal>0</SPAN>;
}</PRE>
      <P><CODE>m_hWndClient</CODE> is a member of =
<CODE>CFrameWindowImpl</CODE>;=20
      this is the window that will be resized when the frame is =
resized.</P>
      <P>The generated <CODE>CMainFrame</CODE> also has handlers for=20
      <I>File|New</I>, <I>File|Exit</I>, and <I>Help|About</I>. We won't =
need=20
      most of the default menu items for our clock, but it won't do any =
harm to=20
      leave them in for now. You can build and run the wizard-generated =
code=20
      now, although the app won't be very useful yet. You might be =
interested in=20
      stepping through the <CODE>CMainFrame::CreateEx()</CODE> call in =
the=20
      global <CODE>Run()</CODE> to see exactly how the frame window and =
its=20
      resources are loaded and created.</P>
      <P>Our next stop on the WTL tour is <CODE>CMessageLoop</CODE>, =
which=20
      handles the message pump and idle processing.</P>
      <H2><A name=3Dmsgloopinternals></A>CMessageLoop Internals</H2>
      <P><CODE>CMessageLoop</CODE> provides a message pump for our app. =
Aside=20
      from a standard =
<CODE>DispatchMessage</CODE>/<CODE>TranslateMessage</CODE>=20
      loop, it also provides message filtering via=20
      <CODE>PreTranslateMessage()</CODE> and idle processing via=20
      <CODE>OnIdle()</CODE>. Here is pseudo code for the logic in=20
      <CODE>Run()</CODE>:</P><PRE><SPAN class=3Dcpp-keyword>int</SPAN> =
Run()
{
MSG msg;
=20
    <SPAN class=3Dcpp-keyword>for</SPAN>(;;)
        {
        <SPAN class=3Dcpp-keyword>while</SPAN> ( !PeekMessage(&amp;msg) =
)
            DoIdleProcessing();
=20
        <SPAN class=3Dcpp-keyword>if</SPAN> ( <SPAN =
class=3Dcpp-literal>0</SPAN> =3D=3D GetMessage(&amp;msg) )
            <SPAN class=3Dcpp-keyword>break</SPAN>;    <SPAN =
class=3Dcpp-comment>// WM_QUIT retrieved from the queue</SPAN>
=20
        <SPAN class=3Dcpp-keyword>if</SPAN> ( =
!PreTranslateMessage(&amp;msg) )
            {
            TranslateMessage(&amp;msg);
            DispatchMessage(&amp;msg);
            }
        }
=20
    <SPAN class=3Dcpp-keyword>return</SPAN> msg.wParam;
}</PRE>
      <P><CODE>CMessageLoop</CODE> knows which=20
      <CODE>PreTranslateMessage()</CODE> functions to call because =
classes that=20
      need to filter messages call=20
      <CODE>CMessageLoop::AddMessageFilter()</CODE>, just like=20
      <CODE>CMainFrame::OnCreate()</CODE> does. And similarly, classes =
that need=20
      to do idle processing call=20
<CODE>CMessageLoop::AddIdleHandler()</CODE>.</P>
      <P>Notice that there are no calls to =
<CODE>TranslateAccelerator()</CODE>=20
      or <CODE>IsDialogMessage()</CODE> in the message loop.=20
      <CODE>CFrameWindowImpl</CODE> handles the former, but if you add =
any=20
      modeless dialogs to your app, you'll need to add a call to=20
      <CODE>IsDialogMessage()</CODE> in=20
      <CODE>CMainFrame::PreTranslateMessage()</CODE>.</P>
      <H2><A name=3Dframeinternals></A>CFrameWindowImpl Internals</H2>
      <P><CODE>CFrameWindowImpl</CODE> and its base class=20
      <CODE>CFrameWindowImplBase</CODE> provide a lot of the features =
you're=20
      used to having in MFC's <CODE>CFrameWnd</CODE>: toolbars, rebars, =
status=20
      bars, tooltips for toolbar buttons, and flyby help for menu items. =
I'll be=20
      covering all those features gradually, since discussing the entire =

      <CODE>CFrameWindowImpl</CODE> class could take up two whole =
articles! For=20
      now, it will be sufficient to see how =
<CODE>CFrameWindowImpl</CODE>=20
      handles <CODE>WM_SIZE</CODE> and its client area. For this =
discussion,=20
      remember that <CODE>m_hWndClient</CODE> is a member of=20
      <CODE>CFrameWindowImplBase</CODE> that holds the <CODE>HWND</CODE> =
of the=20
      "view" window inside the frame.</P>
      <P><CODE>CFrameWindowImpl</CODE> has a handler for=20
      <CODE>WM_SIZE</CODE>:</P><PRE>LRESULT OnSize(UINT <SPAN =
class=3Dcpp-comment>/*uMsg*/</SPAN>, WPARAM wParam, LPARAM <SPAN =
class=3Dcpp-comment>/*lParam*/</SPAN>, BOOL&amp; bHandled)
{
    <SPAN class=3Dcpp-keyword>if</SPAN>(wParam !=3D SIZE_MINIMIZED)
    {

⌨️ 快捷键说明

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