visual-c – 如何在WTL中模拟模态对话框?

visual-c – 如何在WTL中模拟模态对话框?,第1张

概述模态对话框很好用,也很容易使用.问题是他们不允许我自己处理消息循环.所以我想我也许可以使用无模式对话框来模拟模态,并且仍然自己负责消息循环以便处理加速. 目标 我想要实现的是在对话框具有焦点时按Ctrl C(和Ctrl Ins)的能力,然后我希望能够通过将一些信息复制到剪贴板来对此作出反应.因此,如果有人知道在WTL中使用模态对话框的方法,那也会回答我的问题. 我现在正在做什么 现在我现在所做的 模态对话框很好用,也很容易使用.问题是他们不允许我自己处理消息循环.所以我想我也许可以使用无模式对话框来模拟模态,并且仍然自己负责消息循环以便处理加速.

目标

我想要实现的是在对话框具有焦点时按Ctrl C(和Ctrl Ins)的能力,然后我希望能够通过将一些信息复制到剪贴板来对此作出反应.因此,如果有人知道在WTL中使用模态对话框的方法,那也会回答我的问题.

我现在正在做什么

现在我现在所做的是从CDialogImpl< T>中导出我的对话框类.和cmessageFilter为了让我负责PreTranslateMessage.在那里,我只使用CAccelerator :: TranslateAccelerator和CWindow :: IsDialogMessage来处理加速和对话框消息.

在OnInitDialog中,我填充加速表并将消息过滤器添加到(“全局”)消息循环中.加速表与对话框本身具有相同的资源ID:

m_accel.Attach(AtlLoadAccelerators(IDD));cmessageLooP* pLoop = _Module.GetMessageLoop();pLoop->AddMessageFilter(this);

然后我通过名称PretendModal为DoModal创建了一个代理,它使用“全局”消息循环.

现在,我看到的效果(出现在任务栏上的对话框除外)是应用程序,一旦模态对话框关闭,就不能再关闭了.确切地说,主消息循环接收WM_QUIT(WTL :: cmessageLoop :: Run()中的ATLTRACE2给出了它,但是在这个特技之后它仍然挂起(主框架窗口关闭,WM_QUIT被发布,但是进程没有如果我在PretendModal中使用单独的cmessageLoop(而不是“全局”),整个事情的行为都是一样的.

甚至将另一个单独的cmessageLoop新实例移动到其自己的线程中(在所有消息循环都是线程本地之后)似乎无法解决此问题.这让我感到困惑的是,我在这里做错了什么.

注意:IDCANCEL和IDOK的处理程序从消息循环中删除对话框类(即消息过滤器).

在尝试使用无模式对话框模拟模态对话框时,我做错了什么?或者,当使用仅从CDialogImpl< T>派生的模态对话框时,如何捕获Ctrl C(和Ctrl Ins).

班级

class CAboutDlg :    public CDialogImpl<CAboutDlg>,public cmessageFilter{    CAccelerator m_accel;public:    enum { IDD = IDD_ABOUT };    BEGIN_MSG_MAP(CAboutDlg)        MESSAGE_HANDLER(WM_INITDIALOG,OnInitDialog)        COMMAND_ID_HANDLER(IDOK,OnCloseCmd)        COMMAND_ID_HANDLER(IDCANCEL,OnCloseCmd)    END_MSG_MAP()    virtual BOol PreTranslateMessage(MSG* pMsg)    {        if (!m_accel.IsNull() && m_accel.TranslateAccelerator(m_hWnd,pMsg))            return TRUE;        return CWindow::IsDialogMessage(pMsg);    }    LRESulT OnInitDialog(UINT,WParaM,LParaM,BOol&)    {        m_accel.Attach(AtlLoadAccelerators(IDD));        if (m_bModal)        {            cmessageLooP* pLoop = _Module.GetMessageLoop();            pLoop->AddMessageFilter(this);        }        return TRUE;    }    voID PretendModal(HWND hwndParent = ::GetActiveWindow())    {        cmessageLooP* pLoop = _Module.GetMessageLoop();        if (pLoop && ::IsWindow(hwndParent))        {            HWND dlg = Create(*this);            if (::IsWindow(dlg))            {                ShowWindow(SW_SHOW);                pLoop->Run();            }        }    }    LRESulT OnCloseCmd(WORD,WORD,HWND,BOol&)    {        if (m_bModal)            EndDialog(0);        else        {            cmessageLooP* pLoop = _Module.GetMessageLoop();            pLoop->RemoveMessageFilter(this);            ::DestroyWindow(*this);        }        return 0;    }};
解决方法 所以同时我设法实现了我想要的.这似乎很好地工作,我还没有发现任何负面的副作用.

为了做我想做的事,我介绍了一个EmulateModal()函数,它模仿DialogImpl的DoModal()函数.

该功能如下:

voID EmulateModal(_In_ HWND hWndParent = ::GetActiveWindow(),_In_ LParaM DWInitParam = NulL){    ATLASSERT(!m_bModal);    ::EnableWindow(hWndParent,FALSE);    Create(hWndParent,DWInitParam);    ShowWindow(SW_SHOW);    m_loop.AddMessageFilter(this);    m_loop.Run();    ::EnableWindow(hWndParent,TRUE);    ::SetForegrounDWindow(hWndParent);    DestroyWindow();}

m_loop成员是CDialogImpl派生类所拥有的cmessageLoop(它也继承自cmessageFilter,如问题所示).

唯一需要的其他特殊处理是将以下代码添加到命令ID处理程序中,该处理程序监视IDOK和IDCANCEL(在我的情况下都是关闭对话框),即在OnCloseCmd内部.

if(m_bModal){    EndDialog(wID);}else{    m_loop.RemoveMessageFilter(this);    PostMessage(WM_QUIT);}

在调用DestroyWindow()之前从消息循环中删除消息过滤器(即PreTranslateMessage)很重要.退出由CDialogImpl派生类所拥有的“内部”消息循环以及从上面的EmulateModal()调用其Run()也非常重要.

所以要点是:

>从我的问题中删除PretendModal()方法>使用“内部”消息循环而不是使用顶级消息循环

总结

以上是内存溢出为你收集整理的visual-c – 如何在WTL中模拟模态对话框?全部内容,希望文章能够帮你解决visual-c – 如何在WTL中模拟模态对话框?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/1228432.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-05
下一篇 2022-06-05

发表评论

登录后才能评论

评论列表(0条)

保存