背景:
之前我上传过一个关于TableViewer的使用说明(也提供的了源码下载)
当通过ComboBoxCellEditor设置姓名时,需要通过三次单击:
第一次:选中Cell
第二次:展开Combo
第三次:选中想要输入的名称
问题描述:
当如果你快速执行前两次单击 即:双击时,Combo便不能展开了。哪怕你频繁双击也是在选中Cell和选中文字两种状态下切换。
S1:选中Cell
S2:选中文字
循环
而走出这个循环的方法是:在S1时,等一会在 单击 此时Combo展开
原因:
寻找原因,和改进方法颇为艰辛,Eclipse Community Forums也逛了 但还是一无所获。 然后是指忍着恶心 跟鼠标事件的相应,此过程甚是陶冶性情。光第一次单击就触发了5个事件 触发了两次相同的MouseDown 走了相同的逻辑不知为何 当然这都不是重点。
当然 如果事件被断点拦截 Cell的状态相应也就会被打断,我也不知道为何,所以这个比跟踪一般的逻辑还要恶心一点。 善用判断条件的断点是很有帮助的。
秘密的揭开:TypeListener分配事件时,设置断点,查看它的第6次命中,此时就是第二次单击的开始,经过跟踪和对于第一次单击事件的了解发现了端倪。
ColumnViewerEditor的233行 会根据点击速度(自变量) 进行分支 分支的判断来自于shouldFireDoubleClick() 该方法内部比较了两个时间和一个类型 那个类型不可控忽略,哪两个时间跟踪下,就是两次的点击的时间间隔和500ms的大小比较。参考下面代码:
int timeout = cellEditor.getDoubleClickTimeout(); final int activationTime; if (timeout != 0) { activationTime = activationEvent.time + timeout; } else { activationTime = 0; }cellEditor的默认执行结果是:500ms
所以 activationTime的默认值为:第一次的点击时间(mouseDown)+500ms e.time是第二次点击的时间
函数shouldFireDoubleClick()的返回值 决定之后的逻辑。分支判断逻辑:
if (shouldFireDoubleClick(activationTime, e.time, activationEvent) && e.button == 1) { control.removeMouseListener(mouseListener); cancelEditing(); handleDoubleClickEvent(); } else if (mouseListener != null) { control.removeMouseListener(mouseListener); }
shouldFireDoubleClick()函数:
private boolean shouldFireDoubleClick(int activationTime, int mouseTime, ColumnViewerEditorActivationEvent activationEvent) { return mouseTime <= activationTime && activationEvent.eventType != ColumnViewerEditorActivationEvent.KEY_PRESSED && activationEvent.eventType != ColumnViewerEditorActivationEvent.PROGRAMMATIC && activationEvent.eventType != ColumnViewerEditorActivationEvent.TRAVERSAL; }
如果间隔时间e.time-activationEvent.time>500ms 即:mouseTime>activationTime 则返回 false 展开Combo 反之,则返回true Combo不展开
再参考函数名和自己实际添加viewer.addDoubleClickListener()进行测试得出结论。
结论
由于tableViewer无法区分双击事件,是为了触发viewer的双击事件,还是触发CellEditor的展开。所以提供了500ms的阀值,如果两次MouseDown的时间间隔较小(<500ms)认为是触发双击,反之则认为展开CellEditor。
从判断timeout=cellEditor.getDoubleClickTimeout()是否为0的逻辑来看。jFace还是希望使用者通过重写cellEditor.getDoubleClickTimeout()的方法的返回值 在进行自己控制。
解决上述不灵敏的问题也就简单了。 重载getDoubleClickTimeout()返回0,怎屏蔽viewer的双击事件。 PS:如果想屏蔽CellEditor展开,返回个更大的值