CVI中针对鼠标点击事件分析



主要软件: LabWindows/CVI Development Systems>>LabWindows/CVI Full Development System
主要软件版本: 2012
主要软件修正版本: N/A
次要软件: N/A

问题:

1、CVI中的鼠标点击事件响应控制;

2、CVI在Debug模式下可能部分丢失事件;



解答:
          在CVI中,在点击鼠标时候会通过回调函数的方式来响应用户的动作。回调函数的运行机制类似Labview中的事件结构,在MFC中也有类似的消息循环与之相对应。这种机制的目的就是以一个固定的通知机制来实现更加灵活的程序交互控制,并最大限度的减小资源的消耗。
          在CVI中,如果添加一个按钮,可以自动给对应的按钮添加默认事件。默认事件的类型可以通过以下方式打开对话框勾选来设置,如图1。
图1 配置添加默认条件分支
          可以添加的事件种类很多,本文主要针对以下三个事件做测试,这三类事件也是我们在编写程序最经常用到的三个事件类型:
EVENT_COMMIT
EVENT_LEFT_CLICK
EVENT_LEFT_DOUBLE_CLICK
测试环境:
Windows 7 X64、CVI 2012
 
1、鼠标事件的响应机制
          在CVI中每次点击鼠标,会响应不止一个事件,每个事件仅响应一次。比如:EVENT_VAL_CHANGED、EVENT_COMMIT、EVENT_GOT_FOCUS等待。在以下测试代码中,每点击一次(无连续点击),会响应两次事件回调。
图2 程序事件响应分支代码
图3 程序截图
          以上代码对应“Message Button”的回调函数,程序和界面如图2、图3。在Message Button上左键点击时候,事件先响应“EVENT_LEFT_CLICK”;该鼠标弹起时候响应“EVENT_COMMIT”事件。
          当快速点击“Message Button”,以上程序,每次双击会启动两个事件(EVENT_LEFT_DOUBLE_CLICK与EVENT_COMMIT)触发。事件响应依然是EVENT_LEFT_DOUBLE_CLICK响应在前,EVENT_COMMIT在后。
2、编程控制响应机制
         如果不想在同一个消息EVENT中有多个事件被触发,不同的场景想对其中特定事件做响应,可以尝试以下两种方法来实现:
(1)通过GetRelativeMouseState来监测鼠标状态,手动将不需要事件过滤
          如果有这种需求,可以通过使用“GetRelativeMouseState”函数来判断鼠标相对于某个Button的位置以及它是否按下,来对事件进行手动过滤。
int GetRelativeMouseState (int panelHandle, int controlID, int *xCoordinate, int *yCoordinate, int *leftButtonDown, int *rightButtonDown, int *keyModifiers);
          该函数可以获取鼠标释放按下,通过判断鼠标状态,来对事件进行分类,从而实现过滤。这种处理方法比较符合我们直观的编程思维,在此不再累述。
(2)swallow事件
          除了上面通过监测鼠标状态自己判断过滤之外,在CVI中还提供一个swallow机制,在CVI的帮助信息中有以下说明:
User callbacks must always return 0 unless they intend to  the event to which they are responding. To swallow the event, the callback should return 1.
Only user input, such as mouse click and keypress events, and commit events can be swallowed. If swallowed, no more callbacks are called for that event. If a user input event is swallowed, the user’s mouse click or keypress is ignored. If a commit event is swallowed, it is not placed into theGetUserEvent queue.
·         链接:http://zone.ni.com/reference/en-XX/help/370051Y-01/cvi/uiref/cviswallowing_events/
图4 启用Swallow处理
          只要在对应的callback的返回值的末尾将默认的return 0修改为return 1,就在响应一次事件回调之后将后面原来跟着触发的事件swallow掉,如图4。需要注意的是只有用户输入事件和Commit事件能够被swallow机制处理,实际测试如下图5、图6。
图5 不启用swallow,正常响应
图6 启用swallow,EVENT_COMMIT事件不响应
3Debug模式下可能出现事件丢失情况,Release EXE一般能正常触发
          在Debug模式下,有时候事件响应可能不能正常工作,有可能会造成有些事件丢失,但是Build EXE之后一般是正常的。(如果客户遇到事件丢失的问题,建议他们build exe之后看是否还会出现)暂不清楚具体原因是什么,可以通过以下实验来复现和验证。
          在程序中,使用printf函数输出每次事件响应结果。理论上连续点击Message Button时候,每次点击都应该触发两次事件,也就应该每次点击都对应两个事件输出。在Debug模式下对程序进行测试,实际测试结果如下:
图7 快速连击时候事件触发
          由以上测试图7可以看出,在慢速点击时候,每次的点击都触发两个事件。先触发EVENT_LEFT_DOUBLE_CLICK,然后触发EVENT_COMMIT。但是当后面快速点击时候,程序只触发了EVENT_LEFT_DOUBLE_CLICK事件,EVENT_COMMIT事件没有正常触发。
          对程序进行编译,发布EXE程序。再对程序进行调试,重新运行程序,快速双击Message Button,对事件响应进行测试,测试结果如图8。
图8 Release之后测试事件响应
          从以上测试结果来看,每一个EVENT_LEFT_DOUBLE_CLICK事件都对应EVENT_COMMIT事件,没有事件丢失的情况。不过这种情况下,事件响应有可能造成一些延迟,应该是打印输出的耗时导致的。
          因此,如果出现一些事件响应不正常的情况,建议将程序Build为EXE之后再测试。


相关链接:
Swallowing Events介绍
http://zone.ni.com/reference/en-XX/help/370051Y-01/cvi/uiref/cviswallowing_events/
Why Do Callbacks Get Called More Than Once?
http://digital.ni.com/public.nsf/allkb/20C40C2887C79301862569E7005C50E4


附件:
CVI.zip




报告日期: 03/24/2015
最近更新: 03/27/2015
文档编号: 6VN67M7H