在视口外拖动行时,JavaFX自动滚动表向上或向下

时间:2017-09-28 14:43:37

标签: javafx

我有一个表视图,您可以拖动行来重新定位数据。问题是在拖动视口内记录上方或下方的行时,使表格视图自动向上或向下滚动。

如何在JavaFX中实现这一目标?

categoryProductsTable.setRowFactory(tv -> {

        TableRow<EasyCatalogueRow> row = new TableRow<EasyCatalogueRow>();

        row.setOnDragDetected(event -> {
            if (!row.isEmpty()) {
                Dragboard db = row.startDragAndDrop(TransferMode.MOVE);
                db.setDragView(row.snapshot(null, null));
                ClipboardContent cc = new ClipboardContent();
                cc.put(SERIALIZED_MIME_TYPE, new ArrayList<Integer>(categoryProductsTable.getSelectionModel().getSelectedIndices()));
                db.setContent(cc);
                event.consume();
            }
        });

        row.setOnDragOver(event -> {
            Dragboard db = event.getDragboard();
            if (db.hasContent(SERIALIZED_MIME_TYPE)) {
                event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
                event.consume();

            }
        });

        row.setOnDragDropped(event -> {
            Dragboard db = event.getDragboard();
            if (db.hasContent(SERIALIZED_MIME_TYPE)) {
                int dropIndex;

                if (row.isEmpty()) {
                    dropIndex = categoryProductsTable.getItems().size();
                } else {
                    dropIndex = row.getIndex();
                }

                ArrayList<Integer> indexes = (ArrayList<Integer>) db.getContent(SERIALIZED_MIME_TYPE);

                for (int index : indexes) {
                    EasyCatalogueRow draggedProduct = categoryProductsTable.getItems().remove(index);
                    categoryProductsTable.getItems().add(dropIndex, draggedProduct);
                    dropIndex++;
                }

                event.setDropCompleted(true);
                categoryProductsTable.getSelectionModel().select(null);
                event.consume();

                updateSortIndicies();

            }
        });

        return row;
    });

1 个答案:

答案 0 :(得分:1)

好的,所以我明白了。不确定它是最好的方法,但它的工作原理。基本上我向表视图添加了一个事件监听器来处理DragOver事件。在表视图中拖动行时会触发此事件。

基本上,在执行拖动时,如果我们需要向上或向下滚动或者根本不滚动,我会计算出来。这是通过计算拖动的项目是否在表格视图的上部或下部邻近区域内来完成的。

由DragOver事件侦听器控制的单独线程然后处理滚动。

public class CategoryProductsReportController extends ReportController implements Initializable {

    @FXML
    private TableView<EasyCatalogueRow> categoryProductsTable;

    private ObservableList<EasyCatalogueRow> categoryProducts = FXCollections.observableArrayList();

    public enum ScrollMode {
        UP, DOWN, NONE
    }

    private AutoScrollableTableThread autoScrollThread = null;

    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {

        initProductTable();

    }

