Java Swing invokeLater从未出现,invokeAndWait抛出错误。我能做什么?

Java Swing invokeLater从未出现,invokeAndWait抛出错误。我能做什么?,java,swing,Java,Swing,我有以下代码: try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { try { dialog.handleDownload(); } catch (IOException io) { io.printStackTrace(); } } }); } catc

我有以下代码:

try {
    SwingUtilities.invokeAndWait(new Runnable() {
        public void run() {
        try {
            dialog.handleDownload();
        } catch (IOException io) {
            io.printStackTrace();
            }
        }
    });
} catch(Exception io) { io.printStackTrace(); }
handleDownload
中,我正在读取输入流,计算进度条的值,并将其设置为该值。所以,当我点击一个按钮时,一个新的JFrame就会打开,并完成我上面写的所有工作


如果我有
对话框.handleDownload
本身(在no-SwingUtilities方法中),它将冻结,直到操作完成。如果我将它添加到
invokeLater
中,它会很快关闭(我看不到任何东西,操作也没有完成)。如果将其添加到
invokeAndWait
中,则无法从事件调度程序线程错误调用
invokeAndWait
。我该怎么办?

如果您是为了响应按钮单击而这样做的,那么您已经在事件线程中,因此invokeAndWait实际上是在错误的方向上进行的

您需要启动一个新线程来执行handleDownload线程,该线程不是事件调度线程的一部分,而是

在新线程中运行时,请确保任何GUI更新都使用invokeAndWait或最好使用invokeLater返回EDT

要记住的简单规则:

  • Swing交给您的任何线程都是EDT,所以您需要在其上执行所有GUI内容
  • 在EDT上执行GUI元素的所有更新(仅限)
  • 在非EDT线程上执行任何需要较长时间的操作(启动新线程)
  • 使用invokeLater从非EDT线程返回EDT

您不应该在事件线程中访问inputStream。生成一个新线程,该线程实际执行handleDownload()的大部分工作,然后使该线程执行的最后一个操作是调用SwingUtilities.invokeLater(),并使用实际显示和填充对话框的代码。

handleDownload”做什么?不应在事件调度器线程中执行耗时的操作。如果事件调度器线程中的某些内容正在消耗大量CPU周期,则显示将冻结,直到完成为止。在这样的情况下,调用普通线程(不使用SwingUtilities)在事件调度程序线程之外进行处理,并在该线程中使用SwingUtilities.invokeLater发回事件已更改的通知(如更新进度条)会更好每隔一段时间。

看起来你可以利用它。这允许您将一个昂贵的操作延迟到后台线程(保持GUI响应),并且在操作完成后,对GUI执行一些操作

编辑:示例

这里有一个更复杂的示例,演示如何使用SwingWorker的基础知识,以及如何发布/处理中间结果

public static void main(String[] args) {
    final int SIZE = 1024*1024; //1 MiB

    //simulates downloading a 1 MiB file
    final InputStream in = new InputStream() {
        int read = 0;
        public int read() throws IOException {
            if ( read == SIZE ) {
                return -1;
            } else {
                if ( read % 200 == 0 ) {
                    try { Thread.sleep(1); } catch ( InterruptedException e ) {}
                }
                read++;
                return 5;
            }
        }
    };

    final JProgressBar progress = new JProgressBar(0, SIZE);

    final JButton button = new JButton("Start");
    button.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            button.setText("Working...");
            SwingWorker<byte[], Integer> worker = new SwingWorker<byte[], Integer>() {
                @Override
                protected byte[] doInBackground() throws Exception {
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    byte[] buff = new byte[1024];
                    for ( int read = -1; (read = in.read(buff)) != -1; ) {
                        baos.write(buff, 0, read);
                        publish(read);
                    }
                    return baos.toByteArray();
                }

                @Override
                protected void process(List<Integer> chunks) {
                    int total = 0;
                    for ( Integer amtRead : chunks ) {
                        total += amtRead;
                    }
                    progress.setValue(progress.getValue() + total);
                }

                @Override
                protected void done() {
                    try {
                        byte[] data = get();
                        button.setText("Read " + data.length + " bytes");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            };
            worker.execute();
        }
    });

    JFrame frame = new JFrame();
    frame.setLayout(new BorderLayout());
    frame.add(button, BorderLayout.NORTH);
    frame.add(progress, BorderLayout.SOUTH);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack(); frame.setVisible(true);
}
publicstaticvoidmain(字符串[]args){
最终int SIZE=1024*1024;//1 MiB
//模拟下载1 MiB文件
最终输入流输入=新输入流(){
int read=0;
public int read()引发IOException{
如果(读取==大小){
返回-1;
}否则{
如果(读取%200==0){
试试{Thread.sleep(1);}catch(InterruptedException e){}
}
读++;
返回5;
}
}
};
最终JProgressBar进度=新JProgressBar(0,大小);
最终JButton按钮=新JButton(“开始”);
addActionListener(新建ActionListener()){
@凌驾
已执行的公共无效操作(操作事件e){
按钮。设置文本(“工作…”);
SwingWorker worker=新SwingWorker(){
@凌驾
受保护字节[]doInBackground()引发异常{
ByteArrayOutputStream bas=新的ByteArrayOutputStream();
字节[]buff=新字节[1024];
对于(int read=-1;(read=in.read(buff))!=-1;){
写入(buff,0,read);
出版(阅读);
}
返回baos.toByteArray();
}
@凌驾
受保护的无效进程(列表块){
int-total=0;
for(整数amtRead:chunks){
总数+=amtRead;
}
progress.setValue(progress.getValue()+总计);
}
@凌驾
受保护的void done(){
试一试{
字节[]数据=get();
button.setText(“读取”+data.length+“字节”);
}捕获(例外e){
e、 printStackTrace();
}
}
};
worker.execute();
}
});
JFrame=新JFrame();
frame.setLayout(新的BorderLayout());
框架。添加(按钮,边框布局。北);
框架。添加(进度,边界布局。南部);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();frame.setVisible(true);
}

编辑:将示例更改为像下载一样驱动进度条。

听起来您需要的是一个。这将允许您在一个单独的线程中下载文件,而不会影响EDT

您的代码如下所示:

class Downloader extends SwingWorker<String, Void> {
   @Override
   public String doInBackground() {
       dialog.handleDownload();
       return "done";
   }

   @Override
   protected void done() {
       try { 
           someLabel.setText(get());
       } catch (Exception ignore) {
       }
   }
}
类下载程序扩展SwingWorker{
@凌驾
公共字符串doInBackground(){
dialog.handleDownload();
返回“完成”;
}
@凌驾
受保护的void done(){
试试{
setText(get());
}捕获(异常忽略){
}
}
}

这是一个很好的例子。不过,我会将循环更改为:
for(inti=0;I<100;I++){num+=5;publish(num);Thread.sleep(100);}
@jjngguy:对于这个示例,我实际上想要的是