最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - How to remove vertical ScrollBar from VirtualFlow? - Stack Overflow

programmeradmin1浏览0评论

I have a horizontal VirtualFlow and I need to remove vertical ScrollBar. This is my code:

public class NewMain extends Application {

    public class VirtualCell extends IndexedCell<String> {
        @Override
        protected void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            if (empty || item == null) {
                setText(null);
            } else {
                setText(item);
                setMinHeight(250); // 250 > scene height
                setPrefHeight(250); // 250 > scene height
            }
        }

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

    private static class MyVirtualFlow extends VirtualFlow<VirtualCell> {

        public MyVirtualFlow() {
            getVbar().setVisible(false);
            setVertical(false);
        }
    }

    private MyVirtualFlow virtualFlow = new MyVirtualFlow();

    @Override
    public void start(Stage primaryStage) {
        List<String> list = new ArrayList<>();
        for (var i = 0; i < 100; i++) {
            list.add("Item " + i);
        }
        ObservableList<String> items = FXCollections.observableArrayList(list);

        virtualFlow.setCellFactory(vf -> new VirtualCell());
        virtualFlow.setCellCount(items.size());

        virtualFlow.setCellFactory(vf -> new VirtualCell() {
            @Override
            public void updateIndex(int index) {
                super.updateIndex(index);
                if (index >= 0 && index < items.size()) {
                    updateItem(items.get(index), false);
                } else {
                    updateItem(null, true);
                }
            }
        });

        VBox.setVgrow(virtualFlow, Priority.ALWAYS);
        var root = new VBox(this.virtualFlow);
        Scene scene = new Scene(root, 400, 200);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

As you see I tried to remove it using getVbar().setVisible(false); in VirtualFlow constructor. But it didn't work. Could anyone say how to do it , if it is possible.

I have a horizontal VirtualFlow and I need to remove vertical ScrollBar. This is my code:

public class NewMain extends Application {

    public class VirtualCell extends IndexedCell<String> {
        @Override
        protected void updateItem(String item, boolean empty) {
            super.updateItem(item, empty);
            if (empty || item == null) {
                setText(null);
            } else {
                setText(item);
                setMinHeight(250); // 250 > scene height
                setPrefHeight(250); // 250 > scene height
            }
        }

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

    private static class MyVirtualFlow extends VirtualFlow<VirtualCell> {

        public MyVirtualFlow() {
            getVbar().setVisible(false);
            setVertical(false);
        }
    }

    private MyVirtualFlow virtualFlow = new MyVirtualFlow();

    @Override
    public void start(Stage primaryStage) {
        List<String> list = new ArrayList<>();
        for (var i = 0; i < 100; i++) {
            list.add("Item " + i);
        }
        ObservableList<String> items = FXCollections.observableArrayList(list);

        virtualFlow.setCellFactory(vf -> new VirtualCell());
        virtualFlow.setCellCount(items.size());

        virtualFlow.setCellFactory(vf -> new VirtualCell() {
            @Override
            public void updateIndex(int index) {
                super.updateIndex(index);
                if (index >= 0 && index < items.size()) {
                    updateItem(items.get(index), false);
                } else {
                    updateItem(null, true);
                }
            }
        });

        VBox.setVgrow(virtualFlow, Priority.ALWAYS);
        var root = new VBox(this.virtualFlow);
        Scene scene = new Scene(root, 400, 200);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

As you see I tried to remove it using getVbar().setVisible(false); in VirtualFlow constructor. But it didn't work. Could anyone say how to do it , if it is possible.

Share Improve this question asked Mar 17 at 18:00 SilverCubeSilverCube 6443 silver badges12 bronze badges 7
  • 3 The automatically managed scroll bars in VirtualFlow are one of its design features. If you do not want this feature, you should not use VirtualFlow rather than trying to make it not do something it was designed to do. Just my opinion. – jewelsea Commented Mar 17 at 21:01
  • 2 VirtualFlow is not the same as Flowless. A policy for the control of the scroll function is not a feature of VirtualFlow. Your opinion on whether it should be a feature doesn't matter, as that is not the way the control was designed. The ability to not display a node in the scene by making the node invisible is standard for JavaFX (though the invisible node will still take up space unless you make it unmanaged and other layout code stops accounting for it). – jewelsea Commented Mar 17 at 22:04
  • 2 In the case of VIrtualFlow, it can add and remove scroll bars based on its internal algorithm (which is not configurable). So it might make the scroll bar invisible at one point in time, but it might be visible later, and it could accomplish that by removing an old scroll bar and creating a completely new one. So your call to control invisibility at one point in time might not persist and always apply. In general, what you are trying to do may be difficult given the VirtualFlow design. – jewelsea Commented Mar 17 at 22:07
  • 2 There are some old enhancement requests related to this: JDK-8090721, JDK-8091884 and others. An implementation would likely involve an API in VirtualFlow. But unfortunately, what you want is not currently supported. One workaround that might work is setting the scroll bars' min/pref/max width/height to 0 via CSS. – Slaw Commented Mar 17 at 22:51
  • 1 Completely agree with other comments on here. VirtualFlow manages its own scroll bars, and does so in computing its layout each time it performs a layout pass. If you make the content taller than the space it has available, it will add a vertical scroll bar. Use the API the way it’s designed. – James_D Commented Mar 18 at 2:18
 |  Show 2 more comments

1 Answer 1

Reset to default 4

Firstly I agree with all the suggestions provided by @jewelsea and @slaw. You are defying the purpose of VirtualFlow. But if you desperately want to give a try, below is a way to can try to approach.

Note: I am not recommending this approach. The sole purpose is to let you know why setting visible will not fix and a workaround for that.

Though the scroll bar is initiated only once per VirtualFlow instance, its visibility is computed dynamically based on the current state of the VirtualFlow. The scrollbars visibility is recomputed in layoutChildren() method by calling computeBarVisiblity(). The code of this method is as below.

private boolean computeBarVisiblity() {
        if (cells.isEmpty()) {
            // In case no cells are set yet, we assume no bars are needed
            needLengthBar = false;
            needBreadthBar = false;
            return true;
        }

        final boolean isVertical = isVertical();
        boolean barVisibilityChanged = false;

        VirtualScrollBar breadthBar = isVertical ? hbar : vbar;
        VirtualScrollBar lengthBar = isVertical ? vbar : hbar;

        final double viewportBreadth = getViewportBreadth();

        final int cellsSize = cells.size();
        final int cellCount = getCellCount();
        for (int i = 0; i < 2; i++) {
            final boolean lengthBarVisible = getPosition() > 0
                    || cellCount > cellsSize
                    || (cellCount == cellsSize && (getCellPosition(cells.getLast()) + getCellLength(cells.getLast())) > getViewportLength())
                    || (cellCount == cellsSize - 1 && barVisibilityChanged && needBreadthBar);

            if (lengthBarVisible ^ needLengthBar) {
                needLengthBar = lengthBarVisible;
                barVisibilityChanged = true;
            }

            final boolean breadthBarVisible = !suppressBreadthBar && (maxPrefBreadth > viewportBreadth);
            if (breadthBarVisible ^ needBreadthBar) {
                needBreadthBar = breadthBarVisible;
                barVisibilityChanged = true;
            }
        }

        // Start by optimistically deciding whether the length bar and
        // breadth bar are needed and adjust the viewport dimensions
        // accordingly. If during layout we find that one or the other of the
        // bars actually is needed, then we will perform a cleanup pass

        if (!Properties.IS_TOUCH_SUPPORTED) {
            updateViewportDimensions();
            breadthBar.setVisible(needBreadthBar);
            lengthBar.setVisible(needLengthBar);
        } else {
            breadthBar.setVisible(needBreadthBar && tempVisibility);
            lengthBar.setVisible(needLengthBar && tempVisibility);
        }
        return barVisibilityChanged;
    }

So setting the visibility at only one point will not work and will be overriden.

One way to fix this, is by setting the prefWidth of the vBar to 0px, so that the layout computation will ignore the Vbar. But setting prefWidth to 0px alone is not sufficient. The arrows of inc/dec button are still visible (I have not yet checked why it is happening..). To fix that, you can set the opacity of VBar to 0.

Once you update the below changes to MyVirtualFlow, the VBar is not visible anymore.

Option#1: (using API)

private static class MyVirtualFlow extends VirtualFlow<VirtualCell> {
    public MyVirtualFlow() {
        setVertical(false);
        getVbar().setPrefWidth(0);
        getVbar().setOpacity(0);
    }
}

Option#2: (using CSS)

private static class MyVirtualFlow extends VirtualFlow<VirtualCell> {
    private final static String CSS = "data:text/css," +
            """
            .virtual-flow > .scroll-bar:vertical{
                -fx-pref-width: 0px;
            }
            .virtual-flow > .scroll-bar:vertical .increment-arrow,
            .virtual-flow > .scroll-bar:vertical .decrement-arrow{
                -fx-padding: 0px;
            }
    """;

    public MyVirtualFlow() {
        setVertical(false);
        getStylesheets().add(CSS);
    }
}

发布评论

评论列表(0)

  1. 暂无评论