在WTL中有时候需要SDI,MDI,或者TDI,如果这些视图中带有Edit控件,或者工具栏中嵌入Edit控件,会发现control+C, control+V,这此相似的快捷键会失效,有时候甚至一些按键都直接失灵。但这些控件如果放在对话框中则是正常的。
很久之前解决过种问题,但没有非常细致的研究是什么原因,这几天闲着蛋痛,总结了一下。
一开始的我是找到了CEditCommand(在 atlctrls.h里面)。
代码如下 :
接下来是如何使用这个类,从模板参数可以猜出应是常规用法(WTL没文档 L)
于是到主窗口里打个断点一看,消息果然只传给了主窗口,没有传下来,到主窗口的MessageMAP里添加 CHAIN_MSG_MAP_MEMBER(m_view)
事情到这里总算大功造成。问题虽解决了,但还存在一些Bug,比如,这时候有两个view,当其中一个view使用快捷键时,另外一个view也会生效,这显然不是我们想要的效果。于是把 CHAIN_MSG_MAP_MEMBER(m_view)改成
存在两个问题:
1. 为什么对话框里就不需要这些恶心的代码。
2. 为什么这个WM_COMMAND只到主窗口那里响应 为了确认WM_COMMAND是否一定会在父窗口触发,我专门在对话框的的Message MAP添加ID_EDIT_COPY这个COMMAND的映射。
结果是对话框完全没有响应到这个事件。为什么SDI会响应呢,代码跟踪了很久发现了在SDI中有这么一段关键的代码
CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg)的代码如下:
终于看见了曙光了,就是 TranslateAccelerator,快捷键!!!
Edit快捷键与CMainFrame的快捷键有冲突!
所以解决这个问题的最简单方法是:
1.把RC里的Accelerator中与Edit有冲突的快捷键删掉。
2.或者如果不需要快捷键,则把CMainFrame::PreTranslateMessage的CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg)删掉。
很久之前解决过种问题,但没有非常细致的研究是什么原因,这几天闲着蛋痛,总结了一下。
一开始的我是找到了CEditCommand(在 atlctrls.h里面)。
代码如下 :
template <class T>
class CEditCommands
{
public:
BEGIN_MSG_MAP(CEditCommands< T >)
ALT_MSG_MAP(1)
COMMAND_ID_HANDLER(ID_EDIT_CLEAR, OnEditClear)
COMMAND_ID_HANDLER(ID_EDIT_CLEAR_ALL, OnEditClearAll)
COMMAND_ID_HANDLER(ID_EDIT_COPY, OnEditCopy)
//…
END_MSG_MAP()
//…
LRESULT OnEditCopy(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
T* pT = static_cast<T*>(this);
pT->Copy();
return 0;
}
//…
可见平时看到的快捷键最终会转换成一个WM_COMMAND.
接下来是如何使用这个类,从模板参数可以猜出应是常规用法(WTL没文档 L)
class CMyEdit
: public CWindowImpl< CMyEdit,CEdit>
, CEditCommands < CMyEdit>
{
BEGIN_MSG_MAP(CMyEdit)
//…
CHAIN_MSG_MAP_ALT(CEditCommands< CMyEdit>, 1)
//…
END_MSG_MAP()
};
理论上这样消息传递就应OK了,但问题是,使用快捷键时没有收到Edit的WM_COMMAND消息。
于是到主窗口里打个断点一看,消息果然只传给了主窗口,没有传下来,到主窗口的MessageMAP里添加 CHAIN_MSG_MAP_MEMBER(m_view)
事情到这里总算大功造成。问题虽解决了,但还存在一些Bug,比如,这时候有两个view,当其中一个view使用快捷键时,另外一个view也会生效,这显然不是我们想要的效果。于是把 CHAIN_MSG_MAP_MEMBER(m_view)改成
if (::GetFocus() == m_view1.m_hWnd)
{
CHAIN_MSG_MAP_MEMBER(m_view1)
}
if (::GetFocus() == m_view2.m_hWnd)
{
CHAIN_MSG_MAP_MEMBER(m_view2)
}
这段代码有点恶心,但不管怎么样,问题能解决了。
一开始的时候,由于急功近利,代码就是这样草草写完,不知其所以。
存在两个问题:
1. 为什么对话框里就不需要这些恶心的代码。
2. 为什么这个WM_COMMAND只到主窗口那里响应 为了确认WM_COMMAND是否一定会在父窗口触发,我专门在对话框的的Message MAP添加ID_EDIT_COPY这个COMMAND的映射。
结果是对话框完全没有响应到这个事件。为什么SDI会响应呢,代码跟踪了很久发现了在SDI中有这么一段关键的代码
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{
if(CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg))
return TRUE;
return m_view.PreTranslateMessage(pMsg);
}
CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg)的代码如下:
BOOL PreTranslateMessage(MSG* pMsg)
{
if(m_hAccel != NULL && ::TranslateAccelerator(m_hWnd, m_hAccel,pMsg))
return TRUE;
return FALSE;
}
终于看见了曙光了,就是 TranslateAccelerator,快捷键!!!
Edit快捷键与CMainFrame的快捷键有冲突!
所以解决这个问题的最简单方法是:
1.把RC里的Accelerator中与Edit有冲突的快捷键删掉。
2.或者如果不需要快捷键,则把CMainFrame::PreTranslateMessage的CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg)删掉。