Binding two tableviews together such that they scroll in sync

前端 未结 3 1215
甜味超标
甜味超标 2021-02-10 06:38

I want to bind two tableviews together such that they scroll in sync. How do I do that? I am unable to find out how to access the scrollbar of a tableview.

3条回答
  •  天涯浪人
    2021-02-10 07:26

    The easiest way I've found to solve the problem is to bind the valueProperty of the visible an the hidden scrollbars.

    // Controller 
    @FXML private TableView tableLeft;
    @FXML private TableView tableRight;
    @FXML private ScrollBar scrollBar;
    
    
    @SuppressWarnings("rawtypes")
    private void bindScrollBars(TableView tableView1, TableView tableView2, 
                     ScrollBar scrollBar, Orientation orientation) {
    
        // Get the scrollbar of first table
        VirtualFlow vf = (VirtualFlow)tableView1.getChildrenUnmodifiable().get(1);
        ScrollBar scrollBar1 = null;
        for (final Node subNode: vf.getChildrenUnmodifiable()) {
            if (subNode instanceof ScrollBar && 
                    ((ScrollBar)subNode).getOrientation() == orientation) {
                scrollBar1 = (ScrollBar)subNode;
            }
         }
    
        // Get the scrollbar of second table
        vf = (VirtualFlow)tableView2.getChildrenUnmodifiable().get(1);
        ScrollBar scrollBar2 = null;
        for (final Node subNode: vf.getChildrenUnmodifiable()) {
            if (subNode instanceof ScrollBar && 
                    ((ScrollBar)subNode).getOrientation() == orientation) {
                scrollBar2 = (ScrollBar)subNode;
            }
         }
    
        // Set min/max of visible scrollbar to min/max of a table scrollbar
        scrollBar.setMin(scrollBar1.getMin());
        scrollBar.setMax(scrollBar1.getMax());
    
        // bind the hidden scrollbar valueProterty the visible scrollbar
        scrollBar.valueProperty().bindBidirectional(scrollBar1.valueProperty());
        scrollBar.valueProperty().bindBidirectional(scrollBar2.valueProperty());
    }
    
    /*
     * This method must be called in Application.start() after the stage is shown,
     * because the hidden scrollbars exist only when the tables are rendered
     */
    public void setScrollBarBinding() {
        bindScrollBars(this.tableLeft, this.tableRight, this.scrollBar, Orientation.VERTICAL);
    }
    

    Now you have to call the binding from Application after the stage is shown and the tables are rendered:

    // Application
        private MyController controller;
    
        @Override
        public void start(Stage primaryStage) {
            try {
                FXMLLoader fxmlLoader = new FXMLLoader(SalesApp.class.getResource("scene.fxml"));
                BorderPane root = (BorderPane) fxmlLoader.load();;
                Scene scene = new Scene(root);
                scene.getStylesheets().add(getClass().getResource("app.css").toExternalForm());
                primaryStage.setScene(scene);
                primaryStage.show();            
    controller = (MyController) fxmlLoader.getController();
                controller.setScrollBarBinding();
            } catch(Exception e) {
                e.printStackTrace();
            }
        }
    

    Now the tables should scroll synchronously via mouse, key, or scrollbar.

    Have fun, Olaf

提交回复
热议问题