如何在JFreeChart条形图

时间:2018-05-05 01:01:15

标签: java swing jfreechart

我有一个JFrame,在这个框架中有一个JPanel,在JPanel中有一个JFreeChart(图表从方法中获取数据集),这个图表被添加到在JPanel中创建的ChartPanel,然后ChartPanel被添加到JPanel。我在JPanel中也有JComboBox,如果我在JComboBox中更改选项,ActionListener会更新数据集的值。返回数据集的方法也是从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并使用repaint和revalidate来设法更新该图表。如果我在JComboBox中更改了一次选项,在第二次更改之后一切都开始在屏幕上制动,旧图表不想消失并且新图表在其下面,我可以看到它,如果我调整屏幕大小。

2 个答案:

答案 0 :(得分:2)

您可以更新现有图表的数据集,如examples所示;当您更新模型(数据集)时,监听图(视图)将相应地更新自身; CategoryDataset的具体实现通常提供合适的mutator。

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

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

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

虽然技术上可以按照建议here替换封闭的视图组件,但更新或替换模型通常更好,如建议的here

答案 1 :(得分:1)

我发现了它的工作答案,但它有一个小问题。所以我的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选项几次后变慢。计算机的粉丝疯了,现在我不知道这部分代码是否有问题,或者我在某处犯了错误。当我回到我的程序的主菜单并使用其他组件时,它的工作与以前一样。

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

      if(ifActionListenerSet == false) {

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

现在一切都很好。