~$ 存档

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

/*********************************************************************************************************************
*   发布日期:
*   更新日期:2017-11-16 09:22:05
*   进度:待完善
*   作者:骆天
*   备注:
*********************************************************************************************************************/

对话框的创建

一、MFC创建模态对话框

CMyDialog dlg;
dlg.DoModal();

考查模式对话框的创建过程。CDialog::DoModal用来创建模式对话框窗口并执行有关任务,和DoModal相关的是MFC内部使用的成员函数CDialog::PreModal和CDialog::PostModal。下面分别讨论它们的实现。

HWND CDialog::PreModal()
{
// cannot call DoModal on a dialog already constructed as modeless
ASSERT(m_hWnd == NULL);
// allow OLE servers to disable themselves
AfxGetApp()->EnableModeless(FALSE);
// 得到父窗口
CWnd* pWnd = CWnd::GetSafeOwner(m_pParentWnd, &m_hWndTop);
// 如同CWnd处理其他窗口的创建,设置一个窗口创建HOOK
AfxHookWindowCreate(this);
//返回父窗口的句柄
return pWnd->GetSafeHwnd();
}
void CDialog::PostModal()
{
//取消窗口创建前链接的HOOK
AfxUnhookWindowCreate(); // just in case
//MFC对话框对象和对应的Windows对话框窗口分离
Detach(); // just in case
// m_hWndTop是当前对话框的父窗口或所属窗口,则恢复它
if (::IsWindow(m_hWndTop))
    ::EnableWindow(m_hWndTop, TRUE);
m_hWndTop = NULL;
AfxGetApp()->EnableModeless(TRUE);
}
int CDialog::DoModal()
{
    // can be constructed with a resource template or InitModalIndirect
    ASSERT(m_lpszTemplateName != NULL ||
        m_hDialogTemplate != NULL || m_lpDialogTemplate != NULL);

    //加载对话框资源
    LPCDLGTEMPLATE lpDialogTemplate = m_lpDialogTemplate;
    HGLOBAL hDialogTemplate = m_hDialogTemplate;
    HINSTANCE hInst = AfxGetResourceHandle();
    //查找资源(见9.5.2节),找到了就加载它
    if (m_lpszTemplateName != NULL)
    {
        hInst = AfxFindResourceHandle(m_lpszTemplateName, RT_DIALOG);
        HRSRC hResource = ::FindResource(hInst, m_lpszTemplateName, RT_DIALOG);
        hDialogTemplate = LoadResource(hInst, hResource);
    }
    //锁定加载的资源
    if (hDialogTemplate != NULL)
        lpDialogTemplate = (LPCDLGTEMPLATE)LockResource(hDialogTemplate);
    // return -1 in case of failure to load the dialog template resource
    if (lpDialogTemplate == NULL)
        return -1;
    //创建对话框前禁止父窗口,为此要调用PreModal得到父窗口句柄
    HWND hWndParent = PreModal();
    AfxUnhookWindowCreate();
    CWnd* pParentWnd = CWnd::FromHandle(hWndParent);
    BOOL bEnableParent = FALSE;
    if (hWndParent != NULL && ::IsWindowEnabled(hWndParent))
    {
        ::EnableWindow(hWndParent, FALSE);
        bEnableParent = TRUE;
    }
    //创建对话框,注意是无模式对话框
    TRY
    {
        //链接一个HOOK到HOOK链以处理窗口创建,
        //如同4.4.1节描述的CWnd类窗口创建一样
        AfxHookWindowCreate(this);
        //CreateDlgIndirect间接调用::CreateDlgIndirect,
        //最终调用了::CreateWindowEX来创建对话框窗口。
        //HOOK过程_AfxCbtFilterHook用子类化的方法
        //取代原来的窗口过程为AfxWndProc。
        if (CreateDlgIndirect(lpDialogTemplate, CWnd::FromHandle(hWndParent), hInst))
        {
            if (m_nFlags & WF_CONTINUEMODAL)
            {
                // enter modal loop
                DWORD dwFlags = MLF_SHOWONIDLE;
                //RunModalLoop接管整个应用程序的消息处理
                if (GetStyle() & DS_NOIDLEMSG)
                    dwFlags |= MLF_NOIDLEMSG;
                VERIFY(RunModalLoop(dwFlags) == m_nModalResult);
            }
            // hide the window before enabling the parent, etc.
            if (m_hWnd != NULL)
                SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW |
                SWP_NOSIZE | SWP_NOMOVE |
                SWP_NOACTIVATE | SWP_NOZORDER);
        }

    }
    CATCH_ALL(e)
    {
        DELETE_EXCEPTION(e);
        m_nModalResult = -1;
    }
    END_CATCH_ALL
        //Enable并且激活父窗口
    if (bEnableParent)
        ::EnableWindow(hWndParent, TRUE);
    if (hWndParent != NULL && ::GetActiveWindow() == m_hWnd)
        ::SetActiveWindow(hWndParent);
    //::EndDialog仅仅关闭了窗口,现在销毁窗口
    DestroyWindow();
    PostModal();
    // 必要的话,解锁/释放资源
    if (m_lpszTemplateName != NULL || m_hDialogTemplate != NULL)
        UnlockResource(hDialogTemplate);
    if (m_lpszTemplateName != NULL)
        FreeResource(hDialogTemplate);
    return m_nModalResult;

}