    private void initProductTable() {

        categoryProductsTable.setItems(categoryProducts);
        ...

        ...

        // Multi Row Drag And Drop To Allow Items To Be Re-Positioned Within 
        // Table
        categoryProductsTable.setRowFactory(tv -> {

            TableRow<EasyCatalogueRow> row = new TableRow<EasyCatalogueRow>();

            row.setOnDragDetected(event -> {
                if (!row.isEmpty()) {
                    Dragboard db = row.startDragAndDrop(TransferMode.MOVE);
                    db.setDragView(row.snapshot(null, null));
                    ClipboardContent cc = new ClipboardContent();
                    cc.put(SERIALIZED_MIME_TYPE, new ArrayList<Integer>(categoryProductsTable.getSelectionModel().getSelectedIndices()));
                    db.setContent(cc);
                    event.consume();
                }
            });

            row.setOnDragOver(event -> {
                Dragboard db = event.getDragboard();
                if (db.hasContent(SERIALIZED_MIME_TYPE)) {
                    event.acceptTransferModes(TransferMode.COPY_OR_MOVE);
                    event.consume();

                }
            });

            row.setOnDragDropped(event -> {
                Dragboard db = event.getDragboard();
                if (db.hasContent(SERIALIZED_MIME_TYPE)) {
                    int dropIndex;

                    if (row.isEmpty()) {
                        dropIndex = categoryProductsTable.getItems().size();
                    } else {
                        dropIndex = row.getIndex();
                    }

                    ArrayList<Integer> indexes = (ArrayList<Integer>) db.getContent(SERIALIZED_MIME_TYPE);

                    for (int index : indexes) {
                        EasyCatalogueRow draggedProduct = categoryProductsTable.getItems().remove(index);
                        categoryProductsTable.getItems().add(dropIndex, draggedProduct);
                        dropIndex++;
                    }

                    event.setDropCompleted(true);
                    categoryProductsTable.getSelectionModel().select(null);
                    event.consume();

                    updateSortIndicies();

                }
            });

            return row;
        });

        categoryProductsTable.addEventFilter(DragEvent.DRAG_DROPPED, event -> {
            if (autoScrollThread != null) {
                autoScrollThread.stopScrolling();
                autoScrollThread = null;
            }
        });

        categoryProductsTable.addEventFilter(DragEvent.DRAG_OVER, event -> {

            double proximity = 100;

            Bounds tableBounds = categoryProductsTable.getLayoutBounds();

            double dragY = event.getY();

            //System.out.println(tableBounds.getMinY() + " --> " + tableBounds.getMaxY() + " --> " + dragY);
            // Area At Top Of Table View. i.e Initiate Upwards Auto Scroll If
            // We Detect Anything Being Dragged Above This Line.
            double topYProximity = tableBounds.getMinY() + proximity;

            // Area At Bottom Of Table View. i.e Initiate Downwards Auto Scroll If
            // We Detect Anything Being Dragged Below This Line.
            double bottomYProximity = tableBounds.getMaxY() - proximity;

            // We Now Make Use Of A Thread To Scroll The Table Up Or Down If
            // The Objects Being Dragged Are Within The Upper Or Lower
            // Proximity Areas
            if (dragY < topYProximity) {
                // We Need To Scroll Up
                if (autoScrollThread == null) {
                    autoScrollThread = new AutoScrollableTableThread(categoryProductsTable);
                    autoScrollThread.scrollUp();
                    autoScrollThread.start();
                }

            } else if (dragY > bottomYProximity) {
                // We Need To Scroll Down
                if (autoScrollThread == null) {
                    autoScrollThread = new AutoScrollableTableThread(categoryProductsTable);
                    autoScrollThread.scrollDown();
                    autoScrollThread.start();
                }

            } else {
                // No Auto Scroll Required We Are Within Bounds
                if (autoScrollThread != null) {
                    autoScrollThread.stopScrolling();
                    autoScrollThread = null;
                }
            }

        });

    }
}

class AutoScrollableTableThread extends Thread {

    private boolean running = true;
    private ScrollMode scrollMode = ScrollMode.NONE;
    private ScrollBar verticalScrollBar = null;

    public AutoScrollableTableThread(TableView tableView) {
        super();
        setDaemon(true);
        verticalScrollBar = (ScrollBar) tableView.lookup(".scroll-bar:vertical");

    }

    @Override
    public void run() {

        try {
            Thread.sleep(300);
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        }

        while (running) {

            Platform.runLater(() -> {
                if (verticalScrollBar != null && scrollMode == ScrollMode.UP) {
                    verticalScrollBar.setValue(verticalScrollBar.getValue() - 0.01);
                } else if (verticalScrollBar != null && scrollMode == ScrollMode.DOWN) {
                    verticalScrollBar.setValue(verticalScrollBar.getValue() + 0.01);
                }
            });

            try {
                sleep(50);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public void scrollUp() {
        System.out.println("Start To Scroll Up");
        scrollMode = ScrollMode.UP;
        running = true;
    }

    public void scrollDown() {
        System.out.println("Start To Scroll Down");
        scrollMode = ScrollMode.DOWN;
        running = true;
    }

    public void stopScrolling() {
        System.out.println("Stop Scrolling");
        running = false;
        scrollMode = ScrollMode.NONE;
    }

}