简体   繁体   English

JProgressBar 未更新

[英]JProgressBar not updating

I have made a very simple code to show it here, i have a button that should show a JDialog to check the progress status, i am using the invoke late to go through EDT and my loop isn't in the run method, so why isn't my bar updating ?我已经制作了一个非常简单的代码来在这里显示它,我有一个按钮应该显示一个 JDialog 来检查进度状态,我正在使用延迟调用来完成 EDT,我的循环不在 run 方法中,那么为什么我的酒吧不是在更新吗? here is the code这是代码

import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class JBarEx extends JFrame {
private JTextField progStatus = new JTextField("Undefined");
private JButton dialogBtn = new JButton("Show Progression dialog");
final JDialog dlg = new JDialog((JFrame) null, "prog Title", false);
final JProgressBar dpb = new JProgressBar(0, 100);

public JBarEx() {
    JPanel pan = new JPanel();
    dialogBtn.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
            // TODO Auto-generated method stub
            showProgress();
        }
    });
    progStatus.setEditable(false);
    pan.add(progStatus);
    pan.add(dialogBtn);
    setContentPane(pan);
    this.setSize(200, 100);
    setVisible(true);
}

public void showProgress() {
    dlg.add(BorderLayout.CENTER, dpb);
    dlg.add(BorderLayout.NORTH, new JLabel("prog message"));
    dlg.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    dlg.setSize(300, 75);
    dlg.setLocationRelativeTo(null);
    dlg.setVisible(true);

    for (int i = 0; i < 100; i++) {
        final int ii = i;
        try {
            Thread.sleep(25);
            SwingUtilities.invokeLater(new Runnable() {

                @Override
                public void run() {
                    updateBar(ii);

                }
            });
        }
        catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

public void updateBar(int newValue) {
    dpb.setValue(newValue);
}

public static void main(String[] args) {
    JBarEx jbx = new JBarEx();
}

} }

Your showProgress method is being executed within the context of the Event Dispatching Thread.您的showProgress方法正在事件调度线程的上下文中执行。 The EDT is responsible for, amongst other things, processing paint requests. EDT 负责处理油漆请求等。 This means that so long as your for-loop is executing, the EDT can not process any new paint requests (or handle the invokeLater events either) as it is blocking the EDT.这意味着只要您的for-loop正在执行,EDT 就无法处理任何新的绘制请求(或处理invokeLater事件),因为它正在阻塞 EDT。

While there are any number of possible ways to solve the problem, based on your code example, the simplest would be to use a SwingWorker .尽管有多种可能的方法可以解决问题,但根据您的代码示例,最简单的方法是使用SwingWorker

It has the capacity to allow your to execute the long running task the a background thread (freeing up the EDT), but also allows you means for publishing updates (if required) so that they can be processed in the EDT and also provides handy progress notification.它有能力让您在后台线程(释放 EDT)中执行长时间运行的任务,但也允许您publishing更新(如果需要),以便它们可以在 EDT 中处理并提供方便的progress通知。

For example...例如...

在此处输入图片说明

import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;

public class SwingWorkerProgress {

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

    public SwingWorkerProgress() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private JProgressBar pbProgress;
        private JButton start;

        public TestPane() {

            setBorder(new EmptyBorder(10, 10, 10, 10));
            pbProgress = new JProgressBar();
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.insets = new Insets(4, 4, 4, 4);
            gbc.gridx = 0;
            gbc.gridy = 0;
            add(pbProgress, gbc);

            start = new JButton("Start");
            gbc.gridy++;
            add(start, gbc);

            start.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    start.setEnabled(false);
                    ProgressWorker pw = new ProgressWorker();
                    pw.addPropertyChangeListener(new PropertyChangeListener() {

                        @Override
                        public void propertyChange(PropertyChangeEvent evt) {
                            String name = evt.getPropertyName();
                            if (name.equals("progress")) {
                                int progress = (int) evt.getNewValue();
                                pbProgress.setValue(progress);
                                repaint();
                            } else if (name.equals("state")) {
                                SwingWorker.StateValue state = (SwingWorker.StateValue) evt.getNewValue();
                                switch (state) {
                                    case DONE:
                                        start.setEnabled(true);
                                        break;
                                }
                            }
                        }

                    });
                    pw.execute();
                }
            });

        }
    }

    public class ProgressWorker extends SwingWorker<Object, Object> {

        @Override
        protected Object doInBackground() throws Exception {

            for (int i = 0; i < 100; i++) {        
                setProgress(i);
                try {
                    Thread.sleep(25);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            return null;
        }
    }
}

Check out Concurrency in Swing for more details查看Swing 中的并发以获取更多详细信息

Even if you fix the loop as others have pointed out, you'd still block the event dispatch thread.即使您像其他人指出的那样修复了循环,您仍然会阻塞事件调度线程。 The for loop is run in showProgress() which is called from an event listener. for循环在showProgress()运行,它是从事件侦听器调用的。 The updates are pushed to the event queue, but that does not get processed until the loop has completed.更新被推送到事件队列,但在循环完成之前不会被处理。

Use a Swing Timer instead.改用摇摆 计时器 Something like this:像这样的东西:

Timer timer = new Timer(25, new ActionListener() {
    private int position;

    @Override
    public void actionPerformed(ActionEvent e) {
         position++;
         if (position < lastPosition) {
             updateBar(position);
         } else {
             ((Timer) e.getSource).stop();
         }
    }
});
timer.start();

where lastPosition would be the state where you want the progress bar to stop.其中lastPosition将是您希望进度条停止的状态。

Unrelated to that bug, but a bug still, you should not create swing components outside the event dispatch thread.与该错误无关,但仍然是错误,您不应在事件调度线程之外创建 Swing 组件。 It's best to do it right from the start:最好从一开始就这样做:

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            JBarEx jbx = new JBarEx();
        }
    });
}
for (int i = 0; i < 0; i++) {

You will never enter this code so will never call the updateBar(..) method您永远不会输入此代码,因此永远不会调用 updateBar(..) 方法

i needs to be greater than 0 in this case.在这种情况下,需要大于 0。 If it is 1 then updateBar will be called once, if 2 then updateBar will be called twice etc如果是 1 则 updateBar 将被调用一次,如果是 2 则 updateBar 将被调用两次等

Also rather than doing也而不是做

Thread.sleep(25);

take a look at java executors as these will help with your scheduling and remove the need for the sleep看看 java executors,因为它们将有助于您的日程安排并消除对睡眠的需要

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM