I have a JFrame that displays JPanels depending on the MenuItem you click. It works, but now I need to call a method once a JPanel is added to the frame and it is being shown (because I'm using JFreeChart inside that panel and I have to call chartPanel.repaint()
when the JPanel is visible):
this.getContentPane().add( myjpanel, BorderLayout.CENTER ); //this = JFrame
this.validate();
myjpanel.methodCalledOnceDisplayed();
Does it seem ok? Is myjpanel
being shown really? It seems it is not:
public void methodCalledOnceDisplayed() {
chartPanel.repaint()
}
This is not working (chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(0)
is throwing IndexOutOfBoundsException). That means that the JPanel was not visible when repaint was called, I've tested the following:
public void methodCalledOnceDisplayed() {
JOptionPane.showMessageDialog(null,"You should see myjpanel now");
chartPanel.repaint()
}
Now it works, I see myjpanel
behind the alert, just as expected, chartPanel is repainted and no Exception occurs.
EDIT: SSCCE (jfreechart and jcommon needed: http://www.jfree.org/jfreechart/download.html)
import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.Font; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.border.EmptyBorder; import org.jfree.chart.ChartMouseEvent; import org.jfree.chart.ChartMouseListener; import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.CombinedDomainXYPlot; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.ChartPanel; import org.jfree.data.time.TimeSeries; import org.jfree.data.time.TimeSeriesCollection; import org.jfree.data.xy.XYDataset; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; public class Window extends JFrame { private JPanel contentPane; public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { Window frame = new Window(); frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } public Window() { setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 700, 500); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5, 5, 5, 5)); contentPane.setLayout(new BorderLayout(0, 0)); setContentPane(contentPane); JButton clickme = new JButton("Click me"); clickme.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { contentPane.removeAll(); MyJPanel mypanel = new MyJPanel(); contentPane.add( mypanel, BorderLayout.CENTER ); validate(); mypanel.methodCalledOnceDisplayed(); } }); contentPane.add( clickme, BorderLayout.NORTH ); JPanel example = new JPanel(); example.add( new JLabel("Example JPanel") ); contentPane.add( example, BorderLayout.CENTER ); } } class MyJPanel extends JPanel implements ChartMouseListener { private ChartPanel chartPanel; private JFreeChart chart; private XYPlot subplotTop; private XYPlot subplotBottom; private CombinedDomainXYPlot plot; public MyJPanel() { this.add( new JLabel("This JPanel contains the chart") ); createCombinedChart(); chartPanel = new ChartPanel(chart); chartPanel.addChartMouseListener(this); this.add( chartPanel ); } private void createCombinedChart() { plot = new CombinedDomainXYPlot(); plot.setGap(30); createSubplots(); plot.add(subplotTop, 4); plot.add(subplotBottom, 1); plot.setOrientation(PlotOrientation.VERTICAL); chart = new JFreeChart("Title", new Font("Arial", Font.BOLD,20), plot, true); } private void createSubplots() { subplotTop = new XYPlot(); subplotBottom = new XYPlot(); subplotTop.setDataset(emptyDataset("Empty 1")); subplotBottom.setDataset(emptyDataset("Empty 2")); } private XYDataset emptyDataset( String title ) { TimeSeries ts = new TimeSeries(title); TimeSeriesCollection tsc = new TimeSeriesCollection(); tsc.addSeries(ts); return tsc; } @Override public void chartMouseMoved(ChartMouseEvent e) { System.out.println("Mouse moved!"); } @Override public void chartMouseClicked(ChartMouseEvent arg0) {} public void methodCalledOnceDisplayed() { JOptionPane.showMessageDialog(null,"Magic!"); //try to comment this line and see the console chartPanel.repaint(); //now we can get chart areas this.chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(0).getDataArea(); this.chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(1).getDataArea(); } }
See what happens with and without the JOptionPane.
An explanation of why is this happening would be great.
You may get some insight from the variation below. Note
Swing GUI objects should be constructed and manipulated only on the event dispatch thread (EDT) for the reason suggested here.
The EDT continues to process events, as shown in the example, even while user interaction is limited to the modal dialog.
Invoking repaint()
should not be required when using ChartPanel
.
Prefer CardLayout
or JTabbedPane
over manual container manipulation.
Rather than invoking setPreferredSize()
, override getPreferredSize()
, as discussed here.
Addendum: You have removed the two lines … that are showing the problem.
ChartRenderingInfo
is dynamic data that doesn't exist until the chart has been rendered. The modal dialog handles events while the chart is updated in the background; without it, you can schedule your method by wrapping it in a Runnable
suitable for invokeLater()
:
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
myPanel.methodCalledOnceDisplayed();
}
});
A better scheme is to access the ChartRenderingInfo
in listeners where you know the data is valid, i.e. listeners implemented by ChartPanel
.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
/**
* @see https://stackoverflow.com/a/14894894/230513
*/
public class Test extends JFrame {
private JPanel panel;
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
Test frame = new Test();
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public Test() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final MyJPanel myPanel = new MyJPanel();
panel = new JPanel() {
@Override
public Dimension getPreferredSize() {
return myPanel.getPreferredSize();
}
};
panel.setBorder(new EmptyBorder(5, 5, 5, 5));
panel.setLayout(new BorderLayout());
add(panel);
myPanel.start();
JButton clickme = new JButton("Click me");
clickme.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
panel.removeAll();
panel.add(myPanel, BorderLayout.CENTER);
validate();
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
myPanel.methodCalledOnceDisplayed();
}
});
}
});
panel.add(clickme, BorderLayout.NORTH);
JPanel example = new JPanel();
example.add(new JLabel("Example JPanel"));
panel.add(example, BorderLayout.CENTER);
}
private static class MyJPanel extends JPanel {
private static final Random r = new Random();
private ChartPanel chartPanel;
private JFreeChart chart;
private XYPlot subplotTop;
private XYPlot subplotBottom;
private CombinedDomainXYPlot plot;
private Timer timer;
private Day now = new Day(new Date());
public MyJPanel() {
this.add(new JLabel("Chart panel"));
createCombinedChart();
chartPanel = new ChartPanel(chart);
this.add(chartPanel);
timer = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
update(subplotTop);
update(subplotBottom);
}
});
timer.start();
}
public void start() {
timer.start();
}
private void update(XYPlot plot) {
TimeSeriesCollection t = (TimeSeriesCollection) plot.getDataset();
for (int i = 0; i < t.getSeriesCount(); i++) {
TimeSeries s = t.getSeries(i);
s.add(now, Math.abs(r.nextGaussian()));
now = (Day) now.next();
}
}
private void createCombinedChart() {
plot = new CombinedDomainXYPlot();
plot.setGap(30);
createSubplots();
plot.add(subplotTop, 4);
plot.add(subplotBottom, 1);
plot.setOrientation(PlotOrientation.VERTICAL);
chart = new JFreeChart("Title",
JFreeChart.DEFAULT_TITLE_FONT, plot, true);
plot.setDomainAxis(new DateAxis("Domain"));
}
private void createSubplots() {
subplotTop = new XYPlot();
subplotBottom = new XYPlot();
subplotTop.setDataset(emptyDataset("Set 1"));
subplotTop.setRenderer(new XYLineAndShapeRenderer());
subplotTop.setRangeAxis(new NumberAxis("Range"));
subplotBottom.setDataset(emptyDataset("Set 2"));
subplotBottom.setRenderer(new XYLineAndShapeRenderer());
subplotBottom.setRangeAxis(new NumberAxis("Range"));
}
private XYDataset emptyDataset(String title) {
TimeSeriesCollection tsc = new TimeSeriesCollection();
TimeSeries ts = new TimeSeries(title);
tsc.addSeries(ts);
return tsc;
}
public void methodCalledOnceDisplayed() {
PlotRenderingInfo plotInfo =
this.chartPanel.getChartRenderingInfo().getPlotInfo();
for (int i = 0; i < plotInfo.getSubplotCount(); i++) {
System.out.println(plotInfo.getSubplotInfo(i).getDataArea());
}
JOptionPane.showMessageDialog(null, "Magic!");
}
}
}
Addendum: One additional iteration to illustrate ChartMouseListener
and clean up a few loose ends.
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import org.jfree.chart.ChartMouseEvent;
import org.jfree.chart.ChartMouseListener;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.entity.ChartEntity;
import org.jfree.chart.plot.CombinedDomainXYPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.time.Day;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import org.jfree.data.xy.XYDataset;
/**
* @see https://stackoverflow.com/a/14894894/230513
*/
public class Test {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
Test t = new Test();
}
});
}
public Test() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final MyJPanel myPanel = new MyJPanel();
f.add(myPanel, BorderLayout.CENTER);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
myPanel.start();
}
private static class MyJPanel extends JPanel {
private static final Random r = new Random();
private ChartPanel chartPanel;
private JFreeChart chart;
private XYPlot subplotTop;
private XYPlot subplotBottom;
private CombinedDomainXYPlot plot;
private Timer timer;
private Day now = new Day(new Date());
public MyJPanel() {
createCombinedChart();
chartPanel = new ChartPanel(chart);
this.add(chartPanel);
timer = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
update(subplotTop);
update(subplotBottom);
now = (Day) now.next();
}
});
chartPanel.addChartMouseListener(new ChartMouseListener() {
@Override
public void chartMouseClicked(ChartMouseEvent e) {
final ChartEntity entity = e.getEntity();
System.out.println(entity + " " + entity.getArea());
}
@Override
public void chartMouseMoved(ChartMouseEvent e) {
}
});
}
public void start() {
timer.start();
}
private void update(XYPlot plot) {
TimeSeriesCollection t = (TimeSeriesCollection) plot.getDataset();
for (int i = 0; i < t.getSeriesCount(); i++) {
TimeSeries s = t.getSeries(i);
s.add(now, Math.abs(r.nextGaussian()));
}
}
private void createCombinedChart() {
plot = new CombinedDomainXYPlot();
createSubplots();
plot.add(subplotTop, 4);
plot.add(subplotBottom, 1);
plot.setOrientation(PlotOrientation.VERTICAL);
chart = new JFreeChart("Title",
JFreeChart.DEFAULT_TITLE_FONT, plot, true);
plot.setDomainAxis(new DateAxis("Domain"));
}
private void createSubplots() {
subplotTop = new XYPlot();
subplotBottom = new XYPlot();
subplotTop.setDataset(emptyDataset("Set 1"));
subplotTop.setRenderer(new XYLineAndShapeRenderer());
subplotTop.setRangeAxis(new NumberAxis("Range"));
subplotBottom.setDataset(emptyDataset("Set 2"));
subplotBottom.setRenderer(new XYLineAndShapeRenderer());
subplotBottom.setRangeAxis(new NumberAxis("Range"));
}
private XYDataset emptyDataset(String title) {
TimeSeriesCollection tsc = new TimeSeriesCollection();
TimeSeries ts = new TimeSeries(title);
tsc.addSeries(ts);
return tsc;
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With