-1

I want to add a Pie chart inside a JPanel. I have gone through this and this. But it didnt helped me.

I tried this code in the debugger but it is not getting pass line X. Somehow setScene function is not working and pie chart is not visible in the panel.

Here's my code:

private void add_pie_chart(JPanel panel)
    {
    JFXPanel dataPanel = new JFXPanel();
    
    PieChart pieChart = new PieChart();

    ObservableList<PieChart.Data> data= FXCollections.observableArrayList(
            new PieChart.Data("test1", 25),
            new PieChart.Data("test 2", 25),
            new PieChart.Data("test 3", 25),
            new PieChart.Data("test 4", 25)
        );
    pieChart.setData(data);
    pieChart.setTitle("test");
    pieChart.setLabelsVisible(true);

    Group root = new Group();

    root.getChildren().add(pieChart);
    
    Scene scene = new Scene(root);
    dataPanel.setScene(scene);   //line X
    //not getting executing

    panel.add(dataPanel, BorderLayout.CENTER);
    panel.setVisible(true);

    }

I am not sure why this is happening. Plz help..

Any help is appreciated. Thanks in advance...

  • What do you mean "it's not getting past line X"? Is it throwing an exception? If so, post the complete stack trace. Execution cannot just stop for no reason. – James_D Jun 15 '21 at 18:11
  • Which thread is this method being called on? Part of this should be on the FX Application Thread, and part on the AWT event dispatch thread. – James_D Jun 15 '21 at 18:12
  • @James_D it was taking too long and nothing was happening I couldn't Step Over. I think it is somehow stuck in infinite loop or something.. – The Warrior Jun 15 '21 at 18:13
  • How could it be stuck in an infinite loop? This looks like a threading issue. Which thread is this being executed on? Create and post a [mre] – James_D Jun 15 '21 at 18:14
  • @James_D i referred to https://stackoverflow.com/questions/37742836/how-to-restrict-legend-size-and-making-it-scrollable-with-piechart-and-javafx-l. but instead of separate methods i combined them into one for generating pie chart. Pls tell me if something is wrong – The Warrior Jun 15 '21 at 18:20
  • That doesn't really answer anything I asked. – James_D Jun 15 '21 at 18:21
  • I didnt added this method in any FX Application Thread, or part on the AWT event dispatch threads. I just declared the method as shown above in code and used the PieChart function and created scenes manually to add the result in jpanel. Plz tell me if something is missing or wrong – The Warrior Jun 15 '21 at 18:23
  • So which thread is it being executed in? Surely if you're writing a UI application that uses both swing and JavaFX it must be either the FX Application Thread or the AWT event dispatch thread. I don't understand why you can't answer the question. – James_D Jun 15 '21 at 18:25
  • sorry it is AWT event dispatch thread. – The Warrior Jun 15 '21 at 18:27
  • OK, so that is probably the problem. The FX UI code must be executed on the FX Application Thread. Wrap the lines from `PieChart pieChart = new PieChart();` to `Scene scene = new Scene(root);`, inclusive, in `Platform.runLater(...)`. See the [documentation](https://openjfx.io/javadoc/16/javafx.swing/javafx/embed/swing/JFXPanel.html) – James_D Jun 15 '21 at 18:31
  • yes it worked thanks a lot. can u write it as an answer so that i can accept it as correct one – The Warrior Jun 15 '21 at 18:38

1 Answers1

4

Both Swing and JavaFX are single-threaded UI toolkits, and each has their own thread for rendering the UI and processing user events. Modifying Swing components and creating Swing windows (e.g. JFrames) must be done on the AWT event dispatch thread. Modifying JavaFX components must be done on the FX Application Thread.

Thus when you're working with both toolkits together, you have to be careful to delegate the appropriate actions to the appropriate threads. The Javadocs for JFXPanel have more details.

Here's a complete example which includes a slight re-working of your code and shows how to move the different parts of the code to the appropriate thread:

package org.jamesd.examples.piechartswing;

import java.awt.BorderLayout;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.PieChart;


public class App  {

    public void startUI() {
        JFrame frame = new JFrame();
        JFXPanel fxPanel = new JFXPanel();
        Platform.runLater(() -> createChart(fxPanel));
        
        JPanel panel = new JPanel();
        panel.setLayout(new BorderLayout());
        panel.add(fxPanel, BorderLayout.CENTER);
        
        frame.add(panel);
        frame.setSize(600,  600);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
    }
    
    private void createChart(JFXPanel dataPanel) {
        PieChart pieChart = new PieChart();

        ObservableList<PieChart.Data> data= FXCollections.observableArrayList(
                new PieChart.Data("test1", 25),
                new PieChart.Data("test 2", 25),
                new PieChart.Data("test 3", 25),
                new PieChart.Data("test 4", 25)
            );
        pieChart.setData(data);
        pieChart.setTitle("test");
        pieChart.setLabelsVisible(true);

        Group root = new Group();

        root.getChildren().add(pieChart);
        
        Scene scene = new Scene(root);
        dataPanel.setScene(scene); 
    }

    public static void main(String[] args) {
        App app = new App();
        SwingUtilities.invokeLater(app::startUI);
    }

}

For completenes, module-info.java:

module org.jamesd.examples.piechartswing {
    requires javafx.controls;
    requires java.desktop ;
    requires javafx.swing ;
    exports org.jamesd.examples.piechartswing;
}
James_D
  • 201,275
  • 16
  • 291
  • 322