JPanel已添加但未“及时"显示 [英] JPanel added but not displayed "in time"

查看:29
本文介绍了JPanel已添加但未“及时"显示的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 JFrame,它根据您单击的 MenuItem 显示 JPanel.它可以工作,但是现在我需要在将 JPanel 添加到框架并显示它后调用一个方法(因为我在该面板内使用 JFreeChart 并且我必须调用 chartPanel.repaint() 当 JPanel 可见时):

this.getContentPane().add( myjpanel, BorderLayout.CENTER );//this = JFramethis.validate();myjpanel.methodCalledOnceDisplayed();

看起来好吗?myjpanel 真的显示了吗?好像不是:

public void methodCalledOnceDisplayed() {chartPanel.repaint()}

这不起作用(chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(0) 正在抛出 IndexOutOfBoundsException).这意味着调用重绘时 JPanel 不可见,我测试了以下内容:

public void methodCalledOnceDisplayed() {JOptionPane.showMessageDialog(null,"你现在应该看到 myjpanel");chartPanel.repaint()}

现在它可以工作了,我在警报后面看到 myjpanel,正如预期的那样,重新绘制了 chartPanel 并且没有发生异常.

编辑:SSCCE(需要 jfreechart 和 jcommon:http://www.jfree.org/jfreechart/download.html)

<前>导入 java.awt.BorderLayout;导入 java.awt.EventQueue;导入 java.awt.Font;导入 javax.swing.JButton;导入 javax.swing.JFrame;导入 javax.swing.JLabel;导入 javax.swing.JOptionPane;导入 javax.swing.JPanel;导入 javax.swing.border.EmptyBorder;导入 org.jfree.chart.ChartMouseEvent;导入 org.jfree.chart.ChartMouseListener;导入 org.jfree.chart.JFreeChart;导入 org.jfree.chart.plot.CombinedDomainXYPlot;导入 org.jfree.chart.plot.PlotOrientation;导入 org.jfree.chart.plot.XYPlot;导入 org.jfree.chart.ChartPanel;导入 org.jfree.data.time.TimeSeries;导入 org.jfree.data.time.TimeSeriesCollection;导入 org.jfree.data.xy.XY 数据集;导入 java.awt.event.ActionListener;导入 java.awt.event.ActionEvent;公共类窗口扩展 JFrame {私人 JPanel 内容窗格;公共静态无效主(字符串 [] args){EventQueue.invokeLater(new Runnable() {公共无效运行(){尝试 {窗框 = new Window();frame.setVisible(true);} 捕获(异常 e){e.printStackTrace();}}});}公共窗口(){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));设置内容窗格(内容窗格);JButton clickme = new JButton("点击我");clickme.addActionListener(new ActionListener() {公共无效动作执行(ActionEvent arg0){contentPane.removeAll();MyJPanel mypanel = new MyJPanel();contentPane.add( mypanel, BorderLayout.CENTER );证实();mypanel.methodCalledOnceDisplayed();}});contentPane.add( clickme, BorderLayout.NORTH );JPanel 示例 = new JPanel();example.add(new JLabel("Example JPanel"));contentPane.add( 示例, BorderLayout.CENTER );}}类 MyJPanel 扩展 JPanel 实现 ChartMouseListener {私人图表面板图表面板;私人 JFreeChart 图表;私人 XYPlot subplotTop;私人 XYPlot subplotBottom;私有的 CombinedDomainXYPlot 图;公共 MyJPanel() {this.add( new JLabel("This JPanel contains the chart") );createCombinedChart();chartPanel = new ChartPanel(chart);chartPanel.addChartMouseListener(this);this.add( chartPanel );}私有无效 createCombinedChart() {plot = new CombinedDomainXYPlot();plot.setGap(30);创建子图();plot.add(subplotTop, 4);plot.add(subplotBottom, 1);plot.setOrientation(PlotOrientation.VERTICAL);chart = new JFreeChart("Title", new Font("Arial", Font.BOLD,20), plot, true);}私人无效createSubplots(){subplotTop = 新 XYPlot();subplotBottom = new XYPlot();subplotTop.setDataset(emptyDataset("Empty 1"));subplotBottom.setDataset(emptyDataset("Empty 2"));}私人 XYDataset 空数据集(字符串标题){TimeSeries ts = new TimeSeries(title);TimeSeriesCollection tsc = new TimeSeriesCollection();tsc.addSeries(ts);返回 tsc;}@覆盖public void chartMouseMoved(ChartMouseEvent e) {System.out.println("鼠标移动了!");}@覆盖public void chartMouseClicked(ChartMouseEvent arg0) {}public void methodCalledOnceDisplayed() {JOptionPane.showMessageDialog(null,"魔法!");//尝试注释此行并查看控制台chartPanel.repaint();//现在我们可以获得图表区域this.chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(0).getDataArea();this.chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(1).getDataArea();}}

看看有和没有 JOptionPane 会发生什么.

解决方案

关于为什么会发生这种情况的解释会很棒.

您可能会从下面的变体中获得一些见解.注意

  • Swing GUI 对象应该事件调度线程 (EDT),原因在此处.p>

  • EDT 继续处理事件,如示例所示,即使用户交互仅限于模态对话框.

  • 在使用ChartPanel不需要调用repaint().

  • 首选 CardLayoutJTabbedPane 手动容器操作.

  • 不是调用 setPreferredSize(),而是覆盖 getPreferredSize(),正如讨论的 此处.

附录:您已经删除了显示问题的两行……

ChartRenderingInfo 是动态数据,在图表呈现之前不存在.当图表在后台更新时,模态对话框处理事件;没有它,您可以通过将其包装在适合 invokeLater()Runnable 中来安排您的方法:

EventQueue.invokeLater(new Runnable() {@覆盖公共无效运行(){myPanel.methodCalledOnceDisplayed();}});

更好的方案是在您知道数据有效的侦听器中访问ChartRenderingInfo,即由ChartPanel 实现的侦听器.

import java.awt.BorderLayout;导入 java.awt.Dimension;导入 java.awt.EventQueue;导入 java.awt.event.ActionEvent;导入 java.awt.event.ActionListener;导入 java.util.Date;导入 java.util.Random;导入 javax.swing.JButton;导入 javax.swing.JFrame;导入 javax.swing.JLabel;导入 javax.swing.JOptionPane;导入 javax.swing.JPanel;导入 javax.swing.Timer;导入 javax.swing.border.EmptyBorder;导入 org.jfree.chart.ChartPanel;导入 org.jfree.chart.JFreeChart;导入 org.jfree.chart.axis.DateAxis;导入 org.jfree.chart.axis.NumberAxis;导入 org.jfree.chart.plot.CombinedDomainXYPlot;导入 org.jfree.chart.plot.PlotOrientation;导入 org.jfree.chart.plot.PlotRenderingInfo;导入 org.jfree.chart.plot.XYPlot;导入 org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;导入 org.jfree.data.time.Day;导入 org.jfree.data.time.TimeSeries;导入 org.jfree.data.time.TimeSeriesCollection;导入 org.jfree.data.xy.XY 数据集;/*** @see https://stackoverflow.com/a/14894894/230513*/公共类测试扩展 JFrame {私人 JPanel 面板;公共静态无效主(字符串 [] args){EventQueue.invokeLater(new Runnable() {@覆盖公共无效运行(){测试框架 = new Test();框架.pack();frame.setLocationRelativeTo(null);frame.setVisible(true);}});}公共测试(){setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);最后的 MyJPanel myPanel = new MyJPanel();面板 = 新 JPanel() {@覆盖公共维度 getPreferredSize() {返回 myPanel.getPreferredSize();}};panel.setBorder(new EmptyBorder(5, 5, 5, 5));panel.setLayout(new BorderLayout());添加(面板);myPanel.start();JButton clickme = new JButton("点击我");clickme.addActionListener(new ActionListener() {@覆盖公共无效动作执行(ActionEvent arg0){panel.removeAll();panel.add(myPanel, BorderLayout.CENTER);证实();EventQueue.invokeLater(new Runnable() {@覆盖公共无效运行(){myPanel.methodCalledOnceDisplayed();}});}});panel.add(clickme, BorderLayout.NORTH);JPanel 示例 = new JPanel();example.add(new JLabel("Example JPanel"));panel.add(例如,BorderLayout.CENTER);}私有静态类 MyJPanel 扩展 JPanel {私有静态最终随机 r = 新随机();私人图表面板图表面板;私人 JFreeChart 图表;私人 XYPlot subplotTop;私人 XYPlot subplotBottom;私有的 CombinedDomainXYPlot 图;私人定时器定时器;现在私人日 = 新日(新日期());公共 MyJPanel() {this.add(new JLabel("图表面板"));createCombinedChart();chartPanel = new ChartPanel(chart);this.add(chartPanel);计时器 = 新计时器(1000,新 ActionListener(){@覆盖public void actionPerformed(ActionEvent e) {更新(subplotTop);更新(subplotBottom);}});定时器开始();}公共无效开始(){定时器开始();}私人无效更新(XYPlot 图){TimeSeriesCollection t = (TimeSeriesCollection) plot.getDataset();for (int i = 0; i < t.getSeriesCount(); i++) {时间序列 s = t.getSeries(i);s.add(现在,Math.abs(r.nextGaussian()));now = (Day) now.next();}}私有无效 createCombinedChart() {plot = new CombinedDomainXYPlot();plot.setGap(30);创建子图();plot.add(subplotTop, 4);plot.add(subplotBottom, 1);plot.setOrientation(PlotOrientation.VERTICAL);chart = new JFreeChart("Title",JFreeChart.DEFAULT_TITLE_FONT,情节,真);plot.setDomainAxis(new DateAxis("Domain"));}私人无效createSubplots(){subplotTop = 新 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"));}私人 XYDataset 空数据集(字符串标题){TimeSeriesCollection tsc = new TimeSeriesCollection();TimeSeries ts = new TimeSeries(title);tsc.addSeries(ts);返回 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!");}}}

