Efficient VirtualFlow for JavaFX

Related tags

GUI javafx viewport
Overview

Flowless

Efficient VirtualFlow for JavaFX. VirtualFlow is a layout container that lays out cells in a vertical or horizontal flow. The main feature of a virtual flow is that only the currently visible cells are rendered in the scene. You may have a list of thousands of items, but only, say, 30 cells are rendered at any given time.

JavaFX has its own VirtualFlow, which is not part of the public API, but is used, for example, in the implementation of ListView. It is, however, not very efficient when updating the viewport on items change or scroll.

Here is a comparison of JavaFX's ListView vs. Flowless on a list of 80 items, 25 of which fit into the viewport.

Flowless (# of cell creations / # of cell layouts) JDK 8u40 ListView (# of updateItem calls / # of cell layouts) JDK 8u40 ListView with fixed cell size (# of updateItem calls / # of cell layouts)
update an item in the viewport 1/1 1/1 1/1
update an item outside the viewport 0/0 0/0 0/0
delete an item in the middle of the viewport 1/1 38/25 38/25
add an item in the middle of the viewport 1/1 38/25 38/25
scroll 5 items down 5/5 5/5 5/5
scroll 50 items down 25/25 50/25 25/25

Here is the source code of this mini-benchmark.

Use case for Flowless

You will benefit from Flowless (compared to ListView) the most if you have many item updates and an expensive updateItem method.

Note, however, that Flowless is a low-level layout component and does not provide higher-level features like selection model or inline editing. One can, of course, implement those on top of Flowless.

Additional API

VirtualFlow in Flowless provides additional public API compared to ListView or VirtualFlow from JavaFX.

Direct cell access with getCell(itemIndex) and getCellIfVisible(itemIndex) methods. This is useful for measurement purposes.

List of currently visible cells via visibleCells().

Hit test with the hit(double x, double y) method that converts viewport coordinates into a cell index and coordinates relative to the cell, or indicates that the hit is before or beyond the cells.

Navigate to a subregion of a cell using the show(itemIndex, region) method. This is a finer grained navigation than just the show(itemIndex) method.

Scroll: scrollX(deltaX) and scrollY(deltaY) methods.

Gravity: You can create VirtualFlow where cells stick to the bottom (vertical flow) or right (horizontal flow) when there are not enough items to fill the viewport.

Conceptual differences from ListView

Dumb cells. This is the most important difference. For Flowless, cells are just Nodes and don't encapsulate any logic regarding virtual flow. A cell does not even necessarily store the index of the item it is displaying. This allows VirtualFlow to have complete control over when the cells are created and/or updated.

Cell reuse is opt-in, not forced. Cells are not reused by default. A new cell is created for each item. This simplifies cell implementation and does not impair performance if reusing a cell would be about as expensive as creating a new one (i.e. updateItem would be expensive).

No empty cells. There are no empty cells used to fill the viewport when there are too few items. A cell is either displaying an item, or is not displayed at all.

Assumptions about cells

As noted before, for the purposes of virtual flow in Flowless the cells are just Nodes. You are not forced to inherit from ListCell. However, they are expected to behave according to the following rules:

  • Cells of a vertical virtual flow should properly implement methods
    • computeMinWidth(-1)
    • computePrefWidth(-1)
    • computePrefHeight(width)
  • Cells of a horizontal virtual flow should properly implement methods
    • computeMinHeight(-1)
    • computePrefHeight(-1)
    • computePrefWidth(height)

Include Flowless in your project

Maven coordinates

Group ID Artifact ID Version
org.fxmisc.flowless flowless 0.6.3

Gradle example

dependencies {
    compile group: 'org.fxmisc.flowless', name: 'flowless', version: '0.6.3'
}

Sbt example

libraryDependencies += "org.fxmisc.flowless" % "flowless" % "0.6.3"

Manual download

Download the 0.6.3 jar and place it on your classpath.

Documentation

Javadoc

Comments
  • Can't Get Clicked Item in List

    Can't Get Clicked Item in List

    I Have A Virtual ScrollPane Displays All I want, except I cant Click Any Items. Ima Currently Using Gridpane as the node in virtual flow,is that the way to Go ? Screenshot (1505)

    opened by newtingz 27
  • Workaround to correct trackpad scrolling gestures under macOS

    Workaround to correct trackpad scrolling gestures under macOS

    I didn't create this fix, but @StrangeNoises. It was never applied for some reason, but it should fix FXMisc/RichTextFX/issues/265.

    I don't know if this is the "correct" way of fixing it or not, but it works as expected on my OSX machine.

    opened by Arcnor 22
  • Added ScaledVirtualized class

    Added ScaledVirtualized class

    How's this? I'm also not sure if there might be some unwanted implications of adding the Scale object to the ScaledVirtualized wrapper and not the Virtualized content itself

    opened by JordanMartinez 11
  • Make VirtualFlow's scrollBars optional

    Make VirtualFlow's scrollBars optional

    Coming from TomasMikula/RichTextFX#205, allow the option of not showing the horizontal and/or the vertical scrollBars.

    Tomas already said in the above issue:

    Hard-wiring auto-scrollbars into VirtualFlow didn't feel quite right from the start. On the other hand, the internal architecture of VirtualFlow already very much separates the scrollbar concern: VirtualFlow basically just adds scrollbars onto VirtualFlowContent

    opened by JordanMartinez 11
  • Exposed VirtualFlowContent's totalBreadthEstimate & totalLengthEstimate Properties

    Exposed VirtualFlowContent's totalBreadthEstimate & totalLengthEstimate Properties

    I didn't know what the final de-skinned form of RichTextFX would look like, so I decided to work one exposing its scroll properties. However, I can't expose the scrolling properties in RichTextFX unless VirtualFlow itself has them exposed.

    opened by JordanMartinez 10
  • JavaFX 17 breaks scrollbar behaviours in VirtualizedScrollPane

    JavaFX 17 breaks scrollbar behaviours in VirtualizedScrollPane

    Starting with javaFX 17-ea+11 I noticed that scrolling a StyledTextArea (from RichTextFX) no longer worked properly: when clicking the scroll bar elements, the text scrolls for the first couple of clicks and then entirely stop responding to clicks on these elements. It does respond to using the mouse wheel of keyboard arrows however.

    https://user-images.githubusercontent.com/7450507/130807718-723b881d-1de7-4dcd-82d3-d95c4fa3848d.mp4

    Since it did work with previous early access of jfx (up to 17-ea-9, actually), I did manage to pinpoint that change responsible: https://github.com/openjdk/jfx/pull/454

    The above PR changes the type of listener used internally by the built-in bi-directional bindings, from ChangeListeners<T> to InvalidationListeners. This should be transparent to most if not all applications, but because Flowless relies on ReactFX, which interacts with bindings and events in a very intimate way, something was broken by that change.

    I managed to workaround the issue in the VirtualizedScrollPane by replacing the affect bi-directional bindings by a couple of mirrored ChangeListeners.

    I will submit a PR illustrating this workaround for your consideration.

    opened by fthevenet 8
  • Introduce negative checks, just before each access.

    Introduce negative checks, just before each access.

    Is it Possible To Itntoduce Negative Checks, As in some instances, I get Index Out Of Bounds Exception -1, with no cause, usually after being idle for a while,with a Huge List

    opened by newtingz 8
  • Smooth scrolling

    Smooth scrolling

    VirtualFlow calculates a reasonable jump size when using the mouse wheel or scroll bar increment/decrement buttons. This leads to reasonable scrolling behaviour but with large content (e.g. a many page PDF) the scroll amount can be quite large, like 20 pixels or so, and this leads to a jerky feeling when scrolling.

    Seeing as how ReactFX has the nice Val.animate() method it would probably be quite easy to fix this. I had a quick go at doing so without hacking Flowless itself but it seems the methods I'd need are all (package) private. Perhaps there's a simple trick to get this; I guess inserting a simple animated val with short duration between the desired scroll position and the actual position is sufficient.

    enhancement 
    opened by mikehearn 8
  • Add accessors for the index of the first and last visible cell.

    Add accessors for the index of the first and last visible cell.

    Save the index of the first and last visible cell at layout time, and make them available via accessors. This allows much more efficient retrieval of this information.

    opened by davmac314 7
  • VirtualizedScrollPane causes high CPU and GPU on idle with 125% screen scaling

    VirtualizedScrollPane causes high CPU and GPU on idle with 125% screen scaling

    When using a control embedded inside a VirtualizedScrollPane with the upcoming release 16 of JavaFX, then it is possible under specific circumstances that the method layoutChildren() becomes perpetually invoked, causing high CPU and GPU usage even when the application is idle.

    These conditions are:

    • Using openJFX 16 or higher at runtime
    • The effective screen scale at which the window is rendered is not a multiple of 100% (i.e. 125%, 150% or 175%, etc...).
    • The horizontal scrollbar is displayed.

    The following code sample illustrates the issue, when run under javafx 16, with for instance a 125% scale (you can force it with -Dglass.win.uiScale=1.25 or -Dglass.gtk.uiScale=1.25, on windows or linux, respectively):

    public class TextScroll extends Application {
        private final static String LONG_LINE_OF_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " +
                "Nulla viverra fringilla dictum. Integer faucibus laoreet nulla eget vehicula. " +
                "Vivamus et arcu eget metus interdum tincidunt ac sed libero. Phasellus vestibulum" ;
    
        @Override
        public void start(Stage stage) throws Exception {
            var textArea = new CodeArea();
            textArea.replaceText(LONG_LINE_OF_TEXT);
            Scene scene = new Scene(new VirtualizedScrollPane<>(textArea), 800, 600);
            stage.setScene(scene);
            stage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    
    

    The root cause for this, is that the VirtualizedScrollPane request a layout when the height of the horizontal scroll bar changes but in the course and the layout, the calculated value for this height changes, which in turns triggers a request layout, etc...

    This is due to the fact that a bug was fixed in JavaFX 16 (https://bugs.openjdk.java.net/browse/JDK-8211294) where the mechanism which snaps coordinates to actual pixels on screen with a non integer scale factor was broken; this is now fixed in javaFX, but Flowless remains unaware of the need for enforcing snapping, which causes some coordinates calculated in Flowless to be rounded differently that their equivalent in JavaFX; in this case this is what caused the scrollbar height to be different in two nested calls to layoutChildren, and lead to the constant layout.

    A solution is to use snapSize() method to ensure height and width are snapped (i.e. ceil'd) to pixels consistently with JavaFX.

    (NB: Ideally, we'd want to use snapSizeX() and snapSizeY() instead of the deprecated snapSize() so that we properly support non square screen ratio, but this is not available in JavaFX 8 that Flowless is built against.)

    opened by fthevenet 6
  • Make overriding VirtualizedScrollpane's layoutChildren() more developer-friendly

    Make overriding VirtualizedScrollpane's layoutChildren() more developer-friendly

    Coming from TomasMikula/RichTextFX#205 and relating to #9, provide more access to VirtualizedScrollPane's objects so that layoutChildren can be better overridden.

    There's a few ways this could be done:

    • Complete freedom: make the (currently private) content, hbar, and vbar protected. Then the developer can fully layout the children as they desire.
    • Restrict to content layout: since a developer will need to rewrite the scroll bar implementation each time he/she extends VirtualizedScrollPane (or more probably, screw up how the scroll bars get laid out), use a protected method to layout the content which developers can override:
    protected void layoutChildren() {
        // normal layout code...
    
        // instead of "content.resize(w, h)" have
        layoutContent(w, h);
    
       // rest of method's code.
    }
    
    protected void layoutContent(double width, double height) {
        content.resize(width, height);
    }
    
    opened by JordanMartinez 6
  • Error fetching URL: https://github.com/FXMisc/Flowless/#flowless/apidocs/

    Error fetching URL: https://github.com/FXMisc/Flowless/#flowless/apidocs/

    Running maven-javadoc-plugin with detectLinks set to true gives an error:

    error: Error fetching URL: https://github.com/FXMisc/Flowless/#flowless/apidocs/ (java.io.FileNotFoundException: https://github.com/FXMisc/Flowless/package-list)

    opened by dwalluck 0
  • Cell positioning

    Cell positioning

    Is there a way to position the cells manually? I'm trying to create a tree structure. In a tree structure the children of a node are positioned slightly to the right of the parent. How can I tell Flowless to position the cell like that? Also, the space from the right depends on the level of the node, so it should be dynamic

    opened by palexdev 0
  • Adding items too fast causes scroll when item list is empty

    Adding items too fast causes scroll when item list is empty

    Adding items too fast to item list of a VirtualFlow causes scroll if the item list is empty. Waiting few milliseconds after adding first item fixes the problem. Also calling visibleCells() method after adding first item fixes the problem but I don't know if its about time it takes or something else.

    Demo:

    public class Main extends Application {
        ObservableList<Integer> items = FXCollections.observableArrayList();
        VBox vbox = new VBox();
        Button add30Buttton = new Button("add 30");
        Button add1Button = new Button("add 1");
        Button removeAllButton = new Button("remove all");
    
        VirtualFlow<Integer, ?> virtualFlow = VirtualFlow.createVertical(items, i -> Cell.wrapNode(new Label(i.toString())));
        VirtualizedScrollPane<VirtualFlow<Integer, ?>> scrollPane = new VirtualizedScrollPane<>(virtualFlow);
    
        @Override
        public void start(Stage stage) {
            add30Buttton.setOnAction(event -> {
                items.add(0);
                // virtualFlow.visibleCells(); // uncommenting this fixes the problem
                for (int i = 1; i < 29; i++) { items.add(i); }
            });
            add1Button.setOnAction(event -> items.add(999));
            removeAllButton.setOnAction(event -> items.clear());
    
            VBox.setVgrow(scrollPane, Priority.ALWAYS);
            vbox.getChildren().addAll(add30Buttton, add1Button, removeAllButton, scrollPane);
    
            Scene scene = new Scene(vbox, 300, 400);
            stage.setScene(scene);
            stage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    opened by vonkez 1
  • Why happens to performance when Nodes are used for items in the VirtualFlow/createVertical?

    Why happens to performance when Nodes are used for items in the VirtualFlow/createVertical?

    In the VirtualFlow class, there is no constructor but static methods taking a list of items and a mapping function to convert the items into Cells.

    Are there any costs to performance if Node objects are passed in directly?

    question 
    opened by zcaudate 1
  • Trackpad scrolling with momentum doesn't work on OS X

    Trackpad scrolling with momentum doesn't work on OS X

    The vertical scroll lacks fluidity on OSX 10.11.6, while the horizontal scroll works as expected. I have this problem with the demos, with juliar, and with my apps that integrate RichTextFx See attached image for an illustration of the problem

    ezgif-4-a6a97b039b

    This issue its related to RichTextFX/issues/657 and RichTextFX/issues/265, and the solution proposed by @StrangeNoises works for me on OSX.

    The @StrangeNoises code is integrated in the last codebase at #57

    bug 
    opened by teodorov 2
Releases(v0.7.0)
Owner
null
Lib-Tile is a multi Maven project written in JavaFX and NetBeans IDE 8 and provides the functionalities to use and handle easily Tiles in your JavaFX application.

Lib-Tile Intention Lib-Tile is a multi Maven project written in JavaFX and NetBeans IDE and provides the functionalities to use and handle easily Tile

Peter Rogge 13 Apr 13, 2022
DataFX - is a JavaFX frameworks that provides additional features to create MVC based applications in JavaFX by providing routing and a context for CDI.

What you’ve stumbled upon here is a project that intends to make retrieving, massaging, populating, viewing, and editing data in JavaFX UI controls ea

Guigarage 110 Dec 29, 2022
Collection of Binding helpers for JavaFX(8)

Advanced-Bindings for JavaFX (8) advanced-bindings is a collection of useful helpers and custom binding implementations to simplify the development of

Manuel Mauky 63 Nov 19, 2022
Docking framework for JavaFX platform

Docking framework for JavaFX platform AnchorFX is a gratis and open source library for JavaFX to create graphical interfaces with docking features Anc

Alessio Vinerbi 197 Oct 15, 2022
A library of +70 ready-to-use animations for JavaFX

AnimateFX A library of ready-to-use animations for JavaFX Features: Custom animations Custom interpolators Play/Stop animation Play an animation after

Loïc Sculier 366 Jan 5, 2023
BootstrapFX: Bootstrap for JavaFX

BootstrapFX BootstrapFX is a partial port of Twitter Bootstrap for JavaFX. It mainly provides a CSS stylesheet that closely resembles the original whi

Kordamp 810 Dec 28, 2022
A Java framework for creating sophisticated calendar views (JavaFX 8, 9, 10, and 11)

CalendarFX A Java framework for creating sophisticated calendar views based on JavaFX. A detailed developer manual can be found online: CalendarFX 8 D

DLSC Software & Consulting GmbH 660 Jan 6, 2023
Allow runtime modification of JavaFX CSS

cssfx ⚠ WARNING ⚠ In version 11.3.0 we have relocated & refactored the project. maven groupId has been changed to fr.brouillard.oss java module name h

Matthieu Brouillard 134 Jan 2, 2023
A JavaFX UI framework to create fully customized undecorated windows

CustomStage A JavaFX undecorated stage which can fully be customized Donations If this project is helpful to you and love my work and feel like showin

Oshan Mendis 186 Jan 6, 2023
MDI components for JavaFX

DesktopPaneFX DesktopPaneFX is a JavaFX version of Swing’s JDesktopPane which can be used as a container for individual "child" similar to JInternalFr

Kordamp 58 Sep 23, 2022
A framework for easily creating forms for a JavaFX UI.

FormsFX Forms for business application made easy. Creating forms in Java has never been this easy! Maven To use this framework as part of your Maven b

DLSC Software & Consulting GmbH 534 Dec 30, 2022
:icecream: iOS frosty/translucent effect to JavaFX

FroXty is JavaFX library which replicates the famous iOS translucent effect with ease. Set-up FroXty can be imported into your project either by downl

Giorgio Garofalo 33 Dec 11, 2022
💠 Undecorated JavaFX Scene with implemented move, resize, minimise, maximise, close and Windows Aero Snap controls.

Support me joining PI Network app with invitation code AlexKent FX-BorderlessScene ( Library ) ?? Undecorated JavaFX Scene with implemented move, resi

Alexander Kentros 125 Jan 4, 2023
Dynamic JavaFX form generation

FXForm 2 Stop coding forms: FXForm 2 can do it for you! About FXForm2 is a library providing automatic JavaFX form generation. How does it work? Write

dooApp 209 Jan 9, 2023
A JavaFX library that allows Java2D code (Graphics2D) to be used to draw to a Canvas node.

FXGraphics2D Version 2.1, 3 October 2020. Overview FXGraphics2D is a free implementation of Java's Graphics2D API that targets the JavaFX Canvas. It m

David Gilbert 184 Dec 31, 2022
Auto updating launcher for JavaFX Applications

FXLauncher Auto updating launcher for JavaFX Applications. Combined with JavaFX native packaging, you get a native installer with automatic app update

Edvin Syse 694 Dec 27, 2022
Controls for adding Parallax effects for Java (JavaFX)

FXParallax Parallax framework for Java (JavaFX). This framework adds controls to add Parallax effects to JavaFX application, this effect can add a sen

Pedro Duque Vieira 36 Sep 30, 2022
Ribbon control for Java, created in JavaFX

FXRibbon Ribbon control for Java, using JavaFX framework, based on Microsoft Ribbon. If you want to support the development of this library consider a

Pedro Duque Vieira 224 Dec 27, 2022
A library for JavaFX that gives you the ability to show progress on the Windows taskbar.

A clean and easy way to implement this amazing native Windows taskbar-progressbar functionality in javaFX Background Since Windows 7 there is a taskba

Daniel Gyoerffy 77 Nov 28, 2022