0

I want to create a JavaFx chart factory. In this (How to get an image file from a Javafx chart(linechart) without actually rendering it?) thread I posted a question about generating chart wihtout actually renderingon an FX application window. But now that I want to implement the solution multiple times I get the "Exception in thread "main" java.lang.IllegalStateException: Application launch must not be called more than once" exception.

I use two classes. StartChartsFx class has the main non FX thread, from here I create the data and trigger the chart creation process. ChartFactory class launches the FX thread and generates the png charts.

This is the StartChartsFx class:

public class StartChartsFx {

    public static void main(String[] args) {

        // It can be run just once ChartFactory chf=new ChartFactory();
        HashMap<Number, Number> xyData=new HashMap<>();
        xyData.put(1, 23);
        xyData.put(2, 14);
        xyData.put(3, 15);
        xyData.put(4, 24);
        xyData.put(5, 34);
        xyData.put(6, 36);
        xyData.put(7, 22);
        xyData.put(8, 45);
        xyData.put(9, 43);
        xyData.put(10, 17);
        xyData.put(11, 29);
        xyData.put(12, 25);

        ChartFactory chf=new ChartFactory();
        chf.execute(xyData);
        chf.execute(xyData);
                System.out.print("Done");
    }
}

This is the ChartFactory class:

public class ChartFactory extends Application {

    @Override
    public void stop() throws Exception {
        super.stop();
        Platform.exit();
    }

    private static HashMap<Number, Number> a;

    @Override
    public void start(Stage arg0) throws Exception {
        Platform.setImplicitExit(false);
        // defining the axes
        NumberAxis xAxis = new NumberAxis();
        NumberAxis yAxis = new NumberAxis();
        xAxis.setLabel("Number of Month");


        // creating the chart
        LineChart<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis);
        lineChart.setTitle("Stock Monitoring, 2010");
        lineChart.setAnimated(false);

        // defining a series
        XYChart.Series<Number, Number> series = new XYChart.Series<>();
        series.setName("My portfolio");

        // populating the series with data
        for(Map.Entry<Number, Number> entry:a.entrySet() )
            series.getData().add(new XYChart.Data<Number, Number>(entry.getKey(), entry.getValue()));       

        lineChart.getData().add(series);
        lineChart.setPrefSize(800, 240);

        Scene scene = new Scene(lineChart, 800, 240);
        System.out.println(System.getProperty("user.dir"));
        String element = getClass().getResource("chartStyles.css").toExternalForm();
        scene.getStylesheets().add(element);

        WritableImage wi = lineChart.snapshot(new SnapshotParameters(), new WritableImage(800, 240));
        File file = new File("CanvasImage.png");
        try {
            ImageIO.write(SwingFXUtils.fromFXImage(wi, null), "png", file);
        } catch (Exception s) {
        }

        CategoryAxis xAxis2 = new CategoryAxis();
        xAxis2.setLabel("Devices");
        NumberAxis yAxis2 = new NumberAxis();
        yAxis2.setLabel("Visits");
        BarChart<String, Number> barChart = new BarChart<>(xAxis2, yAxis2);
        barChart.setAnimated(false);

        XYChart.Series<String, Number> dataSeries1 = new XYChart.Series<>();
        dataSeries1.setName("2014");

        dataSeries1.getData().add(new XYChart.Data<String, Number>("Desktop", 178));
        dataSeries1.getData().add(new XYChart.Data<String, Number>("Phone", 65));
        dataSeries1.getData().add(new XYChart.Data<String, Number>("Tablet", 23));

        barChart.getData().add(dataSeries1);
        barChart.setPrefSize(640, 480);

        scene = new Scene(barChart, 640, 480);
        scene.getStylesheets().add(getClass().getResource("chartStyles.css").toExternalForm());
        wi = barChart.snapshot(new SnapshotParameters(), new WritableImage(640, 480));
        file = new File("Canvas2Image.png");
        try {
            ImageIO.write(SwingFXUtils.fromFXImage(wi, null), "png", file);
        } catch (Exception s) {
        }

        System.out.print("Done!");

        Platform.exit();

    }

    public void execute(HashMap<Number, Number> xyData) {
        a = xyData;
        launch();
    }

}

I'd like to generate charts with different datasets an undetermined amount of times, but it runs only once.

Novy
  • 1,436
  • 1
  • 14
  • 26
  • 1
    You should look at [this](https://stackoverflow.com/questions/20021328/call-javafx-application-twice). It seems that you can't execute javafx app twice. – Novy Jul 22 '19 at 21:31
  • Your data model should not be launching the JavaFX application. In any case, why would you want your application to run more than once? I suspect what you really need are multiple **Stages**, not application instances. Look into some beginner tutorials on JavaFX and the `Stage` and `Scene` classes. – Zephyr Jul 22 '19 at 23:45
  • *Never* write an empty `catch` block. At the very least, include `s.printStackTrace();`. You want to know if the image write failed, don’t you? – VGR Jul 23 '19 at 00:58
  • I just need the JavaFX charts functionality to generate charts (such as JFreeChart), but my main application is not a GUI application. The image generation it's OK. The problem is that I can run the code just once because of the javaFX exception – Edgar Canul Jul 23 '19 at 18:15

0 Answers0