Search code examples
javaswinguser-interfacejfreechart

How to insert a JFreeChart chart in a panel on a separate GUI?


I want to put a chart inside a specific panel in a GUI using JFreeChart. I have 2 java files (one with the GUI, and another that creates the graph) and would like , if possible, to keep it this way.

In the main GUI I have a panel called panelGraph:

    JPanel panelGraph = new JPanel();
    panelGraph.setBounds(220, 64, 329, 250);
    panelMain.add(panelGraph); //it is inside the main panel
    panelGraph.setLayout(null);

And I also have a button that triggers the appearance of the graph:

    Button btnGetGraph = new JButton("Draw Graph");
    btnGetGraph.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {

            XYLineChart_AWT.runGraph("Cenas", "Titulo", "XLABEL", "YLABEL", panelGraph);

        }
    });
    btnGetGraph.setFont(new Font("Tahoma", Font.BOLD, 13));
    btnGetGraph.setBounds(323, 327, 128, 34);
    panelMain.add(btnGetGraph);

And as follows, is the java file that creates the graph:

  public class XYLineChart_AWT extends JFrame {
  public XYLineChart_AWT( String applicationTitle, String chartTitle, String xLabel, String yLabel, JPanel panel) {

  JFreeChart xylineChart = ChartFactory.createXYLineChart(
     chartTitle ,
     xLabel ,
     yLabel ,
     createDataset() ,
     PlotOrientation.VERTICAL ,
     true , false , false);

  ChartPanel chartPanel = new ChartPanel( xylineChart );
  chartPanel.setPreferredSize( panel.getSize() );


  final XYPlot plot = xylineChart.getXYPlot( );
  plot.setBackgroundPaint(new Color(240, 240, 240));
  XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true,false);
  renderer.setSeriesPaint( 0 , Color.BLACK );
  renderer.setSeriesStroke( 0 , new BasicStroke( 4.0f ) );
  plot.setRenderer( renderer );
  setContentPane(chartPanel);
  panel.add(chartPanel);
  }

private XYDataset createDataset( ){

  final XYSeries seno = new XYSeries ("Sin");
  for(double i=0;i<=1440;i++){
      double temp=Math.sin(i*((2*Math.PI)/640) + Math.PI) + 1;
      seno.add(i/60, temp);
  }


  final XYSeriesCollection dataset = new XYSeriesCollection( );          
  dataset.addSeries(seno);
  return dataset;
}

public static void runGraph(String appTitle, String chartTitle, String xLabel, String yLabel, JPanel panel) {
  XYLineChart_AWT chart = new XYLineChart_AWT(appTitle, chartTitle, xLabel, yLabel, panel);

  chart.pack();
  chart.setVisible(true);
  panel.setVisible(true);

 }
}

This creates the graph and puts it into the specified panel (that I send through the method runGraph()). However, it creates a 2nd JFrame ( I know i made chart.setVisible(true) and I can just put it to false) that I don't want to be created outside of the panel I send.

Is there any way to implement this that does not create that extra jFrame?

P.S.: Another question: the setBackgroundPaint() method changes the back of where the graph is shown. However the parts where the title and legend are don't change. How can I change those parts?

Thank you for your help,

Nhekas


Solution

  • Instead of using the XYLineChartAWT constructor to instantiate a ChartPanel, make runGraph() a factory method that returns a JFreeChart for use in your main GUI's ChartPanel. Use the chart panel method setChart(), which will update your panel automatically. To change the chart panel's default size, override getPreferredSize() as shown here.

    image

    import java.awt.BasicStroke;
    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.EventQueue;
    import java.awt.event.ActionEvent;
    import javax.swing.AbstractAction;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import org.jfree.chart.ChartFactory;
    import org.jfree.chart.ChartPanel;
    import org.jfree.chart.JFreeChart;
    import org.jfree.chart.plot.PlotOrientation;
    import org.jfree.chart.plot.XYPlot;
    import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
    import org.jfree.data.xy.XYDataset;
    import org.jfree.data.xy.XYSeries;
    import org.jfree.data.xy.XYSeriesCollection;
    
    /**
     * @see https://stackoverflow.com/a/36757609/230513
     */
    public class Test {
    
        private void display() {
            JFrame f = new JFrame("Test");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            final ChartPanel chartPanel = new ChartPanel(null);
            f.add(chartPanel);
            f.add(new JButton(new AbstractAction("Draw Graph") {
                @Override
                public void actionPerformed(ActionEvent e) {
                    chartPanel.setChart(
                        new XYLineChartAWT().runGraph("Title", "X", "Y"));
                }
            }), BorderLayout.SOUTH);
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }
    
        public static void main(String[] args) {
            EventQueue.invokeLater(new Test()::display);
        }
    }
    
    public class XYLineChartAWT {
    
        public JFreeChart runGraph(String chartTitle, String xLabel, String yLabel) {
            JFreeChart xylineChart = ChartFactory.createXYLineChart(
                chartTitle,
                xLabel,
                yLabel,
                createDataset(),
                PlotOrientation.VERTICAL,
                true, false, false);
            final XYPlot plot = xylineChart.getXYPlot();
            plot.setBackgroundPaint(new Color(240, 240, 240));
            XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true, false);
            renderer.setSeriesPaint(0, Color.BLACK);
            renderer.setSeriesStroke(0, new BasicStroke(4.0f));
            plot.setRenderer(renderer);
            return xylineChart;
        }
    
        private XYDataset createDataset() {
            final XYSeries seno = new XYSeries("Sin");
            for (double i = 0; i <= 1440; i++) {
                double temp = Math.sin(i * ((2 * Math.PI) / 640) + Math.PI) + 1;
                seno.add(i / 60, temp);
            }
            final XYSeriesCollection dataset = new XYSeriesCollection();
            dataset.addSeries(seno);
            return dataset;
        }
    }