带线程的进度条(Java Swing)

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25646236/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 08:23:35  来源:igfitidea点击:

Progress Bar with Thread (Java Swing)

javaswingthread-sleep

提问by obohovyk

Here is a little a example:

这是一个小例子:

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        int x = 0;
        while (jProgressBar1.getValue() < 100) {
            try {
                Thread.sleep(50);
                x++;
                jProgressBar1.setValue(x);
                jProgressBar1.repaint();
            } catch (InterruptedException ex) {
                Logger.getLogger(MainWindow.class.getName()).log(Level.SEVERE, null, ex);
            }
            System.out.println(jProgressBar1.getValue());
        }
    }

System.out.println(jProgressBar1.getValue());returns digits to IDE output, but jProgressBar1 doesn't draw this value. What's wrong with this code? Please help.

System.out.println(jProgressBar1.getValue());将数字返回到 IDE 输出,但 jProgressBar1 不绘制此值。这段代码有什么问题?请帮忙。

回答by Sergiy Medvynskyy

Never use Thread.sleep() in Swing thread. Use javax.swing.Timer instead.

切勿在 Swing 线程中使用 Thread.sleep()。请改用 javax.swing.Timer。

Example:

例子:

private void jButton1ActionPerformed(ActionEvent evt) {                                         
    final Timer t = new Timer(50, new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            jProgressBar1.setValue(jProgressBar1.getValue() + 1);
            if (jProgressBar1.getValue() == 100) {
              ((Timer) e.getSource()).stop();
            }
        }
    });
    t.start();
}

回答by Mshnik

The problem is that you're calling .repaint()in the same thread you're doing your "work" (Thread.sleep). "repaint() does not invoke paint() directly. It schedules a call to an intermediate method, update(). Finally, update() calls paint()...". This means you're scheduling a bunch of repaint()calls, but they aren't being processed. I would also bet that once the value does reach 100 the progress bar jumps to being full, which is because the main thread has ended and all of the repaint()calls are finally being processed.

问题是您正在调用.repaint()您正在执行“工作”的同一个线程(Thread.sleep)。“repaint() 不直接调用paint()。它调度对中间方法update() 的调用。最后,update() 调用paint()...”。这意味着您正在安排一堆repaint()调用,但它们没有被处理。我还敢打赌,一旦该值达到 100,进度条就会跳到满,这是因为主线程已经结束并且所有的repaint()调用最终都被处理了。

In order to make jProgressBars work, you have to have their repainting occur in a different thread than the one in which you are doing work (which notably should also be in a different thread - This is also true for most Swing updating). Try starting this Runnable in a new thread before you invoke your code:

为了使 jProgressBars 工作,您必须让它们的重绘发生在与您正在工作的线程不同的线程中(特别是也应该在不同的线程中 - 对于大多数 Swing 更新也是如此)。在调用代码之前,尝试在新线程中启动此 Runnable:

public class ProgressBarPainter implements Runnable{
    public JProgressBar jProgressBar1;
    public void run(){
        while(true){
            try {
                Thread.sleep(50);
                jProgressBar1.repaint();
            } catch (InterruptedException ex) {
               break;
            }
        }
    }
}

Example functioningcode to use the above:

使用上面的示例功能代码:

public class Frame extends JFrame {

    private static final long serialVersionUID = 1L;
    private JProgressBar bar;

    public Frame(){
        JPanel contentPanel = (JPanel) getContentPane();

        JButton b = new JButton("Do Process");
        b.addActionListener(new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent e) {
                ProgressBarPainter p = new ProgressBarPainter();
                p.jProgressBar1 = bar; //Fill in with the bar you want painted
                Thread t = new Thread(p);
                t.start();

                Worker w = new Worker();
                w.jProgressBar1 = bar;
                Thread t2 = new Thread(w);
                t2.start();
            }

        });
        contentPanel.add(b, BorderLayout.SOUTH);

        bar = new JProgressBar();
        contentPanel.add(bar, BorderLayout.CENTER);

        pack();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }

    public static void main(String[] args) {
        new Frame();
    }

}

class Worker implements Runnable{
    public JProgressBar jProgressBar1;
    public void run(){
        int x = 0;
        while(jProgressBar1.getValue() != jProgressBar1.getMaximum()){
            try {
                //Do some work
                Thread.sleep(50);
                //Update bar
                jProgressBar1.setValue(x++);
            } catch (InterruptedException ex) {
               break;
            }
        }
    }
}

class ProgressBarPainter implements Runnable{
    public JProgressBar jProgressBar1;
    public void run(){
        while(true){
            try {
                Thread.sleep(50);
                jProgressBar1.repaint();
            } catch (InterruptedException ex) {
               break;
            }
        }
    }
}