JProgressBar是不可见的,但进度正在正确更新

时间:2013-11-26 03:04:10

标签: java swing swingworker jprogressbar invisible

我在这个类中执行任务,Dialog弹出为白色框。 print语句IS打印出我期望的进度值,但在操作完成之前,Dialog上没有显示任何内容。在结束对话框关闭之前,我可以看到进度条闪烁可见一毫秒。完全不知道发生了什么:\

    public class ProgressDialog extends JDialog {

    private JProgressBar pb;
    private SwingWorker<Boolean, Void> task;

    public SwingWorker<Boolean, Void> getTask(){
        return task;
    }

    public ProgressDialog(final String call){
        setTitle("Working...");
        setLayout(new BorderLayout());
        setBounds(300,300,300,100);
        pb = new JProgressBar(0, 100);
        pb.setValue(0);
        pb.setVisible(true);
        pb.setStringPainted(true);
        add(pb, BorderLayout.CENTER);
        setVisible(true);

        task = new SwingWorker<Boolean, Void>(){
            public Boolean doInBackground(){        
                switch(call){
                case "Category": pb.setValue(Category.getProgress());
                while(pb.getValue()<99){
                    try{
                        Thread.sleep(500);
                    } catch (InterruptedException e){
                        Thread.currentThread().interrupt();
                    }
                    pb.setValue(Category.getProgress());
                    System.out.println(pb.getValue());
                    repaint();
                    revalidate();
                }
                break;
                }
                return true;
            }
            public void done(){
                dispose();
            }
        };
    }
}
编辑:试过这个改变。没有骰子。为什么我甚至没有获得0%的进度条?只有在100%

时才出现
public class ProgressDialog extends JDialog {

private JProgressBar pb;
private SwingWorker<Boolean, Integer> task;

public SwingWorker<Boolean, Integer> getTask(){
    return task;
}

public ProgressDialog(final String call){
    setTitle("Working...");
    setLayout(new BorderLayout());
    setBounds(300,300,300,100);
    pb = new JProgressBar(0, 100);
    pb.setValue(0);
    pb.setStringPainted(true);
    add(pb, BorderLayout.CENTER);
    setVisible(true);

    task = new SwingWorker<Boolean, Integer>(){
        public Boolean doInBackground(){        
            switch(call){
            case "Category": setProgress(Category.getProgress());
            while(pb.getValue()<99){
                try{
                    Thread.sleep(500);
                } catch (InterruptedException e){
                    Thread.currentThread().interrupt();
                }
                setProgress(Category.getProgress());
            }
            break;
            }
            return true;
        }

        public void done(){
            //dispose();
        }
    };

    task.addPropertyChangeListener(new PropertyChangeListener() {
                public  void propertyChange(PropertyChangeEvent evt) {
                    if ("progress".equals(evt.getPropertyName())) {
                        System.out.println((Integer)evt.getNewValue());
                        pb.setValue((Integer)evt.getNewValue());
                        pb.revalidate();
                        pb.repaint();
                    }
                }
            });
}

}

2 个答案:

答案 0 :(得分:3)

您正在尝试从SwingWorker的doInBackground方法中设置进度条的状态,从后台线程 - 这没有任何意义。使用SwingWorker的全部原因是允许您在Swing GUI中执行后台处理,因此您不会从后台线程进行Swing调用,因此您不会将Swing线程与运行一点代码。

您不应该通过此后台进程进行Swing调用。而是使用发布/处理方法,如教程将向您展示的那样。或者更好的是,设置SwingWorker的进度字段,并在SwingWorker上使用PropertyChangeListener以允许进度条对其做出反应。

无论如何,底线:

  • 使用SwingWorker进行后台工作。
  • 不要在SwingWorker的doInBackground方法中进行Swing调用。
  • 使用publish将数据从后台方法推送到Swing线程领域。
  • 使用流程方法处理正在推送的数据。
  • SwingWorker有一个progress属性,可以方便地使用Swing代码来响应背景状态的变化。
  • 如果你走这条路,请使用PropertyChangeListener。
  • 您几乎从不想要使用setBounds(...)或null布局。相信我是一个写过数百个Swing程序的人,这个程序最终会咬你。
  • 您的类别似乎正在使用静态方法来获取进度。同样,这是你几乎不想做的事情。进度字段建议 state ,这应该是对象的实例字段的一部分,永远不会是静态的。

答案 1 :(得分:2)

这是一个SSCCE,用于演示如何更新JProgressBar。复制/粘贴并运行它。

请注意我们如何通过调用publish(i)来更新进度条,process()将整数发送到SwingWorker方法。 process()以块的形式将结果发送到Integer方法,但我们只使用JProgressBar来更新SwingWorker所以我们关心的是最后一个块。在这个SSCCE中,我们从1-1000开始。如果你检查一下控制台,你会看到很多1-1000之间的数字被跳过,因为我们更新速度太慢而process()赶上了(但没关系。这就是为什么它以块的形式提供结果的原因)。

注意:JTable方法最初是为程序员设计的,用于从长时间运行的进程返回实时结果并更新GUI。因此,如果您正在进行数据库提取,则可以使用返回的结果更新JProgressBar。不过我讨厌这样做。所以99%的时间我只使用“不确定”done()并等到JProgressBar方法发布我的结果。然而,偶然地,我将使用“确定的”process()并像我们在此SSCCE中那样更新。我从未使用import java.util.List; import java.util.concurrent.ExecutionException; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JProgressBar; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; /** * * @author Ryan */ public class Test { public static void main(String args[]) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { go(); } }); } public static void go() { JFrame frame = new JFrame(); JProgressBar jpb = new JProgressBar(); jpb.setIndeterminate(false); int max = 1000; jpb.setMaximum(max); frame.add(jpb); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); new Task(jpb, max).execute(); } static class Task extends SwingWorker<Void, Integer> { JProgressBar jpb; int max; public Task(JProgressBar jpb, int max) { this.jpb = jpb; this.max = max; } @Override protected void process(List<Integer> chunks) { jpb.setValue(chunks.get(chunks.size()-1)); // The last value in this array is all we care about. System.out.println(chunks.get(chunks.size()-1)); } @Override protected Void doInBackground() throws Exception { for(int i = 0; i < max; i++) { Thread.sleep(10); // Sleep for 1/10th of a second publish(i); } return null; } @Override protected void done() { try { get(); JOptionPane.showMessageDialog(jpb.getParent(), "Success", "Success", JOptionPane.INFORMATION_MESSAGE); } catch (ExecutionException | InterruptedException e) { e.printStackTrace(); } } } } 来返回和发布实际数据。 :)但是,这就是最初设计的目的。

SwingWorker

编辑:我创建了一个图表,在处理{{1}}时应该是一个有用的参考,以便您知道代码的放置位置。

enter image description here