NatTable中如何正确拖拽已多选的行?
NatTable多行拖拽选中异常的解决方案
问题根源
你遇到的问题核心是NatTable的事件优先级:鼠标按下事件会先触发Ctrl+点击切换行选中的逻辑,再触发拖拽判断。当你按住Ctrl拖拽已选中的行时,按下鼠标的瞬间就会把当前点击的行从选中集合中移除,导致最终只有剩余行被拖拽。
解决步骤
1. 拦截拖拽场景下的选中切换逻辑
修改SelectionLayer的鼠标绑定,让Ctrl+点击切换选中的行为只在非拖拽场景生效:
// 先清除默认的Ctrl+点击选中绑定 selectionLayer.configureMouseClickBindings(); MouseBindingRegistry bindingRegistry = selectionLayer.getMouseBindingRegistry(); // 找到默认的Ctrl+点击切换行选中的绑定并移除 Optional<MouseBinding> targetBinding = bindingRegistry.getMouseBindings().stream() .filter(binding -> binding.getAction() instanceof SelectRowAction) .filter(binding -> { SelectRowAction action = (SelectRowAction) binding.getAction(); return !action.isShiftMask() && action.isCtrlMask(); }) .findFirst(); targetBinding.ifPresent(bindingRegistry::unregisterMouseBinding); // 注册自定义绑定:仅当非拖拽状态时,才触发Ctrl+点击切换选中 bindingRegistry.registerMouseBinding( new MouseEventMatcher(SWT.CTRL, MouseEventMatcher.ROW, MouseEventMatcher.LEFT_BUTTON) { @Override public boolean matches(NatTable natTable, MouseEvent event) { // 拖拽状态下不触发选中切换 return super.matches(natTable, event) && !natTable.getDragSource().isDragging(); } }, new SelectRowAction(false, true) );
2. 强制拖拽时携带所有选中行
自定义DragSourceListener,确保拖拽起始时获取的是SelectionLayer中所有选中的行,而非仅当前点击的行:
DragSource dragSource = new DragSource(natTable, DND.DROP_MOVE); dragSource.setTransfer(new RowTransfer()); dragSource.addDragListener(new DragSourceAdapter() { @Override public void dragStart(DragSourceEvent event) { List<Integer> selectedRows = selectionLayer.getSelectedRowIndexes(); // 无选中行则取消拖拽 event.doit = !selectedRows.isEmpty(); if (event.doit) { // 将所有选中行作为拖拽数据 event.data = selectedRows.toArray(new Integer[0]); } } @Override public void dragSetData(DragSourceEvent event) { // 再次确认拖拽数据为全选中行 event.data = selectionLayer.getSelectedRowIndexes().toArray(new Integer[0]); } });
3. 可选:自定义选中行为增强判断
如果上述方案仍有边界问题,可以自定义SelectRowAction,在执行选中切换前判断是否为拖拽操作:
public class DragAwareSelectRowAction extends SelectRowAction { public DragAwareSelectRowAction(boolean shiftMask, boolean ctrlMask) { super(shiftMask, ctrlMask); } @Override public void run(NatTable natTable, MouseEvent event) { // 若当前处于拖拽状态,直接跳过选中切换逻辑 if (natTable.getDragSource() != null && natTable.getDragSource().isDragging()) { return; } super.run(natTable, event); } }
使用时替换之前的SelectRowAction即可。
原理说明
通过修改事件触发条件,让选中切换逻辑和拖拽逻辑互斥:
- 拖拽起始时,拦截选中切换的触发
- 强制拖拽数据从
SelectionLayer的全选中集合中获取,而非依赖点击事件的目标行
内容的提问来源于stack exchange,提问作者user24643642
相关产品推荐
相关产品推荐

