Skip to content

Instantly share code, notes, and snippets.

@hendrikebbers
Last active December 22, 2015 14:28
Show Gist options
  • Save hendrikebbers/eb87093510b1f8e80415 to your computer and use it in GitHub Desktop.
Save hendrikebbers/eb87093510b1f8e80415 to your computer and use it in GitHub Desktop.
JavaFX Performance
import com.sun.javafx.scene.control.skin.ButtonSkin;
import com.sun.javafx.scene.control.skin.TextFieldSkin;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.*;
import javafx.embed.swing.SwingNode;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.*;
import javafx.scene.control.TextField;
import javafx.scene.layout.FlowPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javax.swing.*;
import java.awt.*;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class TextFieldPerformance extends Application {
public static void main(String[] args) {
launch(args);
}
private final FlowPane flow = new FlowPane();
private long startTime;
private BooleanProperty createInBackground = new SimpleBooleanProperty();
private IntegerProperty count = new SimpleIntegerProperty();
private BooleanProperty parallelCreation = new SimpleBooleanProperty();
private BooleanProperty initCss = new SimpleBooleanProperty();
private BooleanProperty initSkin = new SimpleBooleanProperty();
private ObjectProperty<NodeFactory> nodeFactory = new SimpleObjectProperty<>();
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("JavaFX Node Creation Benchmark");
Spinner<Integer> controlCountSpinner = new Spinner<>(100, 10000, 3000, 100);
controlCountSpinner.setTooltip(new Tooltip("Define the number of new nodes"));
count.bind(controlCountSpinner.valueProperty());
CheckBox threadCheckBox = new CheckBox("Create Nodes in Background Thread");
threadCheckBox.setTooltip(new Tooltip("If selected all nodes will be created in a background thread"));
createInBackground.bind(threadCheckBox.selectedProperty());
CheckBox parallelCheckBox = new CheckBox("parallel");
parallelCheckBox.setTooltip(new Tooltip("If selected all nodes will be created in multiple background thread (parallel stream)"));
parallelCheckBox.disableProperty().bind(threadCheckBox.selectedProperty().not());
parallelCreation.bind(parallelCheckBox.selectedProperty());
CheckBox initCssCheckBox = new CheckBox("Init CSS");
initCssCheckBox.setTooltip(new Tooltip("If selected the inital CSS will be called before adding the node"));
initCss.bind(initCssCheckBox.selectedProperty());
CheckBox initSkinCheckBox = new CheckBox("Init Skin");
initSkinCheckBox.setTooltip(new Tooltip("If selected the Skin will be created before adding the node"));
initSkin.bind(initSkinCheckBox.selectedProperty());
ChoiceBox<NodeFactory> nodeFactoryChoiceBox = new ChoiceBox<>();
parallelCheckBox.setTooltip(new Tooltip("Defines the node type that will be created"));
nodeFactoryChoiceBox.getItems().add(new TextFieldFactory());
nodeFactoryChoiceBox.getItems().add(new RectangleFactory());
nodeFactoryChoiceBox.getItems().add(new ButtonFactory());
nodeFactoryChoiceBox.getItems().add(new SwingTextFieldFactory());
nodeFactoryChoiceBox.getSelectionModel().select(0);
nodeFactory.bind(nodeFactoryChoiceBox.valueProperty());
Button createControlsButton = new Button("Create nodes");
createControlsButton.setOnAction(event -> {
printSomeLines();
startTime = System.currentTimeMillis();
if (!createInBackground.get()) {
createNodesAndAdd();
} else {
Executors.newSingleThreadExecutor().execute(() -> {
createNodesAndAdd();
});
}
});
Button removeControlsButton = new Button("Remove all nodes");
removeControlsButton.setOnAction(event -> {
printSomeLines();
startTime = System.currentTimeMillis();
measureRunTime("RemoveControls", () -> flow.getChildren().clear());
});
ToolBar toolBar = new ToolBar(nodeFactoryChoiceBox, controlCountSpinner, createControlsButton, removeControlsButton, initCssCheckBox, initSkinCheckBox, threadCheckBox, parallelCheckBox);
primaryStage.setScene(new Scene(new VBox(toolBar, flow), 1000, 1000));
primaryStage.show();
// stop Mesuring when elements are displayed
flow.needsLayoutProperty().addListener((observable, oldValue, newValue) -> {
if (startTime > 0 && !newValue) {
long duration = System.currentTimeMillis() - startTime;
System.out.println("Duration until controls are visible: " + duration);
System.out.println("Node Count: " + flow.getChildren().size());
startTime = -1;
}
});
}
private void createNodesAndAdd() {
List<Node> nodes = measureSupplyTime("NodeCreation", () -> {
IntStream stream = IntStream.range(0, count.get());
if (parallelCreation.get()) {
stream = stream.parallel();
}
return stream.mapToObj(i -> nodeFactory.get().create()).collect(Collectors.toList());
});
if (initSkin.get()) {
measureRunTime("InitSkin", () -> {
Stream<Node> stream = nodes.stream();
if (parallelCreation.get()) {
stream = stream.parallel();
}
stream.forEach(node -> nodeFactory.get().initSkin(node));
});
}
if (initCss.get()) {
measureRunTime("InitCSS", () -> {
Stream<Node> stream = nodes.stream();
if (parallelCreation.get()) {
stream = stream.parallel();
}
stream.forEach(node -> nodeFactory.get().initCSS(node));
});
}
if (!Platform.isFxApplicationThread()) {
Platform.runLater(() -> {
measureRunTime("AddToScene", () -> flow.getChildren().addAll(nodes));
});
} else {
measureRunTime("AddToScene", () -> flow.getChildren().addAll(nodes));
}
}
private <T> T measureSupplyTime(String name, Supplier<T> supplier) {
long currentTime = System.currentTimeMillis();
try {
return supplier.get();
} finally {
System.out.println("Duration for " + name + ": " + (System.currentTimeMillis() - currentTime));
}
}
private void measureRunTime(String name, Runnable runnable) {
measureSupplyTime(name, () -> {
runnable.run();
return null;
});
}
private void printSomeLines() {
System.out.println();
System.out.println("----------------------------------------------------");
}
private interface NodeFactory<T extends Node> {
T create();
default void initCSS(T node) {
node.applyCss();
}
void initSkin(T node);
}
private class TextFieldFactory implements NodeFactory<TextField> {
@Override
public TextField create() {
TextField textfield = new TextField();
textfield.setMinSize(10, 10);
textfield.setPrefSize(10, 10);
textfield.setMaxSize(10, 10);
return textfield;
}
@Override
public void initSkin(TextField node) {
node.setSkin(new TextFieldSkin(node));
}
@Override
public String toString() {
return "TextField";
}
}
private class SwingTextFieldFactory implements NodeFactory<SwingNode> {
@Override
public SwingNode create() {
JTextField textfield = new JTextField();
textfield.setMinimumSize(new Dimension(10, 10));
textfield.setPreferredSize(new Dimension(10, 10));
textfield.setMaximumSize(new Dimension(10, 10));
SwingNode swingNode = new SwingNode();
swingNode.setContent(textfield);
return swingNode;
}
@Override
public void initSkin(SwingNode node) {
}
@Override
public String toString() {
return "Swing TextField";
}
}
private class RectangleFactory implements NodeFactory<Rectangle> {
@Override
public Rectangle create() {
Rectangle rectangle = new Rectangle(10, 10);
rectangle.setFill(new Color(Math.random(), Math.random(), Math.random(), 1.0));
return rectangle;
}
@Override
public void initSkin(Rectangle node) {
}
@Override
public String toString() {
return "Rectangle";
}
}
private class ButtonFactory implements NodeFactory<Button> {
@Override
public Button create() {
Button button = new Button();
button.setMinSize(10, 10);
button.setPrefSize(10, 10);
button.setMaxSize(10, 10);
return button;
}
@Override
public void initSkin(Button node) {
node.setSkin(new ButtonSkin(node));
}
@Override
public String toString() {
return "Button";
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment