wxWidgets的控件,在双击时,也会同时触发单击事件,而且是触发两次LEFT_UP事件。
如果一个控件同时绑定单击和双击事件的时候,就会对我们的控制造成混乱。
一般解决这个问题有两个方法。
方法1:使用定时器,延时触发单击事件
wxWidgets中可以使用wxTimer来延时。当单击时先阻止事件被处理,并启动计时器。在超时之前如果有双击事件触发 ,则停止单击事件。否则继续处理单击事件。
这种方法会使得代码的程序控制变得麻烦,而且 wxTimer的使用也会增加不必要的耗费。
方法2:使用事件循环,过滤单击。
这也是本文着重讨论使用的方法。
具体步骤是:
1.LEFT_UP事件触发后,先处理后面的事件。
2.如果后面的这些事件中有双击事件,则将LEFT_UP事件屏蔽
3.如果后面的这些事件处理都没有双击事件,且时间超过200ms,才处理LEFT_UP事件
MFC也有类似的问题:MFC 处理双击事件时屏蔽掉单击事件-CSDN博客
不过wxWidgets没有PeekMessage,TranslateMessage,DispatchMessage等API,所以没法直接使用MFC的解决方案。
wxWidgets也是有事件循环的,那就是wxGUIEventLoop。
首先让wxWidgets的控件子类增加一个成员 wxGUIEventLoop m_loop;
再增加一个wxLongLong m_lastDbClick记录上次双击的点击时间
然后重写 ProcessEvent 方法。在其中判断事件:
bool MyFrame::ProcessEvent(wxEvent& event) {
int type = event.GetEventType();
wxLongLong begin_time = wxGetLocalTimeMillis();
if (wxEVT_LEFT_UP==type) {
const int span = 500;
wxLongLong duration = 0;
wxLongLong cur_time;
wxLongLong end_loop_time = begin_time + span;
do {
//先把后面的事件处理了
m_loop.DispatchTimeout(50);
cur_time = wxGetLocalTimeMillis();
duration = cur_time - m_lastDbClick;
if (duration < span) {
//如果期间触发了双击事件,则终止事件。
wxLogDebug("%s:duration:%s,stop left up event", cur_time.ToString(), duration.ToString());
return false;
}
} while (cur_time< end_loop_time);//在span时间内循环
}
else if (wxEVT_LEFT_DCLICK == type) {
wxLogDebug("%s:process double click event", begin_time.ToString());
//刷新上次双击事件的时间
m_lastDbClick = wxGetLocalTimeMillis();
}
return wxFrame::ProcessEvent(event);
}
只要这样,就可以解决wxWidget中单双击事件重叠的问题了。