-
Bug
-
Resolution: Unresolved
-
P4
-
jfx11, 8u261, jfx15
-
x86_64
-
windows_7
ADDITIONAL SYSTEM INFORMATION :
I have tested the samples with Java 8 and Java 10.
A DESCRIPTION OF THE PROBLEM :
When the scene contains a lot of nodes, changing the scene graph takes a long time.
The sample code in JavaFX is about 20 times slower than the equivalent sample in Swing.
Everything is slow in JavaFX : scrolling, changing the widow size, changing the spilt pane size...
The memory footprint is also huge compared to Swing.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the two sample applications and click several times on the "Show / Hide properties form" toggle button. The time to open or close the properties form is displayed next to the button.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expect JavaFX to be at least as fast as Swing.
ACTUAL -
The JavaFX sample shows a time of about 3000 to 4000 ms.
The Swing sample shows a time less than 200 ms.
JavaFX in this use case is 20 times slower than Swing which is abnormal.
---------- BEGIN SOURCE ----------
This is JavaFX sample :
--------------------------------------------------------------------------------------------------------------
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.SplitPane;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToolBar;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* Application demonstrating JavaFX slowness to toggle between a main form and a split pane containing the main form and a properties form.
* The time can be compared to the equivalent {@link FastSwingDemo Swing demo}.
*/
public final class SlowJavaFXDemo extends Application {
private static final int COMPLEXITY = 50;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
stage.setScene(createScene());
stage.setTitle("Slow JavaFX Demo");
stage.setWidth(800);
stage.setHeight(600);
stage.setOnCloseRequest(event -> Platform.exit());
stage.show();
}
private static Scene createScene() {
final VBox content = new VBox();
final ScrollPane mainForm = new ScrollPane(content);
final BorderPane mainPane = new BorderPane(mainForm);
final Label executionTime = new Label();
final ToggleButton togglePropertiesForm = new ToggleButton("Show / Hide properties form");
togglePropertiesForm.selectedProperty().addListener((observable, wasSelected, isSelected) -> {
final long start = System.currentTimeMillis();
if (isSelected) {
final SplitPane splitPane = new SplitPane(mainForm, new Label("Very simple properties form"));
mainPane.setCenter(splitPane);
executionTime.setText("Properties form opened in ");
} else {
mainPane.setCenter(mainForm);
executionTime.setText("Properties form closed in ");
}
Platform.runLater(() -> executionTime.setText(executionTime.getText() + (System.currentTimeMillis() - start) + " ms"));
});
final ToolBar toolBar = new ToolBar(togglePropertiesForm, executionTime);
content.getChildren().addAll(toolBar, createGridPane());
return new Scene(mainPane);
}
private static GridPane createGridPane() {
final VBox innerBox = new VBox();
innerBox.getChildren().addAll(createOuterBoxes());
final GridPane gridPane = new GridPane();
gridPane.setHgap(5);
gridPane.add(innerBox, 0, 0);
gridPane.add(new VBox(), 0, 1);
return gridPane;
}
private static List<OuterBox> createOuterBoxes() {
final List<OuterBox> outerBoxes = new ArrayList<>();
for (int i = 0; i < COMPLEXITY; i++) {
final OuterBox box = new OuterBox();
outerBoxes.add(box);
for (int j = 0; j < COMPLEXITY; j++) {
box.addInnerBox(new InnerBox());
}
}
return outerBoxes;
}
private static class OuterBox extends VBox {
private OuterBox() {
final Label label1 = new Label("Label1");
final Label label2 = new Label("Label2");
this.getChildren().addAll(label1, label2);
}
private void addInnerBox(InnerBox box) {
getChildren().add(box);
}
}
private static class InnerBox extends HBox {
private InnerBox() {
for (int i = 0; i < 10; i++) {
final Label label = new Label("Label[" + i + "]");
label.setTooltip(new Tooltip("Tooltip"));
this.getChildren().add(label);
}
}
}
}
--------------------------------------------------------------------------------------------------------------
This is Swing sample :
--------------------------------------------------------------------------------------------------------------
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
/**
* Application demonstrating Swing fastness to toggle between a main form and a split pane containing the main form and a properties form.
* The time can be compared to the equivalent {@link SlowJavaFXDemo JavaFX demo}.
*/
public final class FastSwingDemo {
private static final int COMPLEXITY = 50;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
final JFrame frame = new JFrame("Fast Swing Demo");
buildRoot(frame.getContentPane());
frame.setSize(800, 600);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
private static void buildRoot(final Container borderPane) {
final Box content = new Box(BoxLayout.Y_AXIS);
final JScrollPane mainForm = new JScrollPane(content);
final JPanel mainPane = new JPanel(new BorderLayout());
mainPane.add(mainForm, BorderLayout.CENTER);
final JLabel executionTime = new JLabel();
final JToggleButton togglePropertiesForm = new JToggleButton("Show / Hide properties form");
togglePropertiesForm.addActionListener(actionEvent -> {
final long start = System.currentTimeMillis();
if (togglePropertiesForm.isSelected()) {
final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, mainForm, new JLabel("Very simple properties form"));
mainPane.removeAll();
mainPane.add(splitPane, BorderLayout.CENTER);
mainPane.revalidate();
executionTime.setText("Properties form opened in ");
} else {
mainPane.removeAll();
mainPane.add(mainForm, BorderLayout.CENTER);
mainPane.revalidate();
executionTime.setText("Properties form closed in ");
}
SwingUtilities.invokeLater(() -> executionTime.setText(executionTime.getText() + (System.currentTimeMillis() - start) + " ms"));
});
final JToolBar toolBar = new JToolBar();
toolBar.add(togglePropertiesForm);
toolBar.add(executionTime);
content.add(toolBar);
content.add(createGridPane());
borderPane.add(mainPane, BorderLayout.CENTER);
}
private static JPanel createGridPane() {
final Box innerBox = new Box(BoxLayout.Y_AXIS);
createOuterBoxes().forEach(innerBox::add);
innerBox.validate();
final GridLayout gridLayout = new GridLayout(0, 2);
gridLayout.setHgap(5);
final JPanel gridPane = new JPanel();
gridPane.add(innerBox);
gridPane.add(new Box(BoxLayout.Y_AXIS));
return gridPane;
}
private static List<OuterBox> createOuterBoxes() {
final List<OuterBox> outerBoxes = new ArrayList<>();
for (int i = 0; i < COMPLEXITY; i++) {
final OuterBox box = new OuterBox();
outerBoxes.add(box);
for (int j = 0; j < COMPLEXITY; j++) {
box.addInnerBox(new InnerBox());
}
}
return outerBoxes;
}
private static class OuterBox extends Box {
private OuterBox() {
super(BoxLayout.Y_AXIS);
final JLabel label1 = new JLabel("Label1");
final JLabel label2 = new JLabel("Label2");
this.add(label1);
this.add(label2);
}
private void addInnerBox(InnerBox box) {
this.add(box);
}
}
private static class InnerBox extends Box {
private InnerBox() {
super(BoxLayout.X_AXIS);
for (int i = 0; i < 10; i++) {
final JLabel label = new JLabel("Label[" + i + "]");
label.setToolTipText("Tooltip");
this.add(label);
}
}
}
}
--------------------------------------------------------------------------------------------------------------
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
No workaround found.
FREQUENCY : always
I have tested the samples with Java 8 and Java 10.
A DESCRIPTION OF THE PROBLEM :
When the scene contains a lot of nodes, changing the scene graph takes a long time.
The sample code in JavaFX is about 20 times slower than the equivalent sample in Swing.
Everything is slow in JavaFX : scrolling, changing the widow size, changing the spilt pane size...
The memory footprint is also huge compared to Swing.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run the two sample applications and click several times on the "Show / Hide properties form" toggle button. The time to open or close the properties form is displayed next to the button.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I expect JavaFX to be at least as fast as Swing.
ACTUAL -
The JavaFX sample shows a time of about 3000 to 4000 ms.
The Swing sample shows a time less than 200 ms.
JavaFX in this use case is 20 times slower than Swing which is abnormal.
---------- BEGIN SOURCE ----------
This is JavaFX sample :
--------------------------------------------------------------------------------------------------------------
import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.SplitPane;
import javafx.scene.control.ToggleButton;
import javafx.scene.control.ToolBar;
import javafx.scene.control.Tooltip;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
/**
* Application demonstrating JavaFX slowness to toggle between a main form and a split pane containing the main form and a properties form.
* The time can be compared to the equivalent {@link FastSwingDemo Swing demo}.
*/
public final class SlowJavaFXDemo extends Application {
private static final int COMPLEXITY = 50;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
stage.setScene(createScene());
stage.setTitle("Slow JavaFX Demo");
stage.setWidth(800);
stage.setHeight(600);
stage.setOnCloseRequest(event -> Platform.exit());
stage.show();
}
private static Scene createScene() {
final VBox content = new VBox();
final ScrollPane mainForm = new ScrollPane(content);
final BorderPane mainPane = new BorderPane(mainForm);
final Label executionTime = new Label();
final ToggleButton togglePropertiesForm = new ToggleButton("Show / Hide properties form");
togglePropertiesForm.selectedProperty().addListener((observable, wasSelected, isSelected) -> {
final long start = System.currentTimeMillis();
if (isSelected) {
final SplitPane splitPane = new SplitPane(mainForm, new Label("Very simple properties form"));
mainPane.setCenter(splitPane);
executionTime.setText("Properties form opened in ");
} else {
mainPane.setCenter(mainForm);
executionTime.setText("Properties form closed in ");
}
Platform.runLater(() -> executionTime.setText(executionTime.getText() + (System.currentTimeMillis() - start) + " ms"));
});
final ToolBar toolBar = new ToolBar(togglePropertiesForm, executionTime);
content.getChildren().addAll(toolBar, createGridPane());
return new Scene(mainPane);
}
private static GridPane createGridPane() {
final VBox innerBox = new VBox();
innerBox.getChildren().addAll(createOuterBoxes());
final GridPane gridPane = new GridPane();
gridPane.setHgap(5);
gridPane.add(innerBox, 0, 0);
gridPane.add(new VBox(), 0, 1);
return gridPane;
}
private static List<OuterBox> createOuterBoxes() {
final List<OuterBox> outerBoxes = new ArrayList<>();
for (int i = 0; i < COMPLEXITY; i++) {
final OuterBox box = new OuterBox();
outerBoxes.add(box);
for (int j = 0; j < COMPLEXITY; j++) {
box.addInnerBox(new InnerBox());
}
}
return outerBoxes;
}
private static class OuterBox extends VBox {
private OuterBox() {
final Label label1 = new Label("Label1");
final Label label2 = new Label("Label2");
this.getChildren().addAll(label1, label2);
}
private void addInnerBox(InnerBox box) {
getChildren().add(box);
}
}
private static class InnerBox extends HBox {
private InnerBox() {
for (int i = 0; i < 10; i++) {
final Label label = new Label("Label[" + i + "]");
label.setTooltip(new Tooltip("Tooltip"));
this.getChildren().add(label);
}
}
}
}
--------------------------------------------------------------------------------------------------------------
This is Swing sample :
--------------------------------------------------------------------------------------------------------------
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
/**
* Application demonstrating Swing fastness to toggle between a main form and a split pane containing the main form and a properties form.
* The time can be compared to the equivalent {@link SlowJavaFXDemo JavaFX demo}.
*/
public final class FastSwingDemo {
private static final int COMPLEXITY = 50;
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
final JFrame frame = new JFrame("Fast Swing Demo");
buildRoot(frame.getContentPane());
frame.setSize(800, 600);
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setVisible(true);
});
}
private static void buildRoot(final Container borderPane) {
final Box content = new Box(BoxLayout.Y_AXIS);
final JScrollPane mainForm = new JScrollPane(content);
final JPanel mainPane = new JPanel(new BorderLayout());
mainPane.add(mainForm, BorderLayout.CENTER);
final JLabel executionTime = new JLabel();
final JToggleButton togglePropertiesForm = new JToggleButton("Show / Hide properties form");
togglePropertiesForm.addActionListener(actionEvent -> {
final long start = System.currentTimeMillis();
if (togglePropertiesForm.isSelected()) {
final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, mainForm, new JLabel("Very simple properties form"));
mainPane.removeAll();
mainPane.add(splitPane, BorderLayout.CENTER);
mainPane.revalidate();
executionTime.setText("Properties form opened in ");
} else {
mainPane.removeAll();
mainPane.add(mainForm, BorderLayout.CENTER);
mainPane.revalidate();
executionTime.setText("Properties form closed in ");
}
SwingUtilities.invokeLater(() -> executionTime.setText(executionTime.getText() + (System.currentTimeMillis() - start) + " ms"));
});
final JToolBar toolBar = new JToolBar();
toolBar.add(togglePropertiesForm);
toolBar.add(executionTime);
content.add(toolBar);
content.add(createGridPane());
borderPane.add(mainPane, BorderLayout.CENTER);
}
private static JPanel createGridPane() {
final Box innerBox = new Box(BoxLayout.Y_AXIS);
createOuterBoxes().forEach(innerBox::add);
innerBox.validate();
final GridLayout gridLayout = new GridLayout(0, 2);
gridLayout.setHgap(5);
final JPanel gridPane = new JPanel();
gridPane.add(innerBox);
gridPane.add(new Box(BoxLayout.Y_AXIS));
return gridPane;
}
private static List<OuterBox> createOuterBoxes() {
final List<OuterBox> outerBoxes = new ArrayList<>();
for (int i = 0; i < COMPLEXITY; i++) {
final OuterBox box = new OuterBox();
outerBoxes.add(box);
for (int j = 0; j < COMPLEXITY; j++) {
box.addInnerBox(new InnerBox());
}
}
return outerBoxes;
}
private static class OuterBox extends Box {
private OuterBox() {
super(BoxLayout.Y_AXIS);
final JLabel label1 = new JLabel("Label1");
final JLabel label2 = new JLabel("Label2");
this.add(label1);
this.add(label2);
}
private void addInnerBox(InnerBox box) {
this.add(box);
}
}
private static class InnerBox extends Box {
private InnerBox() {
super(BoxLayout.X_AXIS);
for (int i = 0; i < 10; i++) {
final JLabel label = new JLabel("Label[" + i + "]");
label.setToolTipText("Tooltip");
this.add(label);
}
}
}
}
--------------------------------------------------------------------------------------------------------------
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
No workaround found.
FREQUENCY : always