代码之家  ›  专栏  ›  技术社区  ›  Geo

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

  •  2
  • Geo  · 技术社区  · 15 年前

    我有这个密码:

    try {
        SwingUtilities.invokeAndWait(new Runnable() {
            public void run() {
            try {
                dialog.handleDownload();
            } catch (IOException io) {
                io.printStackTrace();
                }
            }
        });
    } catch(Exception io) { io.printStackTrace(); }
    

    handleDownload 我正在读取输入流,计算进度条的值,并将其设置为该值。所以,当我点击一个按钮时,一个新的JFrame就会打开,并执行我上面写的所有操作。

    如果我有 dialog.handleDownload invokeLater 关得很快(我什么也看不见,手术还没结束)。如果我把它加到 invokeAndWait 我明白了

    5 回复  |  直到 15 年前
        1
  •  4
  •   Mark Peters    15 年前

    看来你可以利用 SwingWorker

    编辑:示例

    这里有一个更复杂的例子,展示了如何使用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);
    }
    

        2
  •  4
  •   Bill K    15 年前

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

    要记住的简单规则:

    • 使用invokeLater从非EDT线程返回EDT
        3
  •  1
  •   Curtis    15 年前

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

        4
  •  1
  •   Paul Tomblin    15 年前

    “手动下载”是做什么的?不应该在事件调度程序线程中执行耗时的操作。如果事件调度器线程中的某个东西占用了大量CPU周期,那么显示将冻结,直到完成为止。在这样的情况下,调用普通线程(不使用SwingUtilities)在事件调度程序线程之外进行处理,并在该线程中使用SwingUtilities.invokeLater定期发送已更改的通知(如更新进度条),这样的情况要好得多。

        5
  •  1
  •   jjnguy Julien Chastang    15 年前

    SwingWorker . 这将允许您在一个单独的线程中下载文件,而不影响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) {
           }
       }
    }