首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Swing invokeLater从未出现,invokeAndWait抛出错误。我能做什么?

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

Stack Overflow用户
提问于 2010-06-15 02:05:21
回答 5查看 1.3K关注 0票数 3

我有这样的代码:

代码语言:javascript
复制
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 (在没有SwingUtilities方法中),它就会冻结,直到操作完成。如果我将它添加到invokeLater中,它很快就会关闭(我看不到任何东西,并且操作还没有完成)。如果我将它添加到invokeAndWait中,我会得到invokeAndWait无法从事件分派器线程错误中调用。我该怎么办?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2010-06-15 02:16:32

看起来你可以利用SwingWorker。这允许您将代价高昂的操作推迟到后台线程(保持GUI的响应性),并在操作完成后对GUI执行一些操作。

编辑:示例

下面是一个更复杂的示例,它展示了如何使用SwingWorker的基础知识,以及如何发布/处理中间结果。

代码语言:javascript
复制
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);
}

编辑:更改示例以驱动进度条,就像正在进行下载一样。

票数 4
EN

Stack Overflow用户

发布于 2010-06-15 02:09:35

如果你这样做是为了响应按钮点击,那么你已经在事件线程中了,所以invokeAndWait实际上走错了方向。

您需要启动一个新线程来执行不是事件分派线程的handleDownload线程--但是

在新线程中运行时,请确保所有图形用户界面更新都使用invokeAndWait或invokeLater返回到EDT。

要记住的简单规则:

  • Swing传递给您的任何线程都是EDT,因此执行它上的所有图形用户界面内容您希望
  • 执行EDT上的所有图形用户界面元素的更新(仅限)。
  • 在非EDT线程上执行任何耗时较长的操作(启动新线程)。
  • 使用invokeLater从非EDT线程返回EDT
票数 4
EN

Stack Overflow用户

发布于 2010-06-15 02:10:26

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3039657

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档