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

📄 dialog.html.primary

📁 Windows API Tutorials, Windows API编程最好的手册.文档格式专门制作成为各个章节相互关联的html格式,大家可以像查阅msdn一样方便使用.各个章节的内容如下: Wi
💻 PRIMARY
📖 第 1 页 / 共 2 页
字号:
<hr>
         <!--Yellow background-->
        <table cellpadding=10 cellspacing=0 width=100%>
                <tr>
                      <td width=20>&nbsp;</td>
            	      <td bgcolor="#e0e080"><font color="#000000">
<pre>class <font color="#cc0066"><b>CtrlFactory</b></font>
{
public:
    CtrlFactory (void *argList) : _argList (argList) {}

    void *GetArgList () { return _argList; }
    virtual DlgController * MakeController (HWND hwndDlg) = 0;

private:
    void *_argList;
};

template &lt;class ActualCtrl, class ActualArgList&gt;
class <font color="#cc0066"><b>ControllerFactory</b></font> : public <font color="#cc0066"><b>CtrlFactory</b></font>
{
public:
    ControllerFactory (void *argList) : CtrlFactory (argList) {}
    <b>DlgController</b> * MakeController (HWND hwndDlg)
    {
        return new <b>ActualCtrl</b> (hwndDlg, (ActualArgList *) GetArgList ());
    }
};</pre>
<!--End Code--></font>
                       </td>
					   <td width=20>&nbsp;</td>
		</tr>
        </table>
        <!--End of yellow background-->


<hr>
Here is the definition of the abstract class <b>DlgController</b> that is used as a base for all client-defined controller classes. We've already seen how this derivation works in the case of the client class <b>EditorCtrl</b>.
<hr>

         <!--Yellow background-->
        <table cellpadding=10 cellspacing=0 width=100%>
                <tr>
                      <td width=20>&nbsp;</td>
            	      <td bgcolor="#e0e080"><font color="#000000">
<pre>class <font color="#cc0066"><b>DlgController</b></font>
{
public:
    virtual ~DlgController () {} // In case derived class overrides
    virtual void OnInitDialog (HWND hwnd) = 0;
    virtual bool OnCommand (HWND hwnd, int ctrlID, int notifyCode) = 0;
    virtual bool OnNotify (HWND hwnd, int idCtrl, NMHDR *hdr) = 0;

    void *GetArgList () { return _argList; }

protected:
    DlgController (void *argList) : _argList (argList) {}

private:
    void *_argList;
};</pre>
<!--End Code--></font>
                       </td>
					   <td width=20>&nbsp;</td>
		</tr>
        </table>
        <!--End of yellow background-->



<hr>
The central reusable piece of software is the <b>ModalDialog</b> class. It does all the work in its constructor by calling the <b>DialogBoxParam</b> Windows API. The parameter that we are passing to the dialog box (actually, to its dialog procedure) is the pointer to the controller factory. The dialog procedure is defined as a static method (no <i>this</i> pointer--the dialog procedure is callable from Windows, so it has no access to the <i>this</i> pointer). <hr>


         <!--Yellow background-->
        <table cellpadding=10 cellspacing=0 width=100%>
                <tr>
                      <td width=20>&nbsp;</td>
            	      <td bgcolor="#e0e080"><font color="#000000">
<pre>class <font color="#cc0066"><b>ModalDialog</b></font>
{
public:
    ModalDialog (HINSTANCE hInst,
                 HWND hwnd,
                 int dlgResource,
                 CtrlFactory *ctrlFactory)
    {
        _result = <font color="#000099"><b>DialogBoxParam</b></font> (hInst,
                                  MAKEINTRESOURCE (dlgResource),
                                  hwnd,
                                  (DLGPROC) ModalDialogProc,
                                  (LPARAM) ctrlFactory);
    }

    static BOOL CALLBACK ModalDialogProc (HWND hwnd,
                                          UINT message,
                                          WPARAM wParam,
                                          LPARAM lParam);

    bool IsOk () const { return (_result == -1)? false: _result != 0; }

private:
    int                    _result;
};</pre>
<!--End Code--></font>
                       </td>
					   <td width=20>&nbsp;</td>
		</tr>
        </table>
        <!--End of yellow background-->


<hr>
Finally, the dialog procedure, common to all types of dialogs, is implemented to respond to three kinds of messages: WM_INITDIALOG, WM_COMMAND and WM_NOTIFY. Actually, all it does is to direct these messages to the controller object. It obtains the pointer to the polymorphic controller object for the first time by calling the <b>MakeController</b> method of the factory.
<p>Notice that, from that point on, we let Windows keep track of the pointer to the controller. We store it as GWL_USERDATA--a special long that is associated with every window, in particular with our dialog, and accessible through its window handle.
<hr>
         <!--Yellow background-->
        <table cellpadding=10 cellspacing=0 width=100%>
                <tr>
                      <td width=20>&nbsp;</td>
            	      <td bgcolor="#e0e080"><font color="#000000">
<pre>template &lt;class T&gt;
inline T <font color="#cc0066"><b>GetWinLong</b></font> (HWND hwnd, int which = <font color="#009966">GWL_USERDATA</font>)
{
    return reinterpret_cast&lt;T&gt; (::<font color="#000099"><b>GetWindowLong</b></font> (hwnd, which));
}

template &lt;class T&gt;
inline void <font color="#cc0066"><b>SetWinLong</b></font> (HWND hwnd, T value, int which = <font color="#009966">GWL_USERDATA</font>)
{
    ::<font color="#000099"><b>SetWindowLong</b></font> (hwnd, which, reinterpret_cast&lt;long&gt; (value));
}</pre>
<!--End Code--></font>
                       </td>
					   <td width=20>&nbsp;</td>
		</tr>
        </table>
        <!--End of yellow background-->


