4

Swingはまだ比較的新しいですが、数時間検索した後、オンラインで答えを見つけることができなかったため、この投稿(すでに答えられていて見落としていた場合は申し訳ありません)。

SwingアプリケーションでJFreeChartを使用しています。一部のグラフは比較的重く(180kデータポイント)、JFreeChartのChartPanelは最初のpaintComponent()を実行するのに最大6秒かかります。

したがって、コンポーネントがペイントしている間、ダイアログに「お待ちください」というメッセージを表示したいと思います(SwingWorkerで進行状況を表示する必要はありません)。paintComponentメソッドをオーバーライドしようとしましたが、残念ながらメッセージが画面に表示されません(ダイアログをペイントする時間をとらずに、スレッドがチャートのペイントに直接入ると思います)。

私のコードは次のようになります。

public class CustomizedChartPanel extends ChartPanel{

private static final long serialVersionUID = 1L;
private JDialog dialog = null;
boolean isPainted = false;

public CustomizedChartPanel(JFreeChart chart) { super(chart); }

@Override
public void paintComponent(Graphics g) {
    //At first paint (which can be lengthy for large charts), show "please wait" message
    if (! isPainted){
        dialog = new JDialog();
        dialog.setUndecorated(true);
        JPanel panel = new JPanel();
        panel.add(new JLabel("Please wait"));
        dialog.add(panel);
        dialog.pack();
        GuiHelper.centerDialog(dialog); //Custom code to center the dialog on the screen
        dialog.setVisible(true);
        dialog.repaint();
    }

    super.paintComponent(g);

    if (! isPainted){
        isPainted = true;
        dialog.dispose();
            super.repaint();
        }
}
}

これ/ベストプラクティスを解決する方法についてのポインタは非常にありがたいです!

ありがとう、トーマス


アップデート:

ヒントと討論に感謝します:非常に役に立ちました。

JLayerソリューションはEDTでも実行されているため機能しないのではないかと心配しているため、invokeLater()を使用して提案されたソリューションの実装を開始しました。

残念ながら、paintComponent()がinvokeLater()によって呼び出されると、nullポインター例外が発生します。

私のコードは次のようになります。

    @Override
public void paintComponent(Graphics graph) {
    //At first paint (which can be lengthy for large charts), show "please wait" message
    if (! isPainted){
        isPainted = true;
        dialog = new JDialog();
        dialog.setUndecorated(true);
        JPanel panel = new JPanel();
        panel.add(new JLabel("Please wait"));
        panel.add(new JLabel("Please wait !!!!!!!!!!!!!!!!!!!!!!!!!!!!!"));
        dialog.add(panel);
        dialog.pack();
        GuiHelper.centerDialog(dialog); //Custom code to center the dialog on the screen
        dialog.setVisible(true);
        dialog.repaint();
        RunnableRepaintCaller r = new RunnableRepaintCaller(this, graph, dialog);
        SwingUtilities.invokeLater(r);
    }
    else super.paintComponent(graph); //NULL POINTER EXCEPTION HERE (invoked by runnable class)
}

そして、実行可能なクラスは次のとおりです。

public class RunnableRepaintCaller implements Runnable{
private ChartPanel target;
private Graphics g;
private JDialog dialog;

public RunnableRepaintCaller(ChartPanel target, Graphics g, JDialog dialog){
    this.target = target;
    this.g = g;
    this.dialog = dialog;
}

@Override
public void run() {
    System.out.println(g);
    target.paintComponent(g);
    dialog.dispose();
}
}

繰り返しになりますが、どんなポインタでも大歓迎です!

トーマス

4

4 に答える 4

5

これが例ですが、SwingWorkerを使用しています。どういうわけかOSがフレームを無効にし、JFreeChartのロードがEDT(Event Dispatching Thread)で行われると、GUIがフリーズしたように見えるため、これの使用を真剣に検討する必要があります。

また、データの処理中にユーザーからのフィードバックを向上させることもできます。(コードが少し長い場合は申し訳ありませんが、興味深いコードのほとんどはinitUIとSwingWorkerにあります)。

注:ダイアログの代わりにJLayerを使用することもできます(Java 7を使用している場合)が、私の例ではこれは不要でした。

コードはhttp://www.vogella.com/articles/JFreeChart/article.htmlから非常にインスピレーションを得ています

/**
 * This code was directly taken from: http://www.vogella.com/articles/JFreeChart/article.html
 * All credits goes to him for this code.
 * 
 * Thanks to him.
 */

import java.util.List;

