问题
I would like to ask a follow up question to this Q&A question (How can I update a JFreeChart's appearance after it's been made visible?) from @trashgod.
I am trying to give the user a JSlider
to control the transparency of the graphs. I added a JSlider
and a ChangeListener
to repaint whenever there is a JSlider change.
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
chartPanel.repaint();
}
});
However, the transparency is not updated until the user "clicks" the graph with the mouse. Why isn't this working?
Here's the SSCCE (with jFreeChart library):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GradientPaint;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.AttributedString;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.plaf.basic.BasicButtonListener;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.PieSectionLabelGenerator;
import org.jfree.chart.labels.PieToolTipGenerator;
import org.jfree.chart.plot.MultiplePiePlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.chart.title.LegendTitle;
import org.jfree.chart.title.TextTitle;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.PieDataset;
import org.jfree.util.TableOrder;
/**
* This example is similar to {@link MultiplePieChartDemo1}, but slices the
* dataset by column rather than by row.
*/
public class MultiplePieChart extends JPanel {
/**
* Creates a sample dataset.
*
* @return A sample dataset.
*/
private static CategoryDataset createDataset() {
BigInteger topSources_quan = new BigInteger("100");
BigInteger notTopSources_quan = new BigInteger("10");
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.addValue(topSources_quan, "Included Sources", "Sales Quantity");
dataset.addValue(notTopSources_quan, "Not Included Sources", "Sales Quantity");
BigDecimal topSources_total = new BigDecimal("1450.34");
BigDecimal notTopSources_total = new BigDecimal("99.78");
dataset.addValue(topSources_total, "Included Sources", "Sales Total");
dataset.addValue(notTopSources_total, "Not Included Sources", "Sales Total");
return dataset;
}
/**
* Creates a sample chart with the given dataset.
*
* @param dataset the dataset.
*
* @return A sample chart.
*/
private static JFreeChart createChart(CategoryDataset dataset, Dimension size, String chartTitle, boolean includeLegend, final JSlider slider) {
JFreeChart chart = ChartFactory.createMultiplePieChart(
chartTitle, // chart title
dataset, // dataset
TableOrder.BY_COLUMN,
includeLegend, // include legend
true,
false
);
chart.setBackgroundPaint(new GradientPaint(0, 0, new Color(240,240,240), 0, ((int)size.getHeight() / 2), new Color(200, 200, 200), true));
TextTitle title = new TextTitle(chartTitle == null? "" : chartTitle, new Font("Tahoma", Font.BOLD, 16));
chart.setTitle(title);
if(includeLegend) {
LegendTitle legend = chart.getLegend();
legend.setBackgroundPaint(new Color(0, 0, 0, 0));
legend.setItemFont(new Font("Tahoma", Font.PLAIN, 12));
legend.setBorder(0, 0, 0, 0);
}
MultiplePiePlot plot = (MultiplePiePlot) chart.getPlot();
JFreeChart stamper = plot.getPieChart();
if(dataset.getColumnCount() == 1) {
stamper.getTitle().setFont(new Font("Tahoma", Font.PLAIN, 0));
} else {
stamper.getTitle().setFont(new Font("Tahoma", Font.PLAIN, 12));
}
stamper.setBackgroundPaint(new GradientPaint(0, 0, new Color(240,240,240), 0, ((int)size.getHeight() / 2), new Color(200, 200, 200), true));
plot.setOutlineStroke(null);
plot.setBackgroundAlpha(.25f);
JFreeChart subchart = plot.getPieChart();
final PiePlot p = (PiePlot) subchart.getPlot();
p.setBackgroundAlpha(0f);
p.setOutlineStroke(null);
p.setSectionPaint("Included Sources", new Color(0,100,255));
p.setSectionPaint("Not Included Sources", new Color(255, 50, 50));
p.setStartAngle(0);
p.setLabelFont(new Font("Tahoma", Font.PLAIN, 9));
p.setForegroundAlpha(.6f);
if(slider != null) {
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
float value = (float)slider.getValue() / (float)100;
System.out.println("Setting foreground alpha:" + value);
p.setForegroundAlpha(value);
}
});
}
p.setMaximumLabelWidth(0.20);
p.setLabelGenerator(null);
PieToolTipGenerator cttg = new PieToolTipGenerator() {
@Override
public String generateToolTip(PieDataset dataset, Comparable key) {
Number val = dataset.getValue(key);
if(val instanceof BigDecimal) {
DecimalFormat df = new DecimalFormat("$ #,##0.00");
return df.format(val.floatValue());
} else if(val instanceof BigInteger) {
DecimalFormat df = new DecimalFormat("#,##0");
return df.format(val.intValue());
} else
return val.toString();
}
};
p.setToolTipGenerator(cttg);
return chart;
}
/**
* Creates a panel for the demo (used by SuperDemo.java).
*
* @return A panel.
*/
public static JPanel createPanel(final JFrame parentFrame, CategoryDataset dataset, Dimension size, String chartTitle, boolean includeLegend, JSlider slider) {
JFreeChart chart = createChart(dataset, size, chartTitle, includeLegend, slider);
final ChartPanel chartPanel = new ChartPanel(chart);
chartPanel.setMouseWheelEnabled(true);
if(size != null)
chartPanel.setPreferredSize(size);
if(slider != null) {
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
chartPanel.repaint();
}
});
}
return chartPanel;
}
public static void main(String[] args) {
JFrame frame = new JFrame();
JSlider slider = new JSlider();
JFrame sliderFrame = new JFrame();
sliderFrame.add(slider);
sliderFrame.pack();
JPanel panel = createPanel(frame, createDataset(), new Dimension(800, 500), "Sales", true, slider);
frame.add(panel);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
frame.setLocationRelativeTo(null);
sliderFrame.setLocation(frame.getLocationOnScreen().x + frame.getWidth() - slider.getWidth(), frame.getLocationOnScreen().y + frame.getHeight());
sliderFrame.setVisible(true);
sliderFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
static class CustomLabelGenerator implements PieSectionLabelGenerator {
public String generateSectionLabel(PieDataset dataset, Comparable key) {
if(dataset.getValue(key) instanceof BigInteger) {
NumberFormat nf = new DecimalFormat("#,##0");
return nf.format(((BigInteger)dataset.getValue(key)).intValue());
} else if (dataset.getValue(key) instanceof BigDecimal) {
NumberFormat nf = new DecimalFormat("$ #,##0.00");
return nf.format(((BigDecimal)dataset.getValue(key)).doubleValue());
} else {
return dataset.getValue(key).toString();
}
}
public AttributedString generateAttributedSectionLabel(
PieDataset dataset, Comparable key) {
return null;
}
}
}
回答1:
The critical issue is to notify the chart that you've modified "the pie chart that is used to draw the individual pie plots."
chart.fireChartChanged();
Simplified SSCCE:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.math.BigDecimal;
import java.math.BigInteger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.MultiplePiePlot;
import org.jfree.chart.plot.PiePlot;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.util.TableOrder;
/**
* @see http://stackoverflow.com/a/17370398/230513
* This example is similar to {@link MultiplePieChartDemo1}, but slices the
* dataset by column rather than by row.
*/
public class MultiplePieChart extends JPanel {
private JSlider slider = new JSlider();
private CategoryDataset createDataset() {
BigInteger topSources = new BigInteger("100");
BigInteger notTopSources = new BigInteger("10");
DefaultCategoryDataset dataset = new DefaultCategoryDataset();
dataset.addValue(topSources, "Included Sources", "Sales Quantity");
dataset.addValue(notTopSources, "Not Included Sources", "Sales Quantity");
BigDecimal topSourcesTotal = new BigDecimal("1450.34");
BigDecimal notTopSourcesTotal = new BigDecimal("99.78");
dataset.addValue(topSourcesTotal, "Included Sources", "Sales Total");
dataset.addValue(notTopSourcesTotal, "Not Included Sources", "Sales Total");
return dataset;
}
private JFreeChart createChart() {
final JFreeChart chart = ChartFactory.createMultiplePieChart(
"Sales", createDataset(), TableOrder.BY_COLUMN, true, true, false);
MultiplePiePlot plot = (MultiplePiePlot) chart.getPlot();
JFreeChart subchart = plot.getPieChart();
final PiePlot p = (PiePlot) subchart.getPlot();
p.setForegroundAlpha(0.5f);
slider.setValue((int) (p.getForegroundAlpha() * 100));
slider.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
float value = (float) slider.getValue() / (float) 100;
p.setForegroundAlpha(value);
chart.fireChartChanged();
}
});
return chart;
}
public JPanel createChartPanel() {
JFreeChart chart = createChart();
final ChartPanel chartPanel = new ChartPanel(chart) {
@Override
public Dimension getPreferredSize() {
return new Dimension(800, 400);
}
};
return chartPanel;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
MultiplePieChart mpc = new MultiplePieChart();
JFrame frame = new JFrame();
frame.add(mpc.createChartPanel());
frame.add(mpc.slider, BorderLayout.SOUTH);
frame.pack();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
来源:https://stackoverflow.com/questions/17368470/update-transparancy-of-jfreechart-in-real-time-with-jslider