<hr>
We have to be careful, though. First of all, we need to deallocate the controller after we are done. We do it when processing WM_DESTROY.
<p>Second of all, Windows has this unfortunate habit of sending WM_COMMAND and WM_NOTIFY messages <i>before</i> WM_INITDIALOG and <i>after</i> WM_DESTROY. What can I say--if I were the manager of the poor schmuck who's responsible for this "feature" things would have been different. As it is, we have to protect ourselves by testing if <b>ctrl</b> is non-zero before calling <b>OnCommand</b> and <b>OnNotify</b>.
<hr>

         <!--Yellow background-->
        <table cellpadding=10 cellspacing=0 width=100%>
                <tr>
                      <td width=20>&nbsp;</td>
            	      <td bgcolor="#e0e080"><font color="#000000">
<pre>BOOL CALLBACK <font color="#cc0066"><b>ModalDialog::ModalDialogProc</b></font> (HWND hwnd,
                                              UINT message,
                                              WPARAM wParam,
                                              LPARAM lParam)
{
    DlgController * ctrl = GetWinLong&lt;DlgController *&gt; (hwnd);
    switch (message)
    {
    case WM_INITDIALOG:
        {
            CtrlFactory *ctrlFactory = reinterpret_cast&lt;CtrlFactory *&gt; (lParam);
            ctrl = ctrlFactory-&gt;MakeController (hwnd);
            SetWinLong&lt;DlgController *&gt; (hwnd, ctrl);
            ctrl-&gt;OnInitDialog (hwnd);
        }
        return TRUE;

    case WM_COMMAND:
        if (ctrl &amp;&amp; ctrl-&gt;OnCommand (hwnd, LOWORD(wParam), HIWORD (wParam)))
            return TRUE;
        break;

    case WM_NOTIFY:
        if (ctrl &amp;&amp; ctrl-&gt;OnNotify (hwnd, wParam, (NMHDR *)lParam))
            return TRUE;
        break;
    case WM_DESTROY:
        delete ctrl;
        SetWinLong&lt;DlgController *&gt; (hwnd, 0);
        break;
    }
    return FALSE;
}</pre>
<!--End Code--></font>
                       </td>
					   <td width=20>&nbsp;</td>
		</tr>
        </table>
        <!--End of yellow background-->


<hr>
<p>Here's the beauty of polymorphism in action. The <i>factory</i> object is created by the client using a template class. This object is passed to the constructor of <b>ModalDialog</b>. <b>ModalDialog</b> passes it to the dialog procedure as a void pointer (that's because it has to go through Windows). Dialog procedure gets it inside the WM_INITDIALOG message as LPARAM. After going through the digestive tract of Windows it has to be restored to its original shape by casting it back to the pointer to <b>CtrlFactory</b>--the base class of all controller factories.
<p>When we call its virtual method <b>MakeController</b>, we are calling the method overridden in the class template
<b>ControllerFactory</b>. It creates a new object of the client-defined class <b>ActualCtrl</b>. But again, it returns this object to us disguised as a generic pointer to <b>DlgController</b>. So whenever we call any of the virtual methods of <b>ctrl</b>, we are executing client overrides defined in the class <b>ActualCtrl</b>. That's your polymorphism at its best: you write code using generic pointers, but when the code is executed, it is called with very specific pointers. When you call methods through these pointers, you are executing specific methods provided by the client of your code.

<p>This is what happens to the object <i>factory</i> whose actual class is<br> <font color="#cc0066"><b>ControllerFactory&lt;EditorCtrl, EditorData&gt;</b></font>
<p>
<table frame=box border=4 rules=all cellpadding=4 cellspacing=3>
<tr>
   <td>Passed to ModalDialog constructor as
   <td>void *
<tr>
   <td>Passed by Windows to ModalDialogProcedure as
   <td>LPARAM
<tr>
   <td>Cast in ModalDialogProcedure to
   <td>CtrlFactory *
</table>
<p>And this is what happens to the object <i>data</i> whose actual class is <font color="#cc0066"><b>EditorData</b></font>.
<p>
<table cellpadding=4 cellspacing=3 border=4>
<tr>
    <td>Passed to factory constructor as</td>
    <td>void *</td>
</tr>
<tr>
    <td>Cast in the AcquireController method of ControllerFactory&lt;EditorCtrl, EditorData&gt;  to</td>
    <td>EditorData *</td>
</tr>
<tr>
    <td>Passed to the constructor of EditCtrl as</td>
    <td>EditotData *</td>
</tr>
</table>
<p>The object of class <font color="#cc0066"><b>EditCtrl</b></font> created in the <font color="#cc0066"><b>MakeController</b></font> method of <font color="#cc0066"><b>ControllerFactory&lt;EditorCtrl, EditorData&gt;</b></font> is returned from it as <font color="#cc0066"><b>DlgController *</b></font> and stored in this form as a static data member of <font color="#cc0066"><b>ModalDialog</b></font>.

<p><font size="-1">If you have problems following my explanation, don't despair. The object oriented techniques I just described are difficult, but essential. They are called desing patters. I highly recommend reading the book by Gamma, Helm, Johnson and Vlissides called <i>Design Patterns, Elements of Reusable Object-Oriented Software</i> or look at the <a href="http://st-www.cs.uiuc.edu/users/patterns/">Patterns Home Page</a>. It describes a lot of creative ways of using polymorphism, inheritance and templates to make software more reusable.</font>


<p>Now it's time to talk some more about the <a href="canvas.html">Canvas</a>.
<hr>
   </table>
   <td width=60>
</table>


</body>
</html>

⌨️ 快捷键说明

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