【问题标题】:JavaFX tableview auto scroll to selected item when pressing a button to selectNext() or selectPrevious()JavaFX 表格视图在按下按钮 selectNext() 或 selectPrevious() 时自动滚动到所选项目
【发布时间】:2022-01-03 15:58:47
【问题描述】:

我正在编写一个 JavaFX 程序,其中包含一个名为“table”的 TableView 和两个名为“previous”和“next”的按钮。

下面是部分代码:

previous.setOnAction(event -> {
     table.getSelectionModel().selectPrevious();
});

next.setOnAction(event -> {
     table.getSelectionModel().selectNext();
});

但是,如果我一直按下按钮,表格将不会自动滚动以保持所选项目可见。所以我修改了这样的代码:

previous.setOnAction(event -> {
     table.getSelectionModel().selectPrevious();
     table.scrollTo(table.getSelectionModel().getSelectedItem());
});

next.setOnAction(event -> {
     table.getSelectionModel().selectNext();
     table.scrollTo(table.getSelectionModel().getSelectedItem());
});

但它会始终尝试将所选项目保持在可见区域的顶部。如果我一直按“下一步”。选定的项目将停留在顶部而不是底部。

我想模仿 tableview 的自然行为,如果我在键盘上按下或按下选定的内容,tableview 将自动滚动以保持所选项目可见。

我应该如何修改代码以使按下按钮时自动滚动更自然?

谢谢

【问题讨论】:

  • 尝试创建上下按键事件并在桌上触发它们。
  • 你能详细说明一下吗?
  • 不是在这个时候,这就是为什么我发表评论而不是 anser。
  • 控制 scrollTo 的确切行为是一个长期开放的 rfe bugs.openjdk.java.net/browse/JDK-8091220 - 在得到支持之前,您可以尝试一个自定义皮肤,它公开 onSelectNext (和类似的)以用于自定义表和用那个。另一种选择可能是查找可见单元格的数量(virtualFlow 具有查找第一个/最后一个可见单元格的公共方法)并进行一些计算以找到 scrollTo 的索引,以便您想要在底部的单元格就在里面。一切都不好,但可行;)

标签: javafx tableview


【解决方案1】:

问题是

  • 在应用程序级别缺少对 scrollTo 目标位置的细粒度控制
  • virtualizedControl.scrollTo(index) 的(有点不幸)实现(最终)导致调用flow.scrollToTop(index)

有一个long-standing RFE(2014 年报告!)要求对应用程序代码进行更好的控制。实际上,VirtualFlow 有提供这样的公共方法(scrollToTop、scrollTo、scrollPixels),只是它们不会传递到控制层(VirtualContainerBase 中的 getVirtualFlow 是最终保护的),因此不能在自定义皮肤中被覆盖。从 fx12 开始,我们可以稍微修改一下,暴露 Tree/TableViewSkin 的 onSelectXX 并直接在应用程序代码(下面的示例)或自定义 TableView 中使用它们。

示例代码:

public class TableSelectNextKeepVisible extends Application {

    /**
     * Custom table skin to expose onSelectXX methods for application use.
     */
    public static class MyTableSkin<T> extends TableViewSkin<T> {

        public MyTableSkin(TableView<T> control) {
            super(control);
        }

        /**
         * Overridden to widen scope to public.
         */
        @Override
        public void onSelectBelowCell() {
            super.onSelectBelowCell();
        }

        /**
         * Overridden to widen scope to public.
         */
        @Override
        public void onSelectAboveCell() {
            super.onSelectAboveCell();
        }

    }
    
    private Parent createContent() {
        TableView<Locale> table = new TableView<>(FXCollections.observableArrayList(Locale.getAvailableLocales())) {

            @Override
            protected Skin<?> createDefaultSkin() {
                return new MyTableSkin<>(this);
            }

        };

        TableColumn<Locale, String> country = new TableColumn<>("Column");
        country.setCellValueFactory(new PropertyValueFactory<>("displayLanguage"));
        table.getColumns().addAll(country);

        Button next = new Button("next");
        next.setOnAction(e -> {
            table.getSelectionModel().selectNext();
            // scrolls to top
//            table.scrollTo(table.getSelectionModel().getSelectedIndex());
            ((MyTableSkin<?>) table.getSkin()).onSelectBelowCell();

        });

        Button previous = new Button("previous");
        previous.setOnAction(e -> {
            table.getSelectionModel().selectPrevious();
            // scrolls to top
//            table.scrollTo(table.getSelectionModel().getSelectedIndex());
            ((MyTableSkin<?>) table.getSkin()).onSelectAboveCell();

        });

        BorderPane content = new BorderPane(table);
        content.setBottom(new HBox(10, next, previous));
        return content;
    }

    @Override
    public void start(Stage stage) throws Exception {
        stage.setScene(new Scene(createContent()));
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

}

【讨论】:

    【解决方案2】:

    尝试如下使用 getSelectedIndex 而不是使用 getSelectedItem

    previous.setOnAction(event -> {
         table.getSelectionModel().selectPrevious();
         table.scrollTo(table.getSelectionModel().getSelectedIndex());
    });
    

    【讨论】:

    • @kleopatra 因为我这么说,我这样做是对问题的建议
    • 这是错误的 - 行为是相同的,无论您使用哪种 scrollTo 方法。想知道您是否尝试过您的建议?如果是这样,你看到区别了吗?将新选择的行保持在视口底部是否有帮助?
    • 我测试了 getSelectedIndex(),它的工作原理与 getSelectedItem() 完全相同。有时间我会尝试@kleopatra 的建议。谢谢你们。
    • 也许Keeping selected row这个帖子会给你一些线索
    【解决方案3】:

    Platform.runLater( () -&gt; TABLE_NAME.scrollTo(TABLE_INFORMATION_LIST.getList().size()-index) ); 如果您在向表格中添加信息时调用它应该可以工作。

    【讨论】:

    • hmm .. 每当您向表格添加信息时与问题无关,不是吗;)
    • .. 但即使它在哪里:sn-p 应该实现什么确切?什么是索引?什么是 getList()?这些常量是什么?
    猜你喜欢
    • 2014-07-31
    • 1970-01-01
    • 1970-01-01
    • 2020-12-18
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多