MFC中由左键单击模拟左键双击引起的问题

项目需要根据左键单击计时的手段来模拟左键双击的效果。


msdn对于WM_LBUTTONDBLCLK中有一句:

Only windows that have the CS_DBLCLKS style can receive WM_LBUTTONDBLCLK messages, which the system generates whenever the user presses, releases, and again presses the left mouse button within the system's double-click time limit. Double-clicking the left mouse button actually generates a sequence of four messages: WM_LBUTTONDOWN,WM_LBUTTONUP, WM_LBUTTONDBLCLK, and WM_LBUTTONUP.


也就是说,带有CS_DBLCLKS标志的窗口类可接收到WM_LBUTTONDBLCLK消息,且消息以下列序列发出:

WM_LBUTTONDOWN

WM_LBUTTONUP

WM_LBUTTONDBLCLK

WM_LBUTTONUP


开始时在WM_LBUTTONDOWN消息响应函数中计数处理,死活不行,需要三击鼠标左键才能判断为双击,原因就在于对于CS_DCLCLKS标志的窗口类创建的窗口实例,对于双击操作的第二下左键down,不发WM_LBUTTONDOWN消息,所以就漏过了,需要第三下左键按下才判断为双击并进行响应。问题找到了,解决方案有三:

1.在WM_LBUTTONUP中判断双击或是单击

2.在PreTranslateMessage中拦截WM_LBUTTONDBCLK,令其为WM_LBUTTONDOWN,仍然return 0 分发这个消息,只是修改一下pMsg->message


3.改变窗口类风格,用到SetClassLong函数

1)起先,在CWnd::OnCreate中直接改变窗口类风格:

	DWORD style = GetClassLong(m_hWnd, GCL_STYLE);
	style &= ~CS_DBLCLKS;
	SetClassLong(m_hWnd, GCL_STYLE, style);

发现ok了,但是除此之外的有些窗口也无法响应双击消息了。判断为该段代码通过某窗口类(这里记为wndclassA)的一个窗口实例改变了wndclassA的风格,导致同一进程中其它使用wndclassA创建的窗口实例都失去了响应双击消息的能力(不知道窗口过程是否会影响,反正style是影响了),我的项目中wndclassA是windows标准控件LISTBOX,更具体的在《Win32中安全的子类化
》http://www.cppblog.com/mydriverc/articles/28233.html。

“要全局子类化一个窗口类,应用程序必须拥有一个该类的窗口实例。想要获得该类的窗口实例,大多数应用程序采取建立一个属于将要被全局子类化的窗口类的窗口的方法,当应用程序要移除子类化,也必须有一个窗口句柄,该句柄应该是属于应用程序要子类化的窗口类的,因此,为此而专门创建并保存一个窗口是个不错的办法。如果应用程序需要创建它所要子类化的窗口类的窗口实例,这个窗口实例通常应该是不可见的。”

为了验证这个想法,按向导建了个最简单的单文档程序,在CView的OnCreate中写入代码:

	HWND btn1 = CreateWindowEx(0,_T("BUTTON"),_T("改变button类游标前"),WS_CHILD | WS_VISIBLE | BS_FLAT | WS_BORDER,220,10,40,20,m_hWnd,NULL,AfxGetApp()->m_hInstance,NULL);
	SetClassLong(btn1, GCL_HCURSOR,(LONG)LoadCursor(NULL, IDC_HELP) ); 
	HWND btn2 = CreateWindowEx(0,_T("BUTTON"),_T("改变button类游标后"),WS_CHILD | WS_VISIBLE | BS_FLAT | WS_BORDER,220,100,40,20,m_hWnd,NULL,AfxGetApp()->m_hInstance,NULL);

SetClassLong的操作同时影响了两个button,无论创建先后于SetClassLong,这就意味着SetClassLong的操作直接改变了进程中所有以button窗口类名创建的按钮。


2)然后,就只能把我的窗口类单独拉出来注册,由于SetWindowLong函数无法在运行期改变某窗口实例指向的窗口类,故就在PreCreateWindow中处理传入的参数

CREATESTRUCT& cs


写入代码:

BOOL CmySetLongView::PreCreateWindow(CREATESTRUCT& cs)
{	
	WNDCLASSEX myWndClass;
	myWndClass.cbSize = sizeof(WNDCLASSEX);
	GetClassInfoEx(AfxGetApp()->m_hInstance, _T("listbox"), &myWndClass);
	myWndClass.lpszClassName = _T("MYLISTBOXWITHOUTDBCLK");
	myWndClass.style &= ~CS_DBLCLKS;
	RegisterClassEx(&myWndClass);

	cs.lpszClass = _T("MYLISTBOXWITHOUTDBCLK");

	return CView::PreCreateWindow(cs);
}

这样,利用GetClassName函数查看窗口类名,已经是“MYLISTBOXWITHOUTDBCLK”。仅以该类名创建的窗口实例才会无法响应双击消息。

除此之外,还可以使用SetClassLong改变图标、游标等,用SetWindowLong搞掉最小化按钮等

SetWindowLong(m_hWnd,GWL_STYLE,(LONG)GetWindowLong(m_hWnd,GWL_STYLE) & ~WS_MINIMIZEBOX);

(也可以直接操作PreCreateWindow传入的cs:

cs.style &= ~WS_MINIMIZEBOX



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值