关于JFace的TableViewer中引入ComboBoxCellEditor 快速双击对于Cell Combo无法展开问题的解决

时间:2023-01-18 12:42:42

背景:

之前我上传过一个关于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展开,返回个更大的值