import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PiePlot3D;
import org.jfree.data.general.DefaultPieDataset;
import org.jfree.data.general.PieDataset;
import org.jfree.util.Rotation;

public class PieChart extends JFrame {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                initUI();
            }
        });
    }

    protected static void initUI() {
        // First we create the frame and make it visible
        final PieChart demo = new PieChart("Comparison");
        demo.setSize(500, 270);
        demo.setVisible(true);
        // Then we display the dialog on that frame
        final JDialog dialog = new JDialog(demo);
        dialog.setUndecorated(true);
        JPanel panel = new JPanel();
        final JLabel label = new JLabel("Please wait...");
        panel.add(label);
        dialog.add(panel);
        dialog.pack();
        // Public method to center the dialog after calling pack()
        dialog.setLocationRelativeTo(demo);

        // allowing the frame and the dialog to be displayed and, later, refreshed
        SwingWorker<JFreeChart, String> worker = new SwingWorker<JFreeChart, String>() {

            @Override
            protected JFreeChart doInBackground() throws Exception {
                publish("Loading dataset");
                // simulating the loading of the Dataset
                try {
                    System.out.println("Loading dataset");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // This will create the dataset 
                PieDataset dataset = demo.createDataset();
                publish("Loading JFreeChart");
                // simulating the loading of the JFreeChart
                try {
                    System.out.println("Loading JFreeChart");
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // based on the dataset we create the chart
                JFreeChart chart = demo.createChart(dataset, "Which operating system are you using?");
                // we put the chart into a panel
                return chart;
            }

            @Override
            protected void process(List<String> chunks) {
                label.setText(chunks.get(0));
                dialog.pack();
                dialog.setLocationRelativeTo(demo);
                dialog.repaint();
            }

            @Override
            protected void done() {
                try {
                    // Retrieve the created chart and put it in a ChartPanel
                    ChartPanel chartPanel = new ChartPanel(this.get());
                    // add it to our frame
                    demo.setContentPane(chartPanel);
                    // Dispose the dialog.
                    dialog.dispose();
                    // We revalidate to trigger the layout
                    demo.revalidate();
                    // Repaint, just to be sure
                    demo.repaint();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

        };
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                     worker.execute();
            }
        });
        dialog.setVisible(true);
    }

    public PieChart(String applicationTitle) {
        super(applicationTitle);
    }

    /** * Creates a sample dataset */

    private PieDataset createDataset() {
        DefaultPieDataset result = new DefaultPieDataset();
        result.setValue("Linux", 29);
        result.setValue("Mac", 20);
        result.setValue("Windows", 51);
        return result;

    }

    /** * Creates a chart */

    private JFreeChart createChart(PieDataset dataset, String title) {

        JFreeChart chart = ChartFactory.createPieChart3D(title, // chart title
                dataset, // data
                true, // include legend
                true, false);
        PiePlot3D plot = (PiePlot3D) chart.getPlot();
        plot.setStartAngle(290);
        plot.setDirection(Rotation.CLOCKWISE);
        plot.setForegroundAlpha(0.5f);
        return chart;

    }

}
于 2012-07-31T20:04:47.573 に答える
2

ここでJLayer説明されているように使用できます。これは特に、必要に応じてビジーインジケーター用です。

さらに、データが完全に読み込まれるまで、JPanelを維持できます。setEnabled(false)これにより、の不要なクリックを防ぎますJPanel

于 2012-07-31T18:47:45.257 に答える
0

私がJavaで何かをしたのは久しぶりですが、私が知る限り、このrepaint()方法では実際に描画が行われることはありません。できるだけ早く再描画する必要があるとして、コントロールにフラグを立てるだけです。paint()コンポーネントをすぐに描画する場合は、メソッドを直接呼び出す必要があります。

于 2012-07-31T18:54:36.233 に答える
-2

新しいスレッドで待機中のダイアログを開始する必要があります。チャートの作成方法はわかりませんが、ここにサンプルがあります

SwingUtilities.invokeLater(new Runnable() {
        public void run() {
             dialog = new JDialog();
             dialog.setUndecorated(true);
             JPanel panel = new JPanel();
             panel.add(new JLabel("Please wait"));
             dialog.add(panel);                
             GuiHelper.centerDialog(dialog); 
             dialog.setVisible(true);

            Thread performer = new Thread(new Runnable() {
                public void run() {
                    dialog.setVisible(false); 
                    //Here the code that prepare the chart                              
                }
        });
        performer.start();
    }
});     
于 2012-07-31T18:55:47.267 に答える