如何在 JFreeChart 条形图中更新数据集

How to update dataset in JFreeChart Bar Chart

我有一个 JFrame,在这个框架中有一个 JPanel,在一个 JPanel 中有一个 JFreeChart(图表从一个方法中获取数据集),这个图表被添加到在 JPanel 中创建的 ChartPanel,然后 ChartPanel 被添加到J面板。我在 JPanel 中也有 JComboBox,如果我更改该 JComboBox 中的选项,ActionListener 会更新数据集的值。还有方法 which return 数据集,从 JComboBox 中获取一个字符串(数据集的数据取决于 JComboBox 输出)。因此,如果我更改 JComboBox 中的选项,我想用新数据集更新 JFreeChart 并将其显示在屏幕上。我知道我需要在那个 ActionListener 中添加代码,但我不知道我应该在那里添加什么,是否有任何方法可以更新已经创建的 JFreeChart?

private class PanelChart extends JPanel { {
    this.setLayout(new BorderLayout());

    // Create Dataset
    //method GUIImplementation.GetDataForChart takes as an input value of combobox

    CategoryDataset dataset = GUIImplementation.GetDataForChart(comboBoxCrimeTypeChart.getSelectedItem().toString());


    //Create chart
    JFreeChart crimeNumberBarChart = ChartFactory.createBarChart(
        "Number of crimes by type", //Chart Title
        "Fallen within", // Category axis
        "Number of crimes", // Value axis
        dataset,
        PlotOrientation.VERTICAL,
        true,true,false
        );
    ChartPanel panelCrimeNumberBarChart = new ChartPanel(crimeNumberBarChart);
    this.add(panelCrimeNumberBarChart, BorderLayout.CENTER);

    PanelChartSouth panelChartSouth = new PanelChartSouth(); //there is a combobox
    this.add(panelChartSouth, BorderLayout.SOUTH);
}}

private class ChartButtonListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == backChart) {
            SizeAndTitleSetter(0);
            SwapPanelChart(0);
        } else if(e.getSource() == comboBoxCrimeTypeChart) { //comboBoxCrimeTypeChart is a JComboBox from PanelChartSouth
            String crimeType = comboBoxCrimeTypeChart.getSelectedItem().toString();
            System.out.println(crimeType);
            dataset = GUIImplementation.GetDataForChart(crimeType); // dataset updated
        }
    }
}

到目前为止,我只是设法通过从 JFrame 中删除 PanelChart 然后创建新的 PanelChart 并将其添加到 JFrame 并使用重绘和重新验证来以某种方式更新该图表。如果我在 JComboBox 中更改一次选项,它会起作用,在第二次更改后,屏幕上的所有内容都开始停止,旧图表不想消失,新图表在它下面,如果我调整屏幕大小,我可以看到它。

我找到了一个有效的答案,但它有一个小问题。所以我的 ActionListener 现在看起来像这样:

private class ChartButtonListener implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource() == backChart) {
            SizeAndTitleSetter(0);
            SwapPanelChart(0);
        } else if(e.getSource() == comboBoxCrimeTypeChart) {
            SwingUtilities.invokeLater(() -> {
                frame.remove(panelChart);
                panelChart = new PanelChart();
                frame.add(panelChart);
                frame.pack();
                frame.invalidate();
                frame.revalidate();
                frame.repaint();
            });
        }
    }
}

在我添加 SwingUtilities.invokeLater 之后它开始运行良好,但现在的问题是程序在更改 JComboBox 选项几次后变慢。电脑迷们快疯了,现在我不知道这是这部分代码的问题还是我在某处出错了。当我回到我的程序的主菜单并使用其他组件时,它的工作和以前一样。

我发现它开始变得迟钝的原因,在 class PanelChartSouth 中,我将 actionListener 添加到 JComboBox,并且在每次删除和创建新的 PanelChart 之后,将下一个 actionListener 添加到 JComboBox。所以防止它我已经把添加动作监听器的操作放到 if 语句

      if(ifActionListenerSet == false) {

        ifActionListenerSet = true;
    ChartButtonListener chartButtonListener = new ChartButtonListener();
    backChart.addActionListener(chartButtonListener);
    comboBoxCrimeTypeChart.addActionListener(chartButtonListener);
    }

现在一切都很好。

您可以更新现有图表的数据集,如这些所示examples; when you update the model (dataset), the listening plot (view) will update itself accordingly; concrete implementations of CategoryDataset通常会提供合适的修改器。

DefaultCategoryDataset model = …
…
@Override
public void actionPerformed(ActionEvent e) {
    model.setValue(…);
}

您可以使用相关绘图的 setDataset() 方法替换 现有图表的数据集。

CategoryPlot plot = (CategoryPlot) chart.getPlot();
…
@Override
public void actionPerformed(ActionEvent e) {
    plot.setDataset(…);
}

虽然按照建议 , it's generally better to update or replace the model, as suggested .

替换封闭视图组件在技术上是可行的