-1

I'm trying to create a line chart using this tutorial example: https://docs.oracle.com/javase/8/javafx/user-interface-tutorial/line-chart.htm, which I've reworked slightly, but I'm not using the stage provided by the start method of the Application class. Rather, I'm trying to create multiple stages of my own. However, when I attempt to do so I just get presented with a blank white window which stops responding. This is the code:

public Chart() {    
    Stage stage = new Stage();
    stage.setTitle("Test");

    XYChart.Series series = new XYChart.Series();
    series.setName("My portfolio");
    series.getData().add(new XYChart.Data(1, 23));
    series.getData().add(new XYChart.Data(2, 14));
    series.getData().add(new XYChart.Data(3, 15));
    series.getData().add(new XYChart.Data(4, 24));
    series.getData().add(new XYChart.Data(5, 34));
    series.getData().add(new XYChart.Data(6, 36));
    series.getData().add(new XYChart.Data(7, 22));
    series.getData().add(new XYChart.Data(8, 45));
    series.getData().add(new XYChart.Data(9, 43));
    series.getData().add(new XYChart.Data(10, 17));
    series.getData().add(new XYChart.Data(11, 29));
    series.getData().add(new XYChart.Data(12, 25));

    NumberAxis xAxis = new NumberAxis();
    NumberAxis yAxis = new NumberAxis();
    xAxis.setLabel("Time");
    yAxis.setLabel("Value");

    LineChart<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis);
    lineChart.setTitle("Test");
    lineChart.getData().add(series);

    StackPane root = new StackPane();
    root.getChildren().add(lineChart);

    Scene scene = new Scene(root, 800, 600);
    stage.setScene(scene);
    stage.show();
}

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

    @Override
    public void start(Stage stage) {
        run();
    }

    private void run() {
        Chart c1 = new Chart();

        while (true) {
            // Do something and update the charts.
        }
    }
}

I know that this isn't best practice of showing a stage, but I'm simply trying to get to grips with JavaFX. Can anyone see the problem?

alwaysboots
  • 141
  • 1
  • 2
  • 12
  • There's nothing particularly wrong with using a stage this way (though just as a matter of style I don't think I'd create and show a stage in a constructor). Indeed, there's nothing at all wrong with your code: if it's not working you are doing something wrong in the code that is invoking this. It perhaps sounds like you are blocking the FX Application Thread somehow. Can you create an [MCVE](http://stackoverflow.com/help/mcve) and edit your question to include it? – James_D Aug 30 '15 at 02:32
  • @James_D I've updated the question. – alwaysboots Aug 30 '15 at 11:05
  • I ran the code you posted and it worked just fine: I see the line chart as expected. Did you run this *exactly as you posted it* (or, at least, with the minimal change to make it actually executable) and see a blank window? – James_D Aug 30 '15 at 13:13
  • 1
    Try `private void run() { Stage stage = new Stage(); stage.setScene( new Scene( new VBox( new Button( "test" ) ) ) ); stage.show(); }`. Can you see the button? – Uluk Biy Aug 30 '15 at 13:16
  • So it seems that the problem is that I was debugging, and not escaping the `start` method. So in order for JavaFX to render the stage, the `start` method must have returned... This is bad news for me since I put my main application logic (which includes the creation of the charts) in the `run()` method. – alwaysboots Aug 30 '15 at 15:29
  • So can someone confirm this then: JavaFX expects me to have my `main` method contain only a call to `launch`, and to override the `Application.start` method in my program. It is from the `start` method that my application must therefore execute its main logic, but in order to render anything my program must first complete executing the `start` method? That's like asking a program to finish executing its `main` method before anything can be done... Is this truly how JavaFX works or have I completely misunderstood it? I have updated the `run()` method to more similarly replicate my situation. – alwaysboots Aug 30 '15 at 15:39
  • First, please don't post code pertaining to demonstrate a problem when you haven't actually run it and verified it shows the problem at hand. It is a waste of everyone's time. As stated in the [documentation](https://docs.oracle.com/javase/8/javafx/api/javafx/application/Application.html#start-javafx.stage.Stage-) the `start` method is executed on the FX application thread, so you *must not* block it. If you have a long-running process, create a background thread to execute it in. – James_D Aug 30 '15 at 16:14
  • @James_D Thank you for your response. The code that I posted was correct, but since I was debugging it with a break point after the `Chart c1 = new Chart();` line, I didn't see that it worked. I think it's quite normal not to post hundreds of lines of code which you'd think is irrelevant to the problem at hand. I'd argue that it wasn't a waste of time since @Uluk Biy's question enabled me to establish what the problem was. – alwaysboots Aug 30 '15 at 16:35
  • No-one ever suggested you post hundreds of lines of code: I just asked you for an MCVE, which you never provided (just some incomplete chunks of code with compilation errors that prospective answerers of your question are apparently supposed to fix themselves). I'm not particularly inclined to help people when I have to beg for the relevant information. – James_D Aug 30 '15 at 18:08
  • @James_D I don't understand why you're so upset about it. No one forces you to reply, you do so out of choice. – alwaysboots Aug 30 '15 at 19:21

1 Answers1

1

As I can't comment, I will try to help this way.

If I get you right: You want to do some (heavy) work and update UI to reflect what is going on.

To do this, you should make another (worker) thread to call UI (Application) thread whenever it needs to be updated. According to this, you should move long running tasks away from JavaFX Application thread (the one that is running our start(Stage stage) method)

The JavaFX scene graph, which represents the graphical user interface of a JavaFX application, is not thread-safe and can only be accessed and modified from the UI thread also known as the JavaFX Application thread. Implementing long-running tasks on the JavaFX Application thread inevitably makes an application UI unresponsive. A best practice is to do these tasks on one or more background threads and let the JavaFX Application thread process user events.

Here is what Application class does and how it starts.

The Java launcher loads and initializes the specified Application class on the JavaFX Application Thread. If there is no main method in the Application class, or if the main method calls Application.launch(), then an instance of the Application is then constructed on the JavaFX Application Thread.

Your current code should be easy to modify to make it possible. Here is some sample how to update UI from worker thread.

Community
  • 1
  • 1
Manik
  • 96
  • 7