模态对话框很好用且易于使用。问题是他们不允许我自己处理消息循环。所以我想我也许可以使用一个无模式对话框来模拟一个模态对话框,并且仍然自己负责消息循环以便处理加速器。
我想要达到的目的是能够按 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);
然后我使用名为DoModal
的{{1}}创建了一个使用“全局”消息循环的代理。
现在我看到的效果(出现在任务栏上的对话框除外)是应用程序,一旦模态对话框关闭,就不能再关闭了。确切地说,主消息循环接收PretendModal
(WTL :: CMessageLoop :: Run()中的WM_QUIT
给出了它,但它仍然在这个特技之后挂起(主框架窗口关闭,WM_QUIT如果我在ATLTRACE2
内使用单独的CMessageLoop
(而不是“全局”),则整个过程表现相同。
甚至将另一个单独的PretendModal
新实例移动到其自己的线程中(在所有消息循环都是线程本地之后)似乎无法解决此问题。这让我感到困惑的是我在这里做错了什么。
注意:CMessageLoop
和IDCANCEL
的处理程序从消息循环中删除对话框类(即消息过滤器)。
在尝试使用无模式对话框模拟模式对话框时,我做错了什么?或者,如何在使用仅派生的模态对话框时捕获 Ctrl + C (和 Ctrl + Ins )来自IDOK
。
CDialogImpl<T>
答案 0 :(得分:1)
所以同时我设法实现了我想要的。这似乎工作得很好,我还没有发现任何负面影响。
为了做我想做的事,我引入了一个EmulateModal()
函数,它模仿DoModal()
的{{1}}函数。
该功能如下:
DialogImpl
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();
}
成员是[{1}}派生类所拥有的m_loop
(也会继承CMessageLoop
,如问题所示)。
唯一需要的其他特殊处理是将以下代码添加到命令ID处理程序中,该处理程序监视CDialogImpl
和CMessageFilter
(在我的情况下,这两者都是关闭对话框) ,即在IDOK
内。
IDCANCEL
将消息过滤器(即OnCloseCmd
)从消息循环之前移至调用if(m_bModal)
{
EndDialog(wID);
}
else
{
m_loop.RemoveMessageFilter(this);
PostMessage(WM_QUIT);
}
非常重要。退出“内部”消息循环也是非常重要,该消息循环由PreTranslateMessage
派生类所拥有,其DestroyWindow()
从CDialogImpl
调用
所以要点是:
Run()
方法