为了账号安全,请及时绑定邮箱和手机立即绑定

JavaFX:使垂直 ScrollBar 适合 TableView 中的父节点

JavaFX:使垂直 ScrollBar 适合 TableView 中的父节点

郎朗坤 2022-08-03 12:44:26
我有一个垂直滚动的 TableView,我希望 ScrollBar 延伸到其父 AnchorPane 的顶部,并位于右上角填充方块的顶部。请参阅下文,了解默认情况下的情况。请注意,我的填充节点是白色的,这不是右上角的表列。在这行下面是我想要的,由另一个程序正确实现。我能够通过以下方法实现这一目标:Platform.runLater(() ->{    ScrollBar someScrollBar = (ScrollBar) someTable.lookup(".scroll-bar:vertical");    someScrollBar.setTranslateY(-12);    someScrollBar.setScaleY(1.2);});其中 是在 FXML 中创建的表视图,在控制器初始化函数中引用。someTable它看起来很好,但它不能正确缩放。如果包含的 AnchorPane 垂直调整大小,它看起来很糟糕。任何人都可以建议更好的方法来做到这一点吗?非常感谢您抽出宝贵时间接受采访。
查看完整描述

1 回答

?
哔哔one

TA贡献1854条经验 获得超8个赞

不支持滚动条的自定义布局。我最初的评论是,你需要一个带有自定义TableHeaderRow的自定义TableViewSkin:不幸的是,后者负责管理......好吧,tableHeader只是故事的一部分。

  • 一个 TableHeaderRow 确实负责布置表头

  • 但是:TableHeaderRow无法对垂直滚动条进行布局 - 当它试图在被覆盖中这样做时,它会立即重置layoutChildren()

  • 重置发生在VirtualFlow(它是滚动条的父级)中

因此,在一天结束时,我们需要

  • 一个自定义的 TableHeaderRow,表示需要放大和重新定位 scrollBar:下面的示例设置一个标记,如果 scrollBar 可见(待定:检查菜单按钮是否可见),并在 scrollBar 的属性映射中设置所需的额外高度

  • 一个自定义的VirtualFlow,可以处理标记并根据需要实际进行布局:下面的示例检查标记并在需要时调整大小/重新定位滚动条。

  • 一个自定义的 TableViewSkin 来注入两者(通过重写的工厂方法)

该示例是针对 fx11 编写的,应该适用于 fx10,但不适用于 fx9,因为后者不允许提供自定义 VirtualFlow:

public class TableWithoutCorner extends Application {


    /**

     * Custom TableHeaderRow that requests a larger vbar height

     * if needed.

     */

    private static class MyTableHeader extends TableHeaderRow {


        private Region cornerAlias;

        private ScrollBar vBar;

        private TableViewSkinBase skin;


        public MyTableHeader(TableViewSkinBase skin) {

            super(skin);

            this.skin = skin;

        }


        @Override

        protected void layoutChildren() {

            super.layoutChildren();

            adjustCornerLayout();

        }


        private void adjustCornerLayout() {

            checkAlias();

            // tbd: check also if corner is visible

            if (!vBar.isVisible()) {

                vBar.getProperties().remove("DELTA");

            } else { 

                vBar.getProperties().put("DELTA", getHeight());

            }

        }


        private void checkAlias() {

            if (cornerAlias == null) {

                cornerAlias = (Region) lookup(".show-hide-columns-button");

            }

            if (vBar == null) {

                vBar = (ScrollBar) skin.getSkinnable().lookup(".scroll-bar:vertical");

            }

        }


    }


    /**

     * Custom VirtualFlow that respects additinal height for its 

     * vertical ScrollBar.

     */

    private static class MyFlow extends VirtualFlow {


        private ScrollBar vBar;

        private Region clip;


        public MyFlow() {

            // the scrollbar to adjust

            vBar = (ScrollBar) lookup(".scroll-bar:vertical");

            // the clipped container to use for accessing viewport dimensions

            clip = (Region) lookup(".clipped-container");


        }


        /**

         * Overridden to adjust vertical scrollbar's height and y-location

         * after calling super.

         */

        @Override

        protected void layoutChildren() {

            super.layoutChildren();

            adjustVBar();

        }


        /**

         * Adjusts vBar height and y-location by the height as

         * requested by the table header.

         */

        protected void adjustVBar() {

            if (vBar.getProperties().get("DELTA") == null) return;

            double delta = (double) vBar.getProperties().get("DELTA");

            vBar.relocate(clip.getWidth(), - delta);

            vBar.resize(vBar.getWidth(), clip.getHeight() + delta);

        }


    }


    /**

     * Boilerplate: need custom TableViewSkin to inject a custom TableHeaderRow and

     * custom VirtualFlow.

     */

    private static class MyTableViewSkin<T> extends TableViewSkin<T> {


        public MyTableViewSkin(TableView<T> control) {

            super(control);

        }


        @Override

        protected TableHeaderRow createTableHeaderRow() {

            return new MyTableHeader(this);

        }


        @Override

        protected VirtualFlow<TableRow<T>> createVirtualFlow() {

            return new MyFlow();

        }


    }


    private Parent createContent() {

        TableView<Locale> table = new TableView<>(FXCollections.observableArrayList(Locale.getAvailableLocales())) {


            @Override

            protected Skin<?> createDefaultSkin() {

                return new MyTableViewSkin(this);

            }


        }; 

        TableColumn<Locale, String> col = new TableColumn<>("Name");

        col.setCellValueFactory(new PropertyValueFactory<>("displayName"));

        table.getColumns().addAll(col);

        return table;

    }


    @Override

    public void start(Stage stage) throws Exception {

        stage.setScene(new Scene(createContent()));

        //stage.setTitle(FXUtils.version());

        stage.show();

    }


    public static void main(String[] args) {

        launch(args);

    }


    @SuppressWarnings("unused")

    private static final Logger LOG = Logger

            .getLogger(TableWithoutCorner.class.getName());


}


查看完整回答
反对 回复 2022-08-03
  • 1 回答
  • 0 关注
  • 311 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号