Java 如何创建;请稍等;组件绘制时的Swing对话框

Java 如何创建;请稍等;组件绘制时的Swing对话框,java,swing,jfreechart,Java,Swing,Jfreechart,Swing仍然相对较新,但经过几个小时的搜索,我在网上找不到答案,因此发布了这篇文章(如果已经回答了,很抱歉,我忽略了它) 我正在Swing应用程序中使用JFreeChart。有些图表相对较重(180k数据点),JFreeChart的ChartPanel需要约6秒来完成第一个paintComponent() 因此,我希望在组件绘制时在对话框中显示“请稍候”消息(无需显示SwingWorker的进度)。我试图重写paintComponent方法,但不幸的是,消息从未出现在屏幕上(我猜线程直接进入绘

Swing仍然相对较新,但经过几个小时的搜索,我在网上找不到答案,因此发布了这篇文章(如果已经回答了,很抱歉,我忽略了它)

我正在Swing应用程序中使用JFreeChart。有些图表相对较重(180k数据点),JFreeChart的ChartPanel需要约6秒来完成第一个paintComponent()

因此,我希望在组件绘制时在对话框中显示“请稍候”消息(无需显示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();
        }
}
}
    @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)
}
任何关于如何解决此问题/最佳实践的建议都将不胜感激

谢谢, 托马斯


更新:

谢谢你的提示和辩论:非常有用

我开始用invokeLater()实现建议的解决方案,因为我担心JLayer解决方案无法工作,因为它也在EDT上运行

不幸的是,当调用器()调用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();
        }
}
}
    @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();
}
}
再次,任何指针都将不胜感激


Thomas

如前所述,您可以使用
JLayer
。 这是专门为繁忙的指标,因为你想


此外,您还可以使用
setEnabled(false)
保持
JPanel
,直到数据完全加载。这可以防止不必要的点击
JPanel

我已经很久没有用Java做过任何事情了,但据我所知,
repain()
方法实际上不会导致任何绘图。它只是将控件标记为需要尽快重新绘制。如果希望立即绘制组件,则需要直接调用
paint()
方法。

需要在新线程中启动等待对话框。我不知道如何创建图表,但这里有一个示例

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

下面是一个示例,但它使用SwingWorker。你应该认真考虑使用这一点,因为如果不知何故,OS使你的框架无效,你的JFLICH的加载在EDT(事件调度线程)上完成,那么你的GUI看起来会被冻结。 它还允许您在处理数据时提供更好的用户反馈。(如果代码有点长,很抱歉,但是大多数有趣的代码都在initUI和SwingWorker中)

注意:您可以使用JLayer(如果您使用Java7),而不是对话框,但在我的示例中这是不必要的

该代码的灵感来源于

/**
*此代码直接取自:http://www.vogella.com/articles/JFreeChart/article.html
*这个密码的所有功劳都归他了。
* 
*多亏了他。
*/
导入java.util.List;
导入javax.swing.JDialog;
导入javax.swing.JFrame;
导入javax.swing.JLabel;
导入javax.swing.JPanel;
导入javax.swing.SwingUtilities;
导入javax.swing.SwingWorker;
导入org.jfree.chart.ChartFactory;
导入org.jfree.chart.ChartPanel;
导入org.jfree.chart.JFreeChart;
导入org.jfree.chart.plot.PiePlot3D;
导入org.jfree.data.general.DefaultPieDataset;
导入org.jfree.data.general.PieDataset;
导入org.jfree.util.Rotation;
公共类PieChart扩展JFrame{
公共静态void main(字符串[]args){
SwingUtilities.invokeLater(新的Runnable(){
@凌驾
公开募捐{
initUI();
}
});
}
受保护的静态void initUI(){
//首先,我们创建框架并使其可见
最终PieChart演示=新PieChart(“比较”);
演示设置大小(500270);
demo.setVisible(true);
//然后,我们在该框架上显示对话框
最终JDialog对话框=新JDialog(演示);
对话框。设置未装饰(true);
JPanel面板=新的JPanel();
最终JLabel标签=新JLabel(“请稍候…”);
面板。添加(标签);
对话框。添加(面板);
dialog.pack();
//调用pack()后使对话框居中的公共方法
对话框。setLocationRelativeTo(演示);
//允许显示框架和对话框,并在以后刷新
SwingWorker worker=新SwingWorker(){
@凌驾
受保护的JFreeChart doInBackground()引发异常{
发布(“加载数据集”);
//模拟数据集的加载
试一试{
System.out.println(“加载数据集”);
《睡眠》(2000年);
}捕捉(中断异常e){
e、 printStackTrace();
}
//这将创建数据集
PieDataset=demo.createDataset();
发布(“加载JFreeChart”);
//模拟JFreeChart的加载
试一试{
System.out.println(“加载JFreeChart”);
《睡眠》(2000年);
}捕捉(中断异常e){
e、 printStackTrace();
}
//我们根据数据集创建图表
JFreeChart chart=demo.createChart(数据集,“您使用的是哪个操作系统?”);
//我们把图表放在一个面板上
收益表;
}
@凌驾
受保护的无效进程(列表块){
label.setText(chunks.get(0));
dialog.pack();
对话框。setLocationRelativeTo(演示);
dialog.repaint();
}
@凌驾
受保护的void done(){
试一试{
//检索创建的图表并将其放入图表面板中