附录:一个额外的迭代来说明 ChartMouseListener 并清理一些未解决的问题.

import java.awt.BorderLayout;导入 java.awt.EventQueue;导入 java.awt.event.ActionEvent;导入 java.awt.event.ActionListener;导入 java.util.Date;导入 java.util.Random;导入 javax.swing.JFrame;导入 javax.swing.JPanel;导入 javax.swing.Timer;导入 org.jfree.chart.ChartMouseEvent;导入 org.jfree.chart.ChartMouseListener;导入 org.jfree.chart.ChartPanel;导入 org.jfree.chart.JFreeChart;导入 org.jfree.chart.axis.DateAxis;导入 org.jfree.chart.axis.NumberAxis;导入 org.jfree.chart.entity.ChartEntity;导入 org.jfree.chart.plot.CombinedDomainXYPlot;导入 org.jfree.chart.plot.PlotOrientation;导入 org.jfree.chart.plot.XYPlot;导入 org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;导入 org.jfree.data.time.Day;导入 org.jfree.data.time.TimeSeries;导入 org.jfree.data.time.TimeSeriesCollection;导入 org.jfree.data.xy.XY 数据集;/*** @see https://stackoverflow.com/a/14894894/230513*/公共类测试{公共静态无效主(字符串 [] args){EventQueue.invokeLater(new Runnable() {@覆盖公共无效运行(){测试 t = 新测试();}});}公共测试(){JFrame f = new JFrame();f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);最后的 MyJPanel myPanel = new MyJPanel();f.add(myPanel, BorderLayout.CENTER);f.pack();f.setLocationRelativeTo(null);f.setVisible(true);myPanel.start();}私有静态类 MyJPanel 扩展 JPanel {私有静态最终随机 r = 新随机();私人图表面板图表面板;私人 JFreeChart 图表;私人 XYPlot subplotTop;私人 XYPlot subplotBottom;私有的 CombinedDomainXYPlot 图;私人定时器定时器;现在私人日 = 新日(新日期());公共 MyJPanel() {createCombinedChart();chartPanel = new ChartPanel(chart);this.add(chartPanel);计时器 = 新计时器(1000,新 ActionListener(){@覆盖public void actionPerformed(ActionEvent e) {更新(subplotTop);更新(subplotBottom);now = (Day) now.next();}});chartPanel.addChartMouseListener(new ChartMouseListener() {@覆盖public void chartMouseClicked(ChartMouseEvent e) {最终 ChartEntity entity = e.getEntity();System.out.println(entity + " " + entity.getArea());}@覆盖public void chartMouseMoved(ChartMouseEvent e) {}});}公共无效开始(){定时器开始();}私人无效更新(XYPlot 图){TimeSeriesCollection t = (TimeSeriesCollection) plot.getDataset();for (int i = 0; i < t.getSeriesCount(); i++) {时间序列 s = t.getSeries(i);s.add(现在,Math.abs(r.nextGaussian()));}}私有无效 createCombinedChart() {plot = new CombinedDomainXYPlot();创建子图();plot.add(subplotTop, 4);plot.add(subplotBottom, 1);plot.setOrientation(PlotOrientation.VERTICAL);chart = new JFreeChart("Title",JFreeChart.DEFAULT_TITLE_FONT,情节,真);plot.setDomainAxis(new DateAxis("Domain"));}私人无效createSubplots(){subplotTop = 新 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"));}私人 XYDataset 空数据集(字符串标题){TimeSeriesCollection tsc = new TimeSeriesCollection();TimeSeries ts = new TimeSeries(title);tsc.addSeries(ts);返回 tsc;}}}

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;
        }
    }
}

这篇关于JPanel已添加但未“及时"显示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