来讨论下鼠标光标移出窗口的问题。
这问题属于老生常谈,也很实际,我相信有不少应用(尤其是对拆分窗口的界面)都需要得知何时光标移出窗口。但我们都知道光标一旦移出窗口,MouseMove消息就不再发送给对应的窗口了,换句话说,WM_MOUSEMOVE可以知道何时光标移入窗口,却不能知道何时光标移出窗口。
解决方法大概有3个,用timer不断检测,用TrackMouseEvent注册鼠标移出窗口的消息,以及使用SetCapture和ReleaseCapture,但这三种方法都有缺点:
Timer是我不太喜欢用的东西,其一在于频繁查询这种做法我不是很喜欢,总觉得对系统资源的消耗比较大(强迫症强迫症),而且这个有一定的滞后性,并不是实时的,不过其实Timer虽然是理论上最难看的一种,却是实际中最实用的,100毫秒左右的timer足够满足你的要求。这也是目前我在用的。
TrackMouseEvent最大的问题是这个函数的功能和说明都太简单了,他有个timerout的时间,那么到底timeout之后会如何呢?继续沉默?这显然非常不能令人满意,default的timeout非常短,只有400毫秒左右,你拿根笔这个函数就歇掉了,当然可以适当加长这个时间,但多长呢?1分钟?如果人家上个厕所呢……MSDN中也没有对此进行进一步的阐述,这个函数应当是工作在异步模式下的,看上去很美,但不太敢用。
SetCapture和ReleaseCapture这种用法,理论上还是比较完美的,因为WM_MOUSEMOVE这个消息你几乎不可能不响应——当你需要得知鼠标光标是否移出窗口的时候,十有八九是要在WM_MOUSEMOVE里面做些什么的。在移入的时候SetCapture,然后判断焦点是否移出Client区域,如果是则Release,但这种做法也是最麻烦的——MSDN说一旦SetCapture,所有的热键都不会响应(包括Accelerators和MenuKey),实际呢,连WM_KEYDOWN都不响应了,所有按键都被吃掉。这个只能用在类似需要拖拽的场合,实际中反而最不实用。
大家都来讨论下吧,看看有没有像timer那样无负担,像TrackMouseEvent那样工作在异步模式的,并且像SetCapture和ReleaseCapture那样可控性非常好的方法。
先放个20分在这里,如果回答有价值偶再加~