4

クリックした MenuItem に応じて JPanels を表示する JFrame があります。それは機能しますが、JPanel がフレームに追加されて表示されたら、メソッドを呼び出す必要があります (そのパネル内で JFreeChart を使用していてchartPanel.repaint()、JPanel が表示されているときに呼び出す必要があるため):

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;
java.awt.EventQueue をインポートします。
java.awt.Font をインポートします。
import javax.swing.JButton;
javax.swing.JFrame をインポートします。
javax.swing.JLabel をインポートします。
import javax.swing.JOptionPane;
javax.swing.JPanel をインポートします。
import 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.XYDataset をインポートします。
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;

public class Window extends JFrame {
    プライベート JPanel contentPane;

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                試す {
                    ウィンドウ フレーム = new Window();
                    frame.setVisible(真);
                キャッチ(例外e){
                    e.printStackTrace();
                }
            }
        });
    }

    公開ウィンドウ() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setBounds(100, 100, 700, 500);
        contentPane = new JPanel();
        contentPane.setBorder(新しい EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(新しい BorderLayout(0, 0));
        setContentPane(コンテンツペイン);

        JButton clickme = new JButton("クリックしてください");
        clickme.addActionListener(新しいActionListener() {
            public void actionPerformed(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("JPanel の例") );
        contentPane.add( 例、BorderLayout.CENTER );
    }

}

class MyJPanel extends JPanel implement ChartMouseListener {
    プライベート ChartPanel chartPanel;
    プライベート JFreeChart チャート;
    プライベート XYPlot subplotTop;
    プライベート XYPlot subplotBottom;
    private CombinedDomainXYPlot プロット。

    public MyJPanel() {
        this.add( new JLabel("この JPanel にはグラフが含まれています") );
        createCombinedChart();
        chartPanel = new ChartPanel(チャート);
        chartPanel.addChartMouseListener(this);
        this.add(チャートパネル);
    }

    プライベートボイド 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);
    }

    プライベートボイド createSubplots() {
        subplotTop = new XYPlot();
        subplotBottom = new XYPlot();

        subplotTop.setDataset(emptyDataset("Empty 1"));
        subplotBottom.setDataset(emptyDataset("Empty 2"));
    }

    プライベート XYDataset emptyDataset(文字列のタイトル) {
        TimeSeries ts = 新しい TimeSeries(タイトル);
        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,"Magic!"); // この行をコメントして、コンソールを表示してみてください
        chartPanel.repaint();
        //これでグラフ領域を取得できます
        this.chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(0).getDataArea();
        this.chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(1).getDataArea();
    }
}

JOptionPane を使用した場合と使用しない場合で何が起こるかを確認してください。

4

3 に答える 3

5

なぜこれが起こっているのかの説明は素晴らしいでしょう。

以下のバリエーションから、いくつかの洞察が得られるかもしれません。ノート

  • Swing GUI オブジェクトは、ここで提案されている理由により、イベント ディスパッチ スレッド(EDT) でのみ構築および操作する必要があります。

  • EDT は、例に示すように、ユーザーの対話がモーダル ダイアログに限定されている場合でも、イベントの処理を続行します。

  • を使用する場合、呼び出すrepaint()必要はありませんChartPanel

  • 手動のコンテナ操作を優先CardLayoutまたは優先します。JTabbedPane

  • ここで説明するようにsetPreferredSize()、overrideを呼び出すのではなく。getPreferredSize()

補遺:問題を示している 2 行を削除しました。

ChartRenderingInfoチャートがレンダリングされるまで存在しない動的データです。チャートがバックグラウンドで更新されている間、モーダル ダイアログはイベントを処理します。Runnableそれがなくても、次のように適切にラップすることでメソッドをスケジュールできますinvokeLater()

EventQueue.invokeLater(new Runnable() {

    @Override
    public void run() {
        myPanel.methodCalledOnceDisplayed();
    }
});

より良い方法は、データが有効であることがわかっChartRenderingInfoているin リスナー、つまり によって実装されたリスナーにアクセスすることです。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!");
        }
    }
}

補遺:ChartMouseListenerいくつかの未解決の問題を説明し、クリーンアップするための追加の反復。

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;
        }
    }
}
于 2013-02-15T12:37:56.103 に答える
4

JPanel は、Thread.sleep が終了するまで表示されません。なんで?私は何を間違っていますか?

  • ブロックしないEvent Dispatch Thread、Thread.sleep(int)ブロック EDT、Swing GUI はこの遅延が終了するまで待機します。その間に行われたすべての変更Thread.sleep(int)は画面に表示されません。代わりにSwing Timerを使用してください。それ以外の場合は、Swing GUI へのすべての変更をラップする必要があります。invokeLater()

  • Swingはシングル スレッドであり、表示される GUI へのすべての更新 (または記載されているものinvokeLater) は EDT で行う必要があります。

  • より良いヘルプのために、SSCCE、短い、実行可能、コンパイル可能をすぐに投稿してください

于 2013-02-14T12:36:24.600 に答える
1

invokeLaterのおかげで解決したようです:

public void methodCalledOnceDisplayed() {
        SwingUtilities.invokeLater( new Runnable() {
            @オーバーライド
            public void run() {
                chartPanel.repaint();
                chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(0).getDataArea();
                chartPanel.getChartRenderingInfo().getPlotInfo().getSubplotInfo(1).getDataArea();
            }
        });
    }

今はありませんIndexOutOfBoundsException: Index: 0, Size: 0

なぜこれが起こっているのかの説明は素晴らしいでしょう

于 2013-02-15T09:26:14.597 に答える