从DoModal的实现可以看出:
它首先Disable对话框窗口的父窗口;然后使用::CreateIndrectDialog创建对话框窗口,使用子类化的方法用AfxWndProc(或者AfxBaseProc)替换了原来的窗口过程,并把原来的窗口过程保存在CWnd的成员变量m_pfnSuper中。原来的窗口过程就是::DialogBox等创建对话框窗口时指定的,是Windows内部提供的对话框“窗口类”的窗口过程。取代(Subclass)原来“窗口类”的窗口过程的方法如同 4.4.1节描述的CWnd::Create。

在::CreateIndirectDialog创建对话框窗口后,会发送WM_INITDIALOG消息给对话框的对话框过程(必要的话,还有WM_SETFONT消息)。但是MFC取代了原来的对话框窗口过程,这两个消息如何送给对话框过程呢?处理方法如下节所描述。

二、MFC创建非模态对话框

CMyDialog dlg;//此dlg应在类中作为成员变量;
dlg.Create(IDD_DIALOG1,this);
dlg.ShowWindow(SW_SHOW);//显示窗口

对话框的控制:

分为几种情况,第一种,直接调用对话框,前提是已经在资源管理器中创建了一个对话框,比如,在菜单中的某个选项中调出对话框,可以直接用CWnd::DialogBox()函数。一旦显示对话框并且操作完成之后,当需要关闭的时候,调用函数EndDialog()函数。调用之后,只关闭这个对话框,而不是是关闭整个窗口。

BOOL EndDialog(
HWND hDlg; //该对话框所属的窗口句柄,比如hwnd
int nResult //返回值
);

第二种情况,应用程序就只有一个对话框,只要关闭对话框就意味着整个程序关闭。可以在某个按钮上(比如取消按钮)添加一条消息,PostQuitMessage(0);

CDialog成员函数一览表

BOOL Create( LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL );
BOOL Create( UINT nIDTemplate, CWnd* pParentWnd = NULL );

Create用来根据模板创建无模式对话框

BOOL CreateIndirect( LPCDLGTEMPLATE lpDialogTemplate, CWnd* pParentWnd = NULL );
BOOL CreateIndirect( HGLOBAL hDialogTemplate, CWnd* pParentWnd = NULL );

CreateInDirect用来根据内存中的模板创建无模式对话框

BOOL InitModalIndirect( LPCDLGTEMPLATE lpDialogTemplate, CWnd* pParentWnd = NULL );
BOOL InitModalIndirect( HGLOBAL hDialogTemplate, CWnd* pParentWnd = NULL );

InitModalIndirect用来根据内存中的模板创建模式对话框。它们都提供了两个重载版本

/*构造函数*/

CDialog( LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL );
CDialog( UINT nIDTemplate, CWnd* pParentWnd = NULL );
CDialog( );

CDialog重载了三个构造函数。
其中,第三个是缺省构造函数;
第一个和第二个构造函数从指定的对话框模板资源创建,pParentWnd指定了父窗口或所属窗口
若空则设置父窗口为应用程序主窗口。
   
   
   
   
   
   
posted on 2016-04-07 21:37  LuoTian  阅读(536)  评论(0编辑  收藏  举报