1. 程式人生 > >JavaFX2: 滑鼠拖動選擇和Ctrl+Shift連續區間選擇的ListView

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

相關推薦

JavaFX2: 滑鼠選擇Ctrl+Shift連續區間選擇ListView

JavaFX2的ListView中的多選沒有提供滑鼠拖動選擇的功能,同時按下Ctrl和Shift後連續的區間選中也不支援,以下程式碼用於處理這兩個問題,細節見程式碼註釋: import com.sun.javafx.scene.control.skin.ListViewS

Unity基礎篇:Unity使用滑鼠2D3D物體。

 /*     首先說一下,Input.mousePosition是滑鼠所在畫素平面內的座標,需要根據自己的需求轉變成世界座標。         Description 描述         The

OFFICE2007 WORD中無法使用滑鼠選取選單項

方法一(推薦):   開啟Word,點選左上角的圓形按鈕,選擇"Word選項",然後選擇"載入項",接著在最下端的"管理"右側的下拉框中選擇"COM載入項",然後點選"轉到按鈕",最後在彈出的"COM載入項"管理視窗中取消"PowerDesigner12....."載入項前

C# WPF實現滑鼠的程式碼片

C# WPF實現滑鼠拖動的程式碼片 ///可表示實時拖動 void xxx_PreviewMouseLeftButtonUp(System.Object sender, System.Windows.Input.MouseButtonEventArgs e) { IsMous

QT練手專案二:滑鼠視窗

     對於一個沒有邊框的視窗,滑鼠是無法將它拖動的,於是我們就需要自己重寫滑鼠的點選、移動和釋放事件來跟蹤滑鼠,從而 達到使用滑鼠拖動視窗,這裡我們就簡單的使用一個mainwindow來演示。這個小專案程式碼非常少,適合用來入門QT。 &nb

原生js實現table列寬的滑鼠事件

var tTD; //用來儲存當前更改寬度的Table Cell,避免快速移動滑鼠的問題 var table = document.getElementById("tableId"); //table的id名稱 for (j = 0; j < table.rows[0].cells.le

Qt 繪製可以用滑鼠的線段

一、環境 VS2013 + QT5.7.0 二、效果 1.可以建立任意多條線段; 2.滑鼠在靠近到線段時產生吸附效果; 3.可以拖動任意一條線段的任意部位(線段的兩個端點或者整條線段)。 效果圖: 三、說明 1.建立線段的定義: 線段具有

C#窗體屬性FormBordeStyle設定為none後,通過程式碼實現窗體滑鼠功能

備註:使用的是visual studio2013版本 1、新建C#窗體應用程式,初始化的程式預設FormBordeStyle屬性為Sizable,修改屬性FormBordeStyle為none (1)修改前 (2)修改後 2、F5除錯程式後,此時窗體沒有邊框、

QML之滑鼠ListView中某項的位置

現有一種需求,就是用滑鼠拖動某項,動態去改變某一項在ListView中顯示的順序位置,經過研究及實踐實戰,實現方式的核心程式碼如下: import QtQuick 2.4 import QtQuick.Controls 1.3 import QtQuick.Window 2

C#Winform實現無邊框窗體滑鼠

在有時候我們為了實現軟體的美觀,我們需要把窗體的邊框隱藏,但是問題也會隨之而來,在屬性中設定了FormBorderStyle應該為None,邊框便可以隱藏,但是我們在使用軟體時卻無法拖動窗體,

WPF無邊框視窗滑鼠縮放大小

通常,我們會 通過AllowsTransparency=”True”、 WindowStyle=”None” 這兩個屬性將wpf視窗的邊框去掉,由於邊框沒了,我們就不能通過滑鼠指標懸停在某一邊上拖動改變視窗的大小,此時若要能調整視窗大小,官方倒也提供了個屬性:R

c# 實現用滑鼠沒有標題欄的視窗(窗體的任何部分都可實現效果)

上面形式的窗體,實現窗體的任何部分都可實現拖動 首先需要引入非託管程式碼,直接呼叫windows api         public const int WM_NCLBUTTONDOWN = 0xA1;         public const int HT_CAPT

將Eclipse的ctrl + kctrl + shift + k功能移到IDEA中

前言: 由於不習慣記那麼多的快捷鍵,在使用IDEA時使用Eclipse的快捷鍵模板。常用的其實也就那麼幾個,有些可能在IDEA中就變了,比如ctrl + k查詢下一個 在IDEA中設定ctrl + k: 設定如下圖,已劃重點 敲黑板: 設定完後,你會發現選中文字後按ct

帶節點的曲線,可以滑鼠節點,類似PS

轉自:http://topic.csdn.net/u/20120626/22/D778EDE8-CC97-4F13-AC5D-DA65BFB94E50.html 先來PS的 再來剛做的,極其簡單。 思路很簡單 1.曲線由一組Point表示節點 2.滑鼠移動節點實際是修改單

WPF 使用滑鼠一個控制元件的實現[2018.7.15]

原文: WPF 使用滑鼠拖動一個控制元件的實現[2018.7.15] Q:已經把一個Shape和一個TextBlock組合起來放到了一個Grid中,現在想要實現用滑鼠拖動這個Grid到任意位置的功能,如何做? <Grid Height="50" Width="50">

FLASH滑鼠

on (press) { startDrag(this,true); } on (release) { stopDrag(); } 另請 我們知道按鈕有一個優點是可以跟滑鼠配合默契,除了單擊以外,還可以用滑鼠來拖動按鈕,這樣就可以編制出一些遊戲的效果,這一節我

c++builder如何通過滑鼠改變無邊框窗體的大小(bsnone)

在C++Builder中,將Form的BorderStyle設為bsNone以後該窗體將沒有邊框,不能改變窗體大小,也不能拖動窗體。那麼如何拖動及用滑鼠改變無邊框窗體大小呢?拖動無邊框窗體的解決方法很多,例如:1. 向窗體傳送WM_NCLBUTTONDOWN訊息,LParam = HTCAPTION2. 向窗

c# WPF 中圖片縮放功能,滑鼠位置

<Window x:Class="LJDX.MainWindow"         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"         xmlns:x="http://sc

unity按下滑鼠3D物體指令碼

public class ObjectDragger : MonoBehaviour { private Vector3 screenPoint; private Vector3 offset; bool dragged = false; private V

前端滑鼠事件衝突

幾個月前曾處理過一個問題單,底層為canvas,支援圖形拖拽,有一個功能點要求彈出一個對話方塊,且不能使用遮罩層,因為想實現這樣的效果:點選canvas上的一個元素,對話方塊顯示其具體資訊,若使用遮罩層,必須將對話方塊關閉才能點選到canvas上的元素。 好吧