进度条与线程(Java Swing)

时间:2014-09-03 13:55:23

标签: java swing thread-sleep

这是一个小例子:

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());返回IDE输出的数字,但jProgressBar1不会绘制此值。这段代码出了什么问题?请帮忙。

2 个答案:

答案 0 :(得分:1)

永远不要在Swing线程中使用Thread.sleep()。改为使用javax.swing.Timer。

示例:

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();
}

答案 1 :(得分:-1)

问题是你在正在做“工作”的同一个线程中调用.repaint()(Thread.sleep)。 "repaint() does not invoke paint() directly. It schedules a call to an intermediate method, update(). Finally, update() calls paint()..."。这意味着您正在安排一堆repaint()次呼叫,但它们未被处理。我还打赌,一旦值达到100,进度条跳转到已满,这是因为主线程已经结束并且所有repaint()调用最终都被处理。

为了使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;
            }
        }
    }
}

示例正常运行代码以使用上述内容:

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;
            }
        }
    }
}