我有一个显示JPanels的JFrame,具体取决于您单击的MenuItem . 它工作正常,但是现在我需要在将一个JPanel添加到框架中并且正在显示它时调用一个方法(因为我在该面板中使用了JFreeChart,当JPanel可见时我必须调用 chartPanel.repaint()
):
this.getContentPane().add( myjpanel, BorderLayout.CENTER ); //this = JFrame
this.validate();
myjpanel.methodCalledOnceDisplayed();
看起来好吗? myjpanel
真的被展示了吗?似乎不是:
public void methodCalledOnceDisplayed() {
chartPanel.repaint()
}
这不起作用( chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(0)
正在抛出IndexOutOfBoundsException) . 这意味着调用重绘时JPanel不可见,我测试了以下内容:
public void methodCalledOnceDisplayed() {
JOptionPane.showMessageDialog(null,"You should see myjpanel now");
chartPanel.repaint()
}
现在它工作了,我看到警报后面的 myjpanel
正如预期的那样,chartPanel被重新绘制并且没有发生异常 .
EDIT :SSCCE(需要jfreechart和jcommon: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();
}
}
看看有没有JOptionPane会发生什么 .
3 回答
您可以从下面的变体中获得一些见解 . 注意
由于建议here的原因,应仅在event dispatch thread(EDT)上构造和操作Swing GUI对象 .
EDT继续处理事件,如示例所示,即使用户交互仅限于模态对话框 .
使用
ChartPanel
时不应该调用repaint()
.首选CardLayout或JTabbedPane超过手动容器操作 .
而不是调用
setPreferredSize()
,覆盖getPreferredSize()
,如here所述 .附录:你已经删除了显示问题的两条线 .
ChartRenderingInfo
是动态数据,在呈现图表之前不存在 . 模式对话框在后台更新图表时处理事件;没有它,您可以通过将其包装在适合invokeLater()
的Runnable
中来安排您的方法:更好的方案是在您知道数据有效的侦听器中访问
ChartRenderingInfo
,即ChartPanel
实现的侦听器 .附录:一个额外的迭代来说明
ChartMouseListener
并清理一些松散的目标 .不阻止
Event Dispatch Thread
,Thread.sleep(int)
阻止EDT,Swing GUI等待直到此延迟结束,并且在Thread.sleep(int)
期间所做的所有更改都不会在屏幕上显示,而是使用Swing Timer,否则对Swing GUI的所有更改都必须包含在invokeLater()
中Swing是单线程的,所有对可见GUI的更新(或
invokeLater
之外的所有更新)都必须在EDT上完成,更多内容在Concurency in Swing中完成以便更快地发布SSCCE,简短,可运行,可编译
由于invokeLater,它似乎已经解决了:
现在没有
IndexOutOfBoundsException: Index: 0, Size: 0
explanation 为什么会发生这种情况会很棒