Как заставить jprogressbar работать параллельно с моим алгоритмом
Возможный дубликат:
Java GUI JProgressBar не рисует
Можно ли использовать индикатор выполнения в классе вне main?
Я использую перетаскивание Netbeans, чтобы сделать приложение. Я получу ввод от пользователя и использую ввод для запуска моего алгоритма. Алгоритм будет работать разное время, а затем покажет свой результат в новом кадре. В ожидании запуска алгоритма я хочу добавить индикатор выполнения. Я добавляю в код ниже, когда пользователь нажимает кнопку отправить ввод.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
final JProgressBar bar = new JProgressBar(0,250000);
bar.setValue(1000);
bar.setIndeterminate(false);
JOptionPane jO = new JOptionPane(bar);
Thread th = new Thread(){
public void run(){
for(int i = 1000 ; i < 250000 ; i+=10000){
bar.setValue(i);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
}
}
}
};
th.start();
final JDialog dialog = jO.createDialog(jO,"Experiment X");
dialog.pack();
dialog.setVisible(true);
//Algorithm goes here
Индикатор выполнения отображается и запускается. Но когда значение индикатора выполнения обновляется до конца, запускается только мой алгоритм. Я вижу через пример других, но я не очень понимаю, как это работает.
Может кто-нибудь сказать мне, где я ошибся?
1 ответ
Некоторые из наиболее важных понятий в Swing:
НЕ выполняйте никаких длительных / блокирующих операций в потоке диспетчеризации событий (ETD). Это приведет к тому, что пользовательский интерфейс будет выглядеть "замороженным" и не реагирующим. Что приятно, вы, кажется, понимаете это.
НЕ создавайте и не изменяйте ЛЮБОЙ компонент пользовательского интерфейса из какого-либо потока ДРУГОГО, чем EDT Ты этого не делаешь.
Ваша лучшая причина действия состоит в том, чтобы воспользоваться SwingWorker
Это позволяет вам выполнять длительные операции, одновременно обеспечивая обратную связь с слушателями.
public class TestProgress {
public static void main(String[] args) {
new TestProgress();
}
public TestProgress() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException ex) {
} catch (InstantiationException ex) {
} catch (IllegalAccessException ex) {
} catch (UnsupportedLookAndFeelException ex) {
}
ProgressPane progressPane = new ProgressPane();
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(progressPane);
frame.setSize(200, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
// progressPane.doWork();
}
});
}
public class ProgressPane extends JPanel {
private JProgressBar progressBar;
private JButton startButton;
public ProgressPane() {
setLayout(new GridBagLayout());
progressBar = new JProgressBar();
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
add(progressBar, gbc);
startButton = new JButton("Start");
gbc.gridy = 1;
add(startButton, gbc);
startButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
startButton.setEnabled(false);
doWork();
}
});
}
public void doWork() {
Worker worker = new Worker();
worker.addPropertyChangeListener(new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
if ("progress".equals(evt.getPropertyName())) {
progressBar.setValue((Integer) evt.getNewValue());
}
}
});
worker.execute();
}
public class Worker extends SwingWorker<Object, Object> {
@Override
protected void done() {
startButton.setEnabled(true);
}
@Override
protected Object doInBackground() throws Exception {
for (int index = 0; index < 1000; index++) {
int progress = Math.round(((float) index / 1000f) * 100f);
setProgress(progress);
Thread.sleep(10);
}
return null;
}
}
}
}
Вы другой выбор будет использовать ProgressMonitor
или, если вы действительно в отчаянии, используйте SwingUtilities#invokeLater(Runnable)
, но я бы очень рекомендовал вам использовать SwingWorker
вместо;)