我想在新的JDialog中创建JProgressBar,它将与主逻辑处于不同的线程中。因此,我可以通过仅创建新的JDialog并通过处置JDialog完成该进度来开始不确定的进度。但这给了我很多时间,因为在出现JDialog之后,直到完成主线程(SwingUtilities)中的逻辑后,它才显示任何组件(包括JProgressBar)。
包含JDialog的线程:
package gui.progress; public class ProgressThread extends Thread { private ProgressBar progressBar = null; public ProgressThread() { super(); } @Override public void run() { progressBar = new ProgressBar(null); progressBar.setVisible(true); } public void stopThread() { progressBar.dispose(); } }
JProgressBar切换方法:
private static ProgressThread progressThread = null; ... public static void toggleProcessBar() { if(progressThread == null) { progressThread = new ProgressThread(); progressThread.start(); } else { progressThread.stopThread(); progressThread = null; } }
但这给了我很多时间,因为在出现JDialog之后,直到完成主线程(SwingUtilities)中的逻辑后,它才显示任何组件(包括JProgressBar)。
您在Swing中存在并发问题,Swing是单线程的,所有更新必须在EventDispatchThread上完成,有两种方法
易于使用Runnable#Thread,但必须将输出包装到Swing GUI中invokeLater
Runnable#Thread
invokeLater
使用SwingWorker,有关示例,请SwingWorker参见Oracle JProgressBar和SwingWorker教程
SwingWorker
编辑
此代码模拟违反EDT的行为,也针对SwingWorker纠正了解决方法
import java.awt.Dimension; import java.awt.Toolkit; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.*; public class TestProgressBar { private static void createAndShowUI() { JFrame frame = new JFrame("TestProgressBar"); frame.getContentPane().add(new TestPBGui().getMainPanel()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } public static void main(String[] args) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { createAndShowUI(); } }); } private TestProgressBar() { } } class TestPBGui { private JPanel mainPanel = new JPanel(); public TestPBGui() { JButton yourAttempt = new JButton("Your attempt to show Progress Bar"); JButton myAttempt = new JButton("My attempt to show Progress Bar"); yourAttempt.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { yourAttemptActionPerformed(); } }); myAttempt.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { myAttemptActionPerformed(); } }); mainPanel.add(yourAttempt); mainPanel.add(myAttempt); } private void yourAttemptActionPerformed() { Window thisWin = SwingUtilities.getWindowAncestor(mainPanel); JDialog progressDialog = new JDialog(thisWin, "Uploading..."); JPanel contentPane = new JPanel(); contentPane.setPreferredSize(new Dimension(300, 100)); JProgressBar bar = new JProgressBar(0, 100); bar.setIndeterminate(true); contentPane.add(bar); progressDialog.setContentPane(contentPane); progressDialog.pack(); progressDialog.setLocationRelativeTo(null); Task task = new Task("Your attempt"); task.execute(); progressDialog.setVisible(true); while (!task.isDone()) { } progressDialog.dispose(); } private void myAttemptActionPerformed() { Window thisWin = SwingUtilities.getWindowAncestor(mainPanel); final JDialog progressDialog = new JDialog(thisWin, "Uploading..."); JPanel contentPane = new JPanel(); contentPane.setPreferredSize(new Dimension(300, 100)); final JProgressBar bar = new JProgressBar(0, 100); bar.setIndeterminate(true); contentPane.add(bar); progressDialog.setContentPane(contentPane); progressDialog.pack(); progressDialog.setLocationRelativeTo(null); final Task task = new Task("My attempt"); task.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if (evt.getPropertyName().equalsIgnoreCase("progress")) { int progress = task.getProgress(); if (progress == 0) { bar.setIndeterminate(true); } else { bar.setIndeterminate(false); bar.setValue(progress); progressDialog.dispose(); } } } }); task.execute(); progressDialog.setVisible(true); } public JPanel getMainPanel() { return mainPanel; } } class Task extends SwingWorker<Void, Void> { private static final long SLEEP_TIME = 4000; private String text; public Task(String text) { this.text = text; } @Override public Void doInBackground() { setProgress(0); try { Thread.sleep(SLEEP_TIME);// imitate a long-running task } catch (InterruptedException e) { } setProgress(100); return null; } @Override public void done() { System.out.println(text + " is done"); Toolkit.getDefaultToolkit().beep(); } }