• JavaFX2: 鼠标拖动选择和Ctrl+Shift连续区间选择的ListView


    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;
                }
            });
        }
    }
    


     

  • 相关阅读:
    如何让AlertDialog 在点击确定或者取消时不消失
    你的睡眠时间和睡眠质量达标了么?
    如何使用指定浏览器打开网页
    国内主流Android安卓应用市场简介
    位运算——pku2436患病的奶牛
    高精度——sgu112
    树插入,树遍历——hdu3999
    大浮点数相加——hdu1753
    小数的幂——pku1001
    递推型DP——USACO 2009 February Silver bull and cow
  • 原文地址:https://www.cnblogs.com/riskyer/p/3310578.html
Copyright © 2020-2023  润新知