WTL的SDI中Edit控件无法使用快捷键原因

WTL中有时候需要SDI,MDI,或者TDI,如果这些视图中带有Edit控件,或者工具栏中嵌入Edit控件,会发现control+C, control+V,这此相似的快捷键会失效,有时候甚至一些按键都直接失灵。但这些控件如果放在对话框中则是正常的。
很久之前解决过种问题,但没有非常细致的研究是什么原因,这几天闲着蛋痛,总结了一下。
一开始的我是找到了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)删掉。

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用 WTL(Windows Template Library)进行 Windows 桌面应用开发是一个不错的选择。WTL 是一个轻量级的 C++ 模板库,基于 ATL(Active Template Library),它提供了一套简洁而高效的类和模板来开发 Windows 桌面应用程序。 以下是一个使用 WTL 创建一个简单窗口的示例: ```cpp #include <atlbase.h> #include <atlapp.h> #include <atlwin.h> class CMainWindow : public CFrameWnd { public: CMainWindow() { Create(NULL, _T("WTL Application")); } DECLARE_MESSAGE_MAP() }; BEGIN_MESSAGE_MAP(CMainWindow, CFrameWnd) ON_WM_PAINT() ON_WM_DESTROY() END_MESSAGE_MAP() void CMainWindow::OnPaint() { CPaintDC dc(m_hWnd); CRect rect; GetClientRect(&rect); dc.DrawText(_T("Hello, WTL!"), -1, &rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE); } void CMainWindow::OnDestroy() { PostQuitMessage(0); } int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpCmdLine*/, int nShowCmd) { CAppModule appModule; appModule.Init(NULL, hInstance); CMainWindow mainWindow; mainWindow.ShowWindow(nShowCmd); MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } appModule.Term(); return msg.wParam; } ``` 在这个示例,我们创建了一个名为 "CMainWindow" 的类,继承自 WTL 的 CFrameWnd 类。在类,我们通过重写 OnPaint 和 OnDestroy 方法来处理窗口的绘制和销毁事件。然后,在 _tWinMain 函数,我们初始化 WTL 应用程序模块,并创建一个 CMainWindow 对象,最后进入消息循环以响应窗口消息。 请注意,使用 WTL 进行开发需要先安装 WTL 库,并将其包含到项目。你可以从 WTL 官方网站(https://sourceforge.net/projects/wtl/)下载最新的 WTL 版本。 这只是 WTL 开发的简单示例,你可以根据需要进行进一步的开发和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值