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

Tia*_*ago 2 java swing repaint

我是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); }
            }
};
Run Code Online (Sandbox Code Playgroud)

你能帮帮我吗?

mre*_*mre 7

简单 - 使用a SwingWorker.有关更多信息,请阅读具有中间结果的任务教程.


这是一个非常通用的例子,它将使用a JLabel来显示从0到30的计数-

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());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)


JB *_*zet 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);
                      }
                  });
             }
    };
Run Code Online (Sandbox Code Playgroud)

但是您可能希望使用SwingWorker该类,该类旨在以更简单的方式执行此操作.它的文档做得很好并包含示例.