Home > Software design >  Cannot load a thread that loads chart from JFreeChart until clicked
Cannot load a thread that loads chart from JFreeChart until clicked

Time:01-02

I think I did everything right. All I want is to load the thread that contains chart after the main thread that loads the components and window is finished. But it didn't work. Somehow I have to click jPanel1 (the panel that will load the chart) and the chart is loaded. Any help would be appreciated. What I've tried:

  • Changing the thread to SwingWorker
  • Changing the thread to invokeLater
public LaporanPenjualan() {
    initComponents();
    createFrame1();
}
    
private void createFrame1() {
    SwingWorker thread = new SwingWorker() {
        @Override
        protected Boolean doInBackground() throws Exception {
            JLabel loading = new JLabel("Loading, please wait",SwingConstants.CENTER);
            loading.setSize(500,500);
            loading.setAlignmentY(250);
            jPanel1.add(loading);
            final DefaultCategoryDataset dataset = new DefaultCategoryDataset();
            dataset.addValue(34.0, "Penjualan/produk", "Kue Enak");
            dataset.addValue(23.0, "Penjualan/produk", "Kue Enggak Enak");
            dataset.addValue(54.0, "Penjualan/produk", "Kue Sultan");
            final JFreeChart chart = ChartFactory.createBarChart(
                    "", 
                    "Produk",
                    "Penjualan",
                    dataset,
                    PlotOrientation.VERTICAL,
                    true,
                    true,
                    false
                );
            final ChartPanel chartPanel = new ChartPanel(chart);
            chartPanel.setSize(500,500);
            chartPanel.setPreferredSize(new Dimension(300, 300));
            jPanel1.removeAll();
            jPanel1.add(chartPanel);
            chartPanel.setVisible(true);
            return true;
        }
    };                 
    thread.execute();
}

CodePudding user response:

Swing is single threaded and not thread safe. This means that you shouldn't perform any long running or blocking operations with the context of the Event Dispatching Thread and you shouldn't modify the state of the UI or any state the UI relies on, from outside the context of the EDT.

So, having said that, you're createFrame1 might look something more like...

private void createFrame1() {
    JLabel loading = new JLabel("Loading, please wait", SwingConstants.CENTER);
    loading.setSize(500, 500);
    loading.setAlignmentY(250);
    jPanel1.add(loading);
    jPanel1.revalidate();
    jPanel1.repaint();

    SwingWorker<DefaultCategoryDataset, Void> thread;
    thread = new SwingWorker<>() {

        @Override
        protected DefaultCategoryDataset doInBackground() throws Exception {
            final DefaultCategoryDataset dataset = new DefaultCategoryDataset();
            dataset.addValue(34.0, "Penjualan/produk", "Kue Enak");
            dataset.addValue(23.0, "Penjualan/produk", "Kue Enggak Enak");
            dataset.addValue(54.0, "Penjualan/produk", "Kue Sultan");
            return dataset;
        }

        @Override
        protected void done() {
            try {
                DefaultCategoryDataset dataset = get();

                final JFreeChart chart = ChartFactory.createBarChart(
                        "",
                        "Produk",
                        "Penjualan",
                        dataset,
                        PlotOrientation.VERTICAL,
                        true,
                        true,
                        false
                );
                final ChartPanel chartPanel = new ChartPanel(chart);
                jPanel1.removeAll();
                jPanel1.add(chartPanel);
                chartPanel.setVisible(true);
            } catch (InterruptedException ex) {
                Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
            } catch (ExecutionException ex) {
                Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

    };
    thread.execute();
}

Alternatively, if loading the data takes time, you could publish each data point...

public class DataPoint {

    private double value;
    private Comparable rowKey;
    private Comparable columnKey;

    public DataPoint(double value, Comparable rowKey, Comparable columnKey) {
        this.value = value;
        this.rowKey = rowKey;
        this.columnKey = columnKey;
    }

    public double getValue() {
        return value;
    }

    public Comparable getRowKey() {
        return rowKey;
    }

    public Comparable getColumnKey() {
        return columnKey;
    }
}

private void createFrame1() {
    SwingWorker<Void, DataPoint> thread;
    DefaultCategoryDataset dataSet = new DefaultCategoryDataset();
    final JFreeChart chart = ChartFactory.createBarChart(
            "",
            "Produk",
            "Penjualan",
            dataSet,
            PlotOrientation.VERTICAL,
            true,
            true,
            false
    );
    final ChartPanel chartPanel = new ChartPanel(chart);
    jPanel1.add(chartPanel);

    thread = new SwingWorker<>() {

        @Override
        protected Void doInBackground() throws Exception {
            publish(new DataPoint(34.0, "Penjualan/produk", "Kue Enak"));
            publish(new DataPoint(23.0, "Penjualan/produk", "Kue Enggak Enak"));
            publish(new DataPoint(54.0, "Penjualan/produk", "Kue Sultan"));
        }

        @Override
        protected void process(List<DataPoint> chunks) {
            for (DataPoint dp : chunks) {
                dataSet.addValue(dp.getValue(), dp.getRowKey(), dp.getColumnKey());
            }
        }
    };
    thread.execute();
}

Runnable example...

enter image description here

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new BorderLayout());
            DefaultCategoryDataset dataSet = new DefaultCategoryDataset();
            final JFreeChart chart = ChartFactory.createBarChart(
                    "",
                    "Produk",
                    "Penjualan",
                    dataSet,
                    PlotOrientation.VERTICAL,
                    true,
                    true,
                    false
            );
            final ChartPanel chartPanel = new ChartPanel(chart);
            add(chartPanel);

            ChartWorker worker = new ChartWorker(dataSet);
            worker.execute();
        }
    }

    public class ChartWorker extends SwingWorker<Void, ChartWorker.DataPoint> {

        public class DataPoint {

            private double value;
            private Comparable rowKey;
            private Comparable columnKey;

            public DataPoint(double value, Comparable rowKey, Comparable columnKey) {
                this.value = value;
                this.rowKey = rowKey;
                this.columnKey = columnKey;
            }

            public double getValue() {
                return value;
            }

            public Comparable getRowKey() {
                return rowKey;
            }

            public Comparable getColumnKey() {
                return columnKey;
            }
        }

        private DefaultCategoryDataset dataSet;

        public ChartWorker(DefaultCategoryDataset dataSet) {
            this.dataSet = dataSet;
        }

        @Override
        protected Void doInBackground() throws Exception {
            // The sleeps here are just for demonstration, 
            // you don't need them
            Thread.sleep(1000);
            publish(new DataPoint(34.0, "Penjualan/produk", "Kue Enak"));
            Thread.sleep(1000);
            publish(new DataPoint(23.0, "Penjualan/produk", "Kue Enggak Enak"));
            Thread.sleep(1000);
            publish(new DataPoint(54.0, "Penjualan/produk", "Kue Sultan"));
            return null;
        }

        @Override
        protected void process(List<DataPoint> chunks) {
            for (DataPoint dp : chunks) {
                dataSet.addValue(dp.getValue(), dp.getRowKey(), dp.getColumnKey());
            }
        }
    }
}

And waiting for stuff to be done...

enter image description here

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingWorker;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        public TestPane() {
            setLayout(new BorderLayout());

            add(new JLabel("Loading stuff", JLabel.CENTER));

            ChartWorker worker = new ChartWorker();
            worker.addPropertyChangeListener(new PropertyChangeListener() {
                @Override
                public void propertyChange(PropertyChangeEvent evt) {
                    if ("state".equals(evt.getPropertyName())) {
                        if (worker.getState() == SwingWorker.StateValue.DONE) {
                            try {
                                DefaultCategoryDataset dataSet = worker.get();
                                setDataSet(dataSet);
                            } catch (InterruptedException ex) {
                                add(new JLabel("Loading fauked", JLabel.CENTER));
                                Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
                            } catch (ExecutionException ex) {
                                add(new JLabel("Loading fauked", JLabel.CENTER));
                                Logger.getLogger(Test.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                    }
                }
            });
            worker.execute();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 400);
        }

        protected void setDataSet(DefaultCategoryDataset dataSet) {
            final JFreeChart chart = ChartFactory.createBarChart(
                    "",
                    "Produk",
                    "Penjualan",
                    dataSet,
                    PlotOrientation.VERTICAL,
                    true,
                    true,
                    false
            );
            final ChartPanel chartPanel = new ChartPanel(chart);
            removeAll();
            add(chartPanel);
            revalidate();
            repaint();
        }

    }

    public class ChartWorker extends SwingWorker<DefaultCategoryDataset, Void> {

        public ChartWorker() {
        }

        @Override
        protected DefaultCategoryDataset doInBackground() throws Exception {
            DefaultCategoryDataset dataSet = new DefaultCategoryDataset();
            dataSet.addValue(34.0, "Penjualan/produk", "Kue Enak");
            dataSet.addValue(23.0, "Penjualan/produk", "Kue Enggak Enak");
            dataSet.addValue(54.0, "Penjualan/produk", "Kue Sultan");

            // Again, you don't need this
            Thread.sleep(5000);

            return dataSet;
        }
    }
}
  • Related