JavaFX2的ListView中的多选没有提供鼠标拖动选择的功能,同时按下Ctrl和Shift后连续的区间选中也不支持,以下代码用于处理这两个问题,细节见代码注释:

import com.sun.javafx.scene.control.skin.ListViewSkin;
import com.sun.javafx.scene.control.skin.VirtualFlow;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.control.IndexedCell;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.input.MouseEvent; /**
* 该类增强了ListView本身的行中选中功能.
* <br/>1. 鼠标拖动选中
* <br/>2. 连续Ctrl+Shift区间选中
*
* 其中使用VirtualFlow vf = ((VirtualFlow) ((ListViewSkin)
* getChildrenUnmodifiable().get(0)).getChildrenUnmodifiable().get(0));来判断当前显示可见的行号,
* 使用setOnMousePressed/setOnMouseDragged/setOnMouseReleased来处理增强的拖动和Ctrl+Shift选中事件.
*
* 遗留问题: 当Ctrl+Shift操作后一次鼠标点击在一个已经选中的行时, 最后的结果会取消选中该行.
* 如果还需要添加其他鼠标事件而需要使用到选中状态时可能会有冲突, 还未测试.
*
* @author Alan Zeng
*/
public class DragSelectionListView<T extends Object> extends ListView<T> { /**
* 鼠标拖动之前ListView的选中状态. 在鼠标拖动的过程中需要根据拖动事件的起始行号和当前行号来计算新选中的行,
* 同事和原始选中状态结合作为新的选中状态.
*/
private ObservableList<Integer> oldSelectedIndices;
/**
* 鼠标拖动事件是否已经开始. 会在MouseDragged中设置为true, 在MouseReleased中重置为false
*/
private boolean isDragStarted = false;
/**
* 最后一次鼠标点击选中的行号. 每次鼠标点击时都会进行记录
*/
private int lastPressedRow;
/**
* 鼠标拖动事件的起始行. 会在MousePressed中设置为当前点击行, 在MouseReleased中重置为-1
*/
private int dragStartedRow = -1;
/**
* 上一次拖动经过的行号. 鼠标拖动事件过程中, 会不断的触发MouseDragged事件, 每次事件结束时记录鼠标所在行号,
* 在MouseReleased中重置为-1
*/
private int prevDragRow = -1; public DragSelectionListView() {
getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
addDragSelectionEventHandlers();
} public DragSelectionListView(ObservableList<T> ol) {
super(ol);
getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
addDragSelectionEventHandlers();
} /**
* 根据相对于ListView的坐标,获取鼠标所在行
*
* @param x
* @param y
* @return
*/
public int getRowAtPoint(double x, double y) {
int row = -1;
VirtualFlow vf = ((VirtualFlow) ((ListViewSkin) getChildrenUnmodifiable().get(0)).getChildrenUnmodifiable().get(0));
int firstIndex = vf.getFirstVisibleCell().getIndex();
int lastIndex = vf.getLastVisibleCell().getIndex();
for (int i = firstIndex; i <= lastIndex; i++) {
IndexedCell visibleCell = vf.getVisibleCell(i);
if (visibleCell.getBoundsInParent().contains(x, y)) {
row = i;
break;
}
}
return row;
} /**
* 获取当前显示出来的第一行行号
*
* @return
*/
public int getFirstVisibleRow() {
VirtualFlow vf = ((VirtualFlow) ((ListViewSkin) getChildrenUnmodifiable().get(0)).getChildrenUnmodifiable().get(0));
return vf.getFirstVisibleCell().getIndex();
} /**
* 获取当前显示出来的最后一行行号
*
* @return
*/
public int getLastVisibleRow() {
VirtualFlow vf = ((VirtualFlow) ((ListViewSkin) getChildrenUnmodifiable().get(0)).getChildrenUnmodifiable().get(0));
return vf.getLastVisibleCell().getIndex();
} /**
* 添加用于处理拖动选中和连续Ctrl+Shift选中的事件: MousePressed/MouseDraggedMouseReleased
*/
private void addDragSelectionEventHandlers() {
setOnMousePressed(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
final int rowAtPoint = getRowAtPoint(t.getX(), t.getY()); //<editor-fold defaultstate="collapsed" desc="当Shift和Ctrl键同时按下时,会增加选中鼠标两次点击之间的行(不分左右键)">
if (t.isControlDown() && t.isShiftDown()) {
final int min = Math.min(rowAtPoint, lastPressedRow);
final int max = Math.max(rowAtPoint, lastPressedRow);
DragSelectionListView.this.getSelectionModel().selectRange(min, max + 1);
}
//</editor-fold> dragStartedRow = rowAtPoint;
lastPressedRow = rowAtPoint;
}
});
setOnMouseDragged(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
int rowAtPoint = getRowAtPoint(t.getX(), t.getY());
if (prevDragRow == rowAtPoint) {
return;
} ObservableList<Integer> selectedIndices = DragSelectionListView.this.getSelectionModel().getSelectedIndices();
if (!isDragStarted) {
oldSelectedIndices = FXCollections.observableArrayList(selectedIndices);
isDragStarted = true;
} else {
DragSelectionListView.this.getSelectionModel().clearSelection();
for (Integer integer : oldSelectedIndices) {
DragSelectionListView.this.getSelectionModel().selectIndices(integer);
} if (dragStartedRow != -1) {
DragSelectionListView.this.getSelectionModel().selectRange(Math.min(rowAtPoint, dragStartedRow), Math.max(rowAtPoint, dragStartedRow) + 1);
}
} prevDragRow = rowAtPoint;
}
});
setOnMouseReleased(new EventHandler<MouseEvent>() {
@Override
public void handle(MouseEvent t) {
//下面主要是重置Drag完毕后的一些状态
dragStartedRow = -1;
prevDragRow = -1;
isDragStarted = false;
}
});
}
}

JavaFX2: 鼠标拖动选择和Ctrl+Shift连续区间选择的ListView的更多相关文章

  1. Ctrl+Shift+F12切换最大化编辑器

    常用快捷键(keymaps:Default情况下) Esc键编辑器(从工具窗口) F1帮助千万别按,很卡! F2(Shift+F2)下/上高亮错误或警告快速定位 F3向下查找关键字出现位置 F4查找变 ...

  2. (转)Eclipse快捷键大全,导包快捷键:ctrl+Shift+/

    Ctrl+1 快速修复(最经典的快捷键,就不用多说了)Ctrl+D: 删除当前行 Ctrl+Alt+↓ 复制当前行到下一行(复制增加)Ctrl+Alt+↑ 复制当前行到上一行(复制增加)Alt+↓ 当 ...

  3. Eclipse快捷键大全,导包快捷键:ctrl+Shift+/【转】

    Ctrl+Shift+L 显示所有快捷键 Ctrl+1 快速修复(最经典的快捷键,就不用多说了)Ctrl+D: 删除当前行 Ctrl+Alt+↓ 复制当前行到下一行(复制增加)Ctrl+Alt+↑ 复 ...

  4. CTRL+SHIFT

    CTRL+SHIFT+鼠标左右,上下拖动,可快速实现平行和垂直上下复制的功能,

  5. 【editplus经常用的快捷键】Editplus 选中一行ctrl+r,Edit 合并行 Ctrl+Shift+J 合并选定行 删除当前行

    Editplus 选中一行: ctrl+rEditplus 复制一行: ctrl+r选择行,然后ctrl+c复制.复制一行到下一行中:Editplus有:Ctrl+j 复制上一行的一个字符到当前行Ed ...

  6. echats 油表盘 鼠标拖动指针改变数值

    近期需要做一个鼠标拖动完成油表盘数值改变的功能,使用canvas感觉太麻烦,而且指针不太好监听和拖动,只能另谋出路,在网上参考了某位大神的操作,最终选择了echats来解决这个问题.废话不多说,直接上 ...

  7. python模拟鼠标拖动操作的方法

    本文实例讲述了python模拟鼠标拖动操作的方法.分享给大家供大家参考.具体如下: pdf中的书签只有页码,准备把现有书签拖到一个目录中,然后添加自己页签.重复的拖动工作实在无趣,还是让程序帮我实现吧 ...

  8. listbox鼠标拖动数据和为button注册快捷键

    将listbox1中的数据用鼠标拖动至listbox2,即有左至右. 分别对应控件注册如下事件DragEnter,MouseDown,DragDrop 代码如下: //P128 DataGridVie ...

  9. Android Studio 调试过程中快捷查看断点处变量值(Ctrl+Shift+I无效)?

    当你在做Keymap到Eclipse后,在debug过程中,在Eclipse中我们很喜欢用Ctrl+Shift+I去查看一个运算或者调用的结果,这样用起来很方便.但是keymap到Eclipse后,你 ...

随机推荐

  1. jquery $.post

    jQuery.post() jQuery.post( url [, data ] [, success ] [, dataType ] )Returns:jqXHR Description: Load ...

  2. cloudflare的新waf,用Lua实现的

    我们使用nginx贯穿了我们的网络,做前线web服务,代理,流量过滤.在某些情况下,我们已经扩充了nginx上我们自己的模块的核心C代码,但近期我们做了一个重大举措,与nginx结合使用lua 差点儿 ...

  3. Android-onInterceptTouchEvent()和onTouchEvent()总结

    老实说,这两个小东东实在是太麻烦了,很不好懂,我自己那api文档都头晕,在网上找到很多资料,才知道是怎么回事,这里总结一下,记住这个原则就会很清楚了: 1.onInterceptTouchEvent( ...

  4. android事件传递机制以及onInterceptTouchEvent()和onTouchEvent()详解二之小秘与领导的故事

    总结的不是很好,自己也有点看不懂,正好现在用到了,研究了一个,再次总结,方便大家查看 总则: 1.onInterceptTouchEvent中有个Intercept,这是什么意思呢?她叫拦截,你大概知 ...

  5. MVC客户端验证的小示例

    MVC客户端验证的小示例 配置客户端验证的可用性: <configuration> <appSettings>  <add key="ClientValidat ...

  6. SQL 教程

    SQL 教程 http://www.w3school.com.cn/sql/

  7. javascript笔记整理(函数)

    javascript函数的声明和调用将完成某一特定功能的代码集合起来,可以重复使用的代码块. 一.函数的声明方式(创建) A.基本语法(function  关键字)function 函数名([参数1] ...

  8. urllib模块

    python爬虫-urllib模块   urllib 模块是一个高级的 web 交流库,其核心功能就是模仿web浏览器等客户端,去请求相应的资源,并返回一个类文件对象.urllib 支持各种 web ...

  9. 网盘大全, 邮箱大全 good

    网盘推荐 115网盘 注册 百度网盘 注册 微云 注册 360云盘 注册 金山快盘 注册 新浪微盘 注册 和彩云 注册 酷盘 注册 OneDrive 外链 BOX 注册 Dropbox 注册 国内网盘 ...

  10. jquery mobile左右滑动切换页面

    jquery mobile左右滑动切换页面 $(function() {$("body").bind('swiperight', function() {  $.mobile.ch ...