设想我们有一个表,表中有很多数据(多到竖起滚动条至少要出现)。我们需要一个功能:用鼠标拖动某些项,然后将他们移动另一个位置,例如我们可能想一些名字相似啊,或者是内容相关度更高的数据项在一起。
要支持鼠标拖动,显示要增加drag-drop的支持,不过我不打算详细介绍这个,可以找些其他的资料看看。
大致希望实现以下功能:
1.希望在拖过某项时,有一个背景色的回显,需要增加一个变量以记录当前滑过的项:
private TableItem prevItem;
在dragOver()方法里设置滑过项的背景色,如下:
// 当拖动滑过表项时,设置滑过项的背景色,以标示 if (prevItem != null) { prevItem.setBackground(null); } Widget item = event.item; if (item != null && (item instanceof TableItem)) { ((TableItem) item).setBackground(getTable().getDisplay() .getSystemColor(SWT.COLOR_GRAY)); } prevItem = (TableItem) item;
2.如果有竖直滚动条在,当拖动最上或最下时,如果滚动条可用,则滚动:
/* * 以下处理滚动操作 */ // 如果竖直滚动条未出现,则不需要处理滚动 ScrollBar verticalBar = getTable().getVerticalBar(); int thumb = verticalBar.getThumb(); int maximum = verticalBar.getMaximum(); if (maximum == thumb) { return; } // 得到当前滚动条的位置 int selection = verticalBar.getSelection(); // 得到表项的高度 int itemHeight = getTable().getItemHeight(); // 得到表的绝对坐标位置 int y_table = getTable().toDisplay(0, 0).y; // 判断是向上滚动还是向下滚动,并处理 boolean isTop = event.y - y_table > itemHeight ? false : true; if (isTop && selection > 0) { getTable().showItem(getTable().getItem(selection - 1)); } else if (prevItem == null && !isTop && selection + thumb < maximum) { getTable().showItem(getTable().getItem(selection + thumb + 1)); }
3.实现移动
/** * * @param selection * @param currentItem * 鼠标放下时所对的表项 * @param isTop * 判断是在最顶端放下,还是在最低端放下,此项只针对当currentItem为空时有用 */ private void moveSelected(IStructuredSelection selection, Widget currentItem, boolean isTop) { if (selection.isEmpty()) { return; } List<Field0> continuousBlock = getFirstContinuousBlock(selection); boolean hasMoved = false; if (currentItem != null) { hasMoved = moveSelected2Current(continuousBlock, (TableItem) currentItem); } else if (isTop) { hasMoved = moveSelected2Top(continuousBlock); } else if (!isTop) { hasMoved = moveSelected2Bottom(continuousBlock); } if (hasMoved) { fireDragMovedEvent(); } }
这里的Field0是假设为表中存储的模型对象。
这里的hasMoved用于判断是否真的移动了项,如果移动了,发出一个事件通知。通常可以在这里定义一个移动监听列表,当移动时,发出通知,让监听实现者可以在移动后做一些事情。
移动的时候分移到最底、最顶或移到某个中间位置。
这里的getFirstContinuousBlock()方法用于得到一块连续选中区域:因为可能用户用鼠标加ctrl选中了很多非连续的区域,为了简单,我们只取第一个选中区,方法如下:
private List<Field0> getFirstContinuousBlock(IStructuredSelection selection) { List<Field0> list = selection.toList(); int firstId = Integer.parseInt(list.get(0).getId()); List<Field0> result = new ArrayList<Field0>(); for (int i = 0; i < list.size(); i++) { Field0 field0 = list.get(i); int id = Integer.parseInt(field0.getId()); if (id == firstId) { result.add(field0); } else { break; } firstId++; } return result; }
这个方法见仁见智。大家可以按自己的想法实现。
5.实现移动
最后就是实现三个对应的方法。也是见人见智。简单一些假如你的input是一个list或者是一个数组,那其实就是修改移动的对象在数组或者是list中的相对位置。