【问题标题】:Binding two tableviews together such that they scroll in sync将两个表视图绑定在一起,使它们同步滚动
【发布时间】:2023-03-14 14:37:02
【问题描述】:

我想将两个表视图绑定在一起,使它们同步滚动。我怎么做?我不知道如何访问 tableview 的滚动条。

【问题讨论】:

    标签: java scrollbar tableview javafx javafx-2


    【解决方案1】:

    我做了一个 CSS hack,将 Tableview 与外部滚动条绑定。一个滚动条控制两个表格视图。

    我的想法概述:

    • 创建两个表视图
    • 制作一个垂直滚动条。在这个例子中我们称之为 myScrollbar
    • 将 myScrollbar 的最小值和最大值设置为 min=0, max=TableView.Items.size()
    • 当 myScrollbar 的值发生变化时,调用两个 tableview 的 scrollTo(int) 函数
    • 禁用使用 CSS 实现的 tableview 的原生垂直滚动条。

    这将为您提供两个表格,均由一个外部滚动条 (myScrollbar) 控制。

    下面是使用 css 隐藏 tableview 滚动条的代码:

    /* The main scrollbar **track** CSS class  */
    
    .mytableview .scroll-bar:vertical .track{
            -fx-padding:0px;
        -fx-background-color:transparent;
        -fx-border-color:transparent;
        -fx-background-radius: 0em;
        -fx-border-radius:2em;
    
    }
    
    /* The increment and decrement button CSS class of scrollbar */
    
    .mytableview .scroll-bar:vertical .increment-button ,
    .mytableview .scroll-bar:vertical .decrement-button {
    
        -fx-background-color:transparent;
        -fx-background-radius: 0em;
        -fx-padding:0 0 0 0;
    }
    
    .mytableview  .scroll-bar:vertical .increment-arrow,
    .mytableview  .scroll-bar:vertical  .decrement-arrow
    {
        -fx-shape: " "; 
        -fx-padding:0;        
    }
    
    /* The main scrollbar **thumb** CSS class which we drag every time (movable) */
    .mytableview .scroll-bar:vertical .thumb {
        -fx-background-color:transparent;
        -fx-background-insets: 0, 0, 0;
        -fx-background-radius: 2em;
        -fx-padding:0px;
    
    }
    

    然后我们需要设置如何使用滚动条来滚动tableview。

    scroll.setMax(100); //make sure the max is equal to the size of the table row data.
    scroll.setMin(0); 
    scroll.valueProperty().addListener(new ChangeListener(){
    
        @Override
        public void changed(ObservableValue ov, Number t, Number t1) {
            //Scroll your tableview according to the table row index
            table1.scrollTo(t1.intValue()); 
            table2.scrollTo(t1.intValue());
        }
    
    });
    

    http://blog.ngopal.com.np/2012/09/25/how-to-bind-vertical-scroll-in-multi-tableview/

    【讨论】:

    • 解决方案看起来很棒。把它写成一个帖子,这样它就会在堆栈溢出时存档,我会给你赏金。
    【解决方案2】:

    我认为目前这是不可能的。 TableViewSkin 继承自具有 VirtualFlow 字段的 VirtualContainerBase。 VirtualFlow 对象有两个 VirtualScrollBar 字段,即您所追求的 hbar 和 vbar。不过我看不出有什么办法。

    有趣的是,TableView 中还有一个私有的 contentWidth 字段,虽然这是私有的。我确信 JFX 团队对于开放太多可以理解的 API 非常谨慎。您可以要求将 contentWidth 字段作为 int 属性打开,作为 JFX JIRA 或 openjfx-dev 邮件列表上的功能请求。

    权宜之计是绑定表视图选择模型的选定项或索引属性。

    【讨论】:

    • 感谢您的意见。接受否定答案的习惯是什么?我不知道这是否真的是不可能的——证明它确实是不可能的。至少还要再等六天。
    【解决方案3】:

    我发现解决问题的最简单方法是将可见滚动条的 valueProperty 绑定到隐藏滚动条。

    // Controller 
    @FXML private TableView<MyBean> tableLeft;
    @FXML private TableView<MyBean> 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);
    }
    

    现在您必须在显示阶段并呈现表格后从 Application 调用绑定:

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

    现在表格应该通过鼠标、键或滚动条同步滚动。

    玩得开心,奥拉夫

    【讨论】:

      猜你喜欢
      • 2016-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-11
      • 2011-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多