问题
I am using pie chart to display some statistics in a JFrame
using JFreeChart package. I am using the PieDataset
to be passed to the createChart
method. Also, the datatset is set to update dynamically, as I am using the observer pattern in my application, which I thoroughly debugged. My issue is that in spite of being able to update the datatset dynamically, the piechart on the frame does not update as it is, maybe not able to take the new (updated) values and display the result. I would like to know if there is some other way to update the pie-chart dynamically.
public void update(Observable observable, Object o) {
if (o instanceof Game || o instanceof GameController) {
String label = "<html><head><h1>World Domination View</h1></head><body> ";
territoriesList = Game.getInstance().getGameMap().getTerritories();
String[] name = new String[Game.getInstance().getNumPlayers()] ;
Float[] value = new Float[Game.getInstance().getNumPlayers()];
for (int i = 0; i < Game.getInstance().getNumPlayers(); i++) {
int tempTerritoryCount = 0;
float percentage = 0;
for (Territory territory : territoriesList) {
if (territory.getOwner() == Game.getInstance().getPlayerById(i)) {
tempTerritoryCount += 1;
}
}
percentage = (float) 100.0 * tempTerritoryCount / Game.getInstance().getGameMap().getTerritories().size();
label = label + Game.getInstance().getPlayerById(i).getName() + " owns " + percentage
+ " % territories and owns " + PhaseView.getInstance().curPArmies + "<br/>";
worldDominationViewLabel.setText(label);
//dt = createDataset(Game.getInstance().getPlayerById(i).getName(),percentage);
//createDataset(Game.getInstance().getPlayerById(i).getName(),percentage);
//for(int j=0; j<Game.getInstance().getNumPlayers();j++){
name[i] = Game.getInstance().getPlayerById(i).getName();
//}
if(name[i] != null)
{
value[i] = percentage;
}
}
dt = createDataset(name,value);
chartPanel = new ChartPanel(createChart(dt));
chartPanel.setBounds(1024,0,310,300);//390
chartPanel.setVisible(true);
frameFromPhase.add(chartPanel);
worldDominationViewLabel.setText(label + "</body></html>");}}
//the dataset definition
public static PieDataset createDataset(String[] plname,Float[] value){
DefaultPieDataset dataset = new DefaultPieDataset();
for(int i =0; i< plname.length;i++){
dataset.setValue(plname[i],value[i]);
}
return dataset;
}
//chart definition
public static JFreeChart createChart(PieDataset dataset ) {
JFreeChart chart = ChartFactory.createPieChart(
"Player Map Domination: Territorywise", // chart title
dataset, // data
true, // include legend
true,
false);
return chart;
}
回答1:
As suggested here, don't create a new dataset and chart with each change; instead, "update the chart's data model, PieDataset
, and the listening view will follow." An implementation of the Observer interface can update the chart's model in its update()
method, just as well as the action handler of a JButton
can. Starting from this complete example, I've added an empty pie chart to View
and modified update()
to track guesses by invoking setValue()
on the chart's dataset.
class View extends JPanel {
private static final String s = "Click a button.";
private static final int SIZE = 256;
private Model model;
private ColorIcon icon = new ColorIcon(SIZE, Color.gray);
private JLabel label = new JLabel(s, icon, JLabel.CENTER);
DefaultPieDataset dataset = new DefaultPieDataset();
public View(Model model) {
super(new BorderLayout());
this.model = model;
label.setVerticalTextPosition(JLabel.BOTTOM);
label.setHorizontalTextPosition(JLabel.CENTER);
this.add(label, BorderLayout.CENTER);
this.add(genButtonPanel(), BorderLayout.SOUTH);
PiePlot plot = new PiePlot(dataset);
plot.setSimpleLabels(true);
JFreeChart chart = new JFreeChart(null, null, plot, false);
this.add(new ChartPanel(chart) {
@Override
public Dimension getPreferredSize() {
return new Dimension(SIZE, SIZE);
}
}, BorderLayout.WEST);
model.addObserver(new ModelObserver());
}
…
private class ModelObserver implements Observer {
private int pass, fail;
@Override
public void update(Observable o, Object arg) {
if (arg == null) {
label.setText(s);
icon.color = Color.gray;
} else {
if ((Boolean) arg) {
label.setText("Win!");
dataset.setValue("Pass", ++pass);
} else {
label.setText("Keep trying.");
dataset.setValue("Fail", ++fail);
}
}
}
}
…
}
来源:https://stackoverflow.com/questions/55459036/dynamically-update-a-pie-chart-in-an-observer