如何在Swing中进行一些处理时重新绘制标签?

3

我刚接触Swing,尝试实现以下功能:

按下一个JButton后,程序开始迭代处理数百个项目,每个项目需要1秒钟的时间进行处理,每当处理完一个项目后,程序应该更新标签以显示已处理的项目数量。

问题在于,在所有项目迭代完成之前,标签的文本不会更新。

我在网上搜索了一下,似乎是因为它运行在同一个线程中,所以我创建了一个新的线程来处理数据并更新要在标签中使用的变量(已处理的文件数)。

但是这没有奏效。然后我甚至又创建了另一个线程,启动在前一个线程之后,用于重绘标签。仍然没有奏效。

代码如下:

btnNewButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            try { SwingUtilities.invokeLater(validateFiles); } 
}); }

Runnable validateFiles = new Runnable() {

    @Override
    public void run() {
                 while(x_is_not_100) {
                      processLoadsOfStuff();
                      label.setText(x); }
            }
};

你能帮我解决这个问题吗?

2个回答

8

简单 - 使用SwingWorker。欲了解更多信息,请阅读具有中间结果的任务教程。


这是一个相当通用的例子,它将使用 JLabel 显示从 030 的计数 -

public final class SwingWorkerDemo {
    private static JLabel label = 
        new JLabel(String.valueOf(0), SwingConstants.CENTER);

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

        JLabelSwingWorker workerThread = new JLabelSwingWorker();
        workerThread.run();
    }

    private static void createAndShowGUI(){
        final JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(label);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private static class JLabelSwingWorker extends SwingWorker<Void, Integer>{
        @Override
        protected Void doInBackground() throws Exception {
            for(int i = 1; i < 31; i++){
                Thread.sleep(1000);
                publish(i);
            }
            return null;
        }

        @Override
        protected void process(List<Integer> integers) {
            Integer i = integers.get(integers.size() - 1);
            label.setText(i.toString());
        }
    }
}

据我记得,avatar(...) + 1 很不错。 - mKorbel

6

后台处理必须在单独的线程中完成。但标签更新必须在事件分派线程中完成。

因此,您的代码应如下所示:

btnNewButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // start a new thread for the background task
        new Thread(validateFiles).start(); 
    }); 
}

Runnable validateFiles = new Runnable() {

    @Override
    public void run() {
             while(x_is_not_100) {
                  processLoadsOfStuff();
                  // use SwingUtilities.invokeLater so that the label update is done in the EDT:
                  SwingUtilities.invokeLater(new Runnable() {
                      @Override
                      public void run() {
                          label.setText(x);
                      }
                  });
             }
    };

但是您可能希望使用SwingWorker类,它设计为以更简单的方式执行此操作。其文档编写得非常好,并包含示例。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接