Skip to content

Instantly share code, notes, and snippets.

@Jugen
Forked from TomasMikula/FlowlessBenchmark.java
Last active August 30, 2023 02:52
Show Gist options
  • Save Jugen/2d392fd72ebec9db3c5d2aca1f8f5eb5 to your computer and use it in GitHub Desktop.
Save Jugen/2d392fd72ebec9db3c5d2aca1f8f5eb5 to your computer and use it in GitHub Desktop.
ListView vs. Flowless
import javafx.application.Application;
import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Region;
import javafx.stage.Stage;
import org.fxmisc.flowless.Cell;
import org.fxmisc.flowless.VirtualFlow;
public class FlowlessBenchmark extends Application {
public static void main(String[] args) {
launch(args);
}
private int counter = 0;
private int layoutCounter = 0;
private BorderPane bp = new BorderPane();
@Override
public void start(Stage primaryStage) {
Scene scene = new Scene(bp, 200, 400);
primaryStage.setScene(scene);
primaryStage.show();
System.out.println("\nNumber of LISTVIEW cell creations/layouts when:");
ListView<String> lv = new ListView<>( getItems() );
lv.setCellFactory( this::cellFactory );
lv.setFixedCellSize( 16.0 );
benchmark( lv, lv.getItems() );
runLater( 1000, () -> {
ObservableList<String> flowItems = getItems();
System.out.println("\nNumber of VIRTUALFLOW cell creations/layouts when:");
VirtualFlow<String, ?> flow = VirtualFlow.createVertical( flowItems, color -> reg(color) );
benchmark( flow, flowItems );
});
}
private ObservableList<String> getItems()
{
ObservableList<String> items = FXCollections.observableArrayList();
for(int i = 0; i < 20; ++i) {
items.addAll("red", "green", "blue", "purple");
}
return items;
}
private void benchmark( Parent listCtrl, ObservableList<String> items )
{
bp.setCenter( listCtrl );
runLater( 125, () -> {
// Reset counters
counter = 0; layoutCounter = 0;
// Updating an item in the viewport
items.set(10, "yellow");
});
runLater( 250, () -> {
// Print counters of previous operation
System.out.println(" - updating an item in the viewport: " + counter + "/" + layoutCounter);
// Reset counters
counter = 0; layoutCounter = 0;
// Updating an item outside the viewport
items.set(30, "yellow");
});
runLater( 375, () -> {
// Print counters of previous operation
System.out.println(" - updating an item outside the viewport: " + counter + "/" + layoutCounter);
// Reset counters
counter = 0; layoutCounter = 0;
// Deleting an item in the middle of the viewport
items.remove(12);
});
runLater( 500, () -> {
// Print counters of previous operation
System.out.println(" - deleting an item in the middle of the viewport: " + counter + "/" + layoutCounter);
// Reset counters
counter = 0; layoutCounter = 0;
// Adding an item in the middle of the viewport
items.add(12, "yellow");
});
runLater( 725, () -> {
// Print counters of previous operation
System.out.println(" - adding an item in the middle of the viewport: " + counter + "/" + layoutCounter);
// Reset counters
counter = 0; layoutCounter = 0;
// Scrolling 5 items down
if ( listCtrl instanceof ListView ) ((ListView<?>) listCtrl).scrollTo(5);
else ((VirtualFlow) listCtrl).showAsFirst( 5 );
});
runLater( 850, () -> {
// Print counters of previous operation
System.out.println(" - scrolling 5 items down: " + counter + "/" + layoutCounter);
// Reset counters
counter = 0; layoutCounter = 0;
// Scrolling 50 items down
if ( listCtrl instanceof ListView ) ((ListView<?>) listCtrl).scrollTo(55);
else ((VirtualFlow) listCtrl).showAsFirst( 55 );
});
runLater( 975, () -> {
// Print counters of previous operation
System.out.println(" - scrolling 50 items down: " + counter + "/" + layoutCounter);
});
}
private ListCell<String> cellFactory( ListView<String> lv )
{
return new ListCell<> () {
{ setStyle("-fx-padding: 0"); }
@Override
protected void updateItem(String color, boolean empty) {
super.updateItem(color, empty);
setText(null);
if(empty) {
setGraphic(null);
} else {
counter += 1;
Region reg = new Region() {
@Override
protected void layoutChildren() {
layoutCounter += 1;
super.layoutChildren();
}
};
reg.setPrefHeight(16);
reg.setStyle("-fx-background-color: " + color);
setGraphic(reg);
}
}
};
}
private Cell<String, Region> reg(String color) {
counter += 1;
Region reg = new Region() {
@Override
protected void layoutChildren() {
layoutCounter += 1;
super.layoutChildren();
}
};
reg.setPrefHeight(16);
reg.setStyle("-fx-background-color: " + color);
return Cell.wrapNode(reg);
}
/**
* Delays the execution of a Runnable on the FX thread by <code>time</code> milliseconds.
* @param time Milliseconds to wait before executing <code>runFX</code>.
* @param runFX Runnable to execute on the FX thread.
*/
public void runLater( final long time, final Runnable runFX )
{
new Thread( () ->
{
long t0 = System.currentTimeMillis();
long t1 = t0 + time;
while ( t0 < t1 ) try { Thread.sleep( t1 - t0 ); } catch ( Exception e ) {}
finally { t0 = System.currentTimeMillis(); }
Platform.runLater( runFX );
}, "DelayedFx Thread" ).start();
}
}

Tested with JDK 16.

ListViewBenchmark:

Number of LISTVIEW cell creations/layouts when:
 - updating an item in the viewport: 1/1
 - updating an item outside the viewport: 0/0
 - deleting an item in the middle of the viewport: 13/13
 - adding an item in the middle of the viewport: 13/13
 - scrolling 5 items down: 5/5
 - scrolling 50 items down: 25/25

FlowlessBenchmark:

Number of VIRTUALFLOW cell creations/layouts when:
 - updating an item in the viewport: 1/1
 - updating an item outside the viewport: 0/0
 - deleting an item in the middle of the viewport: 1/1
 - adding an item in the middle of the viewport: 1/1
 - scrolling 5 items down: 5/5
 - scrolling 50 items down: 25/25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment