【问题标题】:Cannot load a thread that loads chart from JFreeChart until clicked在单击之前无法加载从 JFreeChart 加载图表的线程
【发布时间】:2021-12-31 09:27:33
【问题描述】:

我认为我做的一切都是正确的。我想要的只是在加载组件和窗口的主线程完成后加载包含图表的线程。但它没有用。不知何故,我必须单击jPanel1(将加载图表的面板)并加载图表。任何帮助,将不胜感激。我试过的:

  • 将线程更改为SwingWorker
  • 将线程更改为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();
}

【问题讨论】:

  • 所有对 Swing 组件的更新都需要在 Event Dispatch Thread (EDT) 上执行。方法 doInBackground not 在 EDT 上运行,因此您不应该在该方法中操作 GUI 组件,例如 JLabelJPanel。顺便说一句,我通常使用glass panedoInBackground 运行时向用户显示一条消息。
  • 但是 JLabel 真的有效吗?它在线程执行后添加到 JPanel。
  • 您可以在 不是 EDT 的线程上更新 Swing 组件,但这可能会导致您的应用程序出现意外行为,我知道这是您的问题。您是否阅读了我其他评论中的链接?
  • 那么Swing不支持自定义线程?

标签: java multithreading swing


【解决方案1】:

Swing 是单线程的,不是线程安全的。这意味着您不应在事件调度线程的上下文中执行任何长时间运行或阻塞操作,并且不应从 EDT 的上下文之外修改 UI 的状态或 UI 依赖的任何状态。

所以,话虽如此,你createFrame1 可能看起来更像...

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();
}

或者,如果加载数据需要时间,您可以发布每个数据点...

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();
}

可运行示例...

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());
            }
        }
    }
}

等待事情完成……

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;
        }
    }
}

【讨论】:

  • 我之前尝试过将 SwingWorker 与 done() 方法一起使用,但仍然无法正常工作。我也试过你的代码(第一个),还是不行。我必须单击 jPanel1 才能显示图表。发表每一点是否会有所不同?其实我没有兴趣这样做,但如果这样做,我会尝试。
  • 我的一位代码导师说,JFreeChart 库可能存在错误,因为他们已经有一段时间没有维护该库了。
  • 好吧,我有一个正在运行的示例,它演示了它的工作原理。我认为在你的代码中没有被称为错误,但没有 minimal reproducible example 其他一切都是猜测工作
  • 现在我有两个可运行的示例,它们都有效。我怀疑JFreeChart 的问题在于您的代码中没有共享的内容
  • 您好 MadProgrammer,感谢您的大力支持。我实际上只在 initComponents() 之后调用了构造函数内的 createFrame1() 方法(在 Netbeans 中默认加载 UI 组件的方法)。在 PSVM 方法中使用 invokeLater() 调用构造函数。在您的示例中,您在 changeListener 中调用 done 方法。您能否详细说明为什么它是必要的,因为我仍然无法理解为什么出现 JLabel 而不是我帖子代码中的 JFreeChart。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-16
相关资源
最近更新 更多