【问题标题】:Update normal distribution graph using JTextField in JFreeChart在 JFreeChart 中使用 JTextField 更新正态分布图
【发布时间】:2017-03-02 23:57:28
【问题描述】:

我有一个将JPanel 扩展为JFreeChart 的类。在setMean() 内部,我尝试更新dataset 或仅更新Function2D 的值,但即使使用repaint(),图表上也没有任何变化。

    public class JFreeChartPanel extends JPanel {
        Function2D normal = new NormalDistributionFunction2D(0.0, 3.0);
        XYDataset dataset = DatasetUtilities.sampleFunction2D(normal, -5.0, 5.0, 100, "Normal");

        double mean = 0.0, std = 1.0;

        public double getMean() {
            return mean;
        }

        public void setMean(double mean) {
            this.mean = mean;
            normal = new NormalDistributionFunction2D(mean,std);
            dataset = DatasetUtilities.sampleFunction2D(normal, -5.0, 5.0, 100, "Normal");
            repaint();
        }

        public double getStd() {
            return std;
        }

        public void setStd(double std) {
            this.std = std;
        }

        public JFreeChartPanel(){        

            JFreeChart chart = ChartFactory.createXYLineChart(
                "Normal Distribution",
                "X", 
                "Y", 
                dataset,
                PlotOrientation.VERTICAL,
                true,
                true,
                false
            );


            final ChartPanel chartPanel = new ChartPanel(chart);
            setLayout(new BorderLayout());
            add(chartPanel);
        }
}

每次我更改 JTextField 中的值时都会执行此操作。

public void updateMean()
    {
        String meanS = mean.getText();
        double mean = 0.0;
        try{
            mean = Double.parseDouble(meanS);
            System.out.println("Mean: "+mean);
            jFreeChartPanel.setMean(mean);
        }catch(Exception e){
            System.out.println("Mean: incorrect input");
        }
    }

【问题讨论】:

  • 您更改了 dataset 保存的值,但您从未更改过 JFreeChart 图表,它不会自行神奇地改变。我不使用 JFreeChart,但您必须检查 API 以查看是否可以在显示的图表上调用方法,或者是否必须使用新数据创建新方法。
  • @HovercraftFullOfEels 据我所知,JFreeChart 有大量的侦听器,因此任何更改都应自动反映在图表上。
  • 你不了解监听器是如何工作的——你必须设置它们,连接它们以使它们起作用。是的,您使用数据集对象创建了一个 JFreeChart 对象,但同样,稍后简单地更改数据集不会对 JFreeChart 对象产生影响。 JFreeChart 对象有一个模型,如果这个模型有侦听器,并且您使用适当的设置器方法更改模型,这些方法会使侦听器绊倒,我可以理解您的期望,但您不知道。您正在创建一个全新的数据集对象,因此无法想象它可以像您认为的那样工作。
  • 例如,假设 XYDataset 对象作为其模型连接到 JFreeChart 对象中(同样,我不使用 JFreeChart,因此可能不是这样,但只是假设它是),那么也许调用改变其状态的方法可能会起作用,但是再次您正在创建一个全新的 XYDataset 对象,因此即使它作为侦听器连接,您的新对象也不会导致JFreeChart 对象中的任何更改。
  • @HovercraftFullOfEels 关于替换数据集是正确的,正如below所建议的那样。

标签: java swing events jpanel jfreechart


【解决方案1】:

通常,您可以简单地更新用于创建JFreeChartXYDataset,收听图表会自动更新作为响应。作为@Hovercraft notes,仅repaint() 不足以告诉图表您已替换数据集。在下面的示例中,我重构了数据集的初始化并将其作为参数传递给setDataset()

public void setMean(double mean) {
    this.mean = mean;
    plot.setDataset(initDataset());
}

请参阅相关的source 以检查事件接线。将ChangeListener 添加到JSpinner 可能比JTextField 更易于操作。

import java.awt.BorderLayout;
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.event.ChangeEvent;
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.data.function.Function2D;
import org.jfree.data.function.NormalDistributionFunction2D;
import org.jfree.data.general.DatasetUtilities;
import org.jfree.data.xy.XYDataset;

/**
 * @see https://stackoverflow.com/a/40167139/230513
 */
public class TestDistribution {

    private static class JFreeChartPanel extends JPanel {

        private XYPlot plot;
        private double mean = 0.0, sigma = 1.0;
        XYDataset dataset = initDataset();

        private XYDataset initDataset() {
            Function2D normal = new NormalDistributionFunction2D(mean, sigma);
            XYDataset dataset = DatasetUtilities.sampleFunction2D(normal, -5.0, 5.0, 100, "Normal");
            return dataset;
        }

        ;
        public double getMean() {
            return mean;
        }

        public void setMean(double mean) {
            this.mean = mean;
            plot.setDataset(initDataset());
        }

        public double getStd() {
            return sigma;
        }

        public void setStd(double sigma) {
            this.sigma = sigma;
        }

        public JFreeChartPanel() {
            JFreeChart chart = ChartFactory.createXYLineChart(
                "Normal Distribution", "X", "Y", dataset,
                PlotOrientation.VERTICAL, true, true, false
            );
            plot = chart.getXYPlot();
            final ChartPanel chartPanel = new ChartPanel(chart);
            add(chartPanel);
        }
    }

    private void display() {
        JFrame f = new JFrame("TestDistribution");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JFreeChartPanel chartPanel = new JFreeChartPanel();
        f.add(chartPanel);
        JSpinner spinner = new JSpinner();
        spinner.setValue(chartPanel.mean);
        spinner.addChangeListener((ChangeEvent e) -> {
            JSpinner s = (JSpinner) e.getSource();
            Number n = (Number) s.getValue();
            chartPanel.setMean(n.doubleValue());
        });
        f.add(spinner, BorderLayout.PAGE_END);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new TestDistribution()::display);
    }
}

【讨论】:

  • 检查相关事件链here
  • 如果您不介意我有一个问题,是否有一种简单的方法可以更改 x 轴的刻度单位?由于它使用 ValueAxis 而不是 NumberAxis 我无法访问 setTickUnit
  • ChartFactory.createXYLineChart() 在内部使用NumberAxis,所以你可以投射;检查新问题here
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多