Come faccio a far funzionare correttamente il mio esempio SwingWorker?

Ho creato il mio esempio SwingWorker per familiarizzare con il suo funzionamento.

Quello che voglio fare è il seguente: Quando si fa clic sul pulsante Voglio che venga visualizzata una barra di avanzamento fino a quando l’attività è terminata Voglio semplicemente rimuovere la barra di avanzamento e aggiungere una stringa alla finestra di dialogo.

Quando si fa clic sul pulsante, la barra di avanzamento viene visualizzata ma non scompare mai. (non rimuove mai la barra di avanzamento dopo 10 secondi e non posiziona mai l’etichetta)

Ecco un SSCCE:

package swingtesting; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JProgressBar; import javax.swing.SwingWorker; public class SwingTesting { /** * Creates a frame that will hold a simple button to make use of SwingWorker */ public static void main(String[] args) { // TODO code application logic here JFrame frame = new JFrame(); JButton button = new JButton(); button.addActionListener(new ActionListener() { public void actionPerformsd(ActionEvent e) { new GuiWorker().execute(); } }); button.setText("Test Me"); frame.getContentPane().add(button); frame.pack(); frame.setVisible(true); } } class GuiWorker extends SwingWorker { /* * This should just create a frame that will hold a progress bar until the * work is done. Once done, it should remove the progress bar from the dialog * and add a label saying the task complete. */ private JFrame frame = new JFrame(); private JDialog dialog = new JDialog(frame, "Swingworker test", true); private JProgressBar progressBar = new JProgressBar(); public GuiWorker() { progressBar.setString("Waiting on time"); progressBar.setStringPainted(true); progressBar.setIndeterminate(true); dialog.getContentPane().add(progressBar); dialog.pack(); dialog.setVisible(true); } @Override protected Integer doInBackground() throws Exception { Thread.sleep(10000); return 0; } @Override protected void done() { JLabel label = new JLabel("Task Complete"); dialog.getContentPane().remove(progressBar); dialog.getContentPane().add(label); } } 

Ecco una versione aggiornata del tuo codice che funziona

 import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JProgressBar; import javax.swing.SwingWorker; public class SwingTesting { public static void main(String[] args) { EventQueue.invokeLater( new Runnable() { @Override public void run() { JFrame frame = new JFrame(); JButton button = new JButton(); button.addActionListener(new ActionListener() { @Override public void actionPerformsd(ActionEvent e) { new GuiWorker().execute(); } }); button.setText("Test Me"); frame.getContentPane().add(button); frame.pack(); frame.setVisible(true); } } ); } } class GuiWorker extends SwingWorker { /* * This should just create a frame that will hold a progress bar until the * work is done. Once done, it should remove the progress bar from the dialog * and add a label saying the task complete. */ private JFrame frame = new JFrame(); private JDialog dialog = new JDialog(frame, "Swingworker test", true); private JProgressBar progressBar = new JProgressBar(); public GuiWorker() { progressBar.setString("Waiting on time"); progressBar.setStringPainted(true); progressBar.setIndeterminate(true); dialog.getContentPane().add(progressBar); dialog.pack(); dialog.setModal( false ); dialog.setVisible(true); } @Override protected Integer doInBackground() throws Exception { System.out.println( "GuiWorker.doInBackground" ); Thread.sleep(1000); return 0; } @Override protected void done() { System.out.println("done"); JLabel label = new JLabel("Task Complete"); dialog.getContentPane().remove(progressBar); dialog.getContentPane().add(label); dialog.getContentPane().validate(); } } 

Il punto chiave è che l’impostazione di una finestra di dialogo del modello è visibile fino a quando la finestra di dialogo non viene disposta. Quindi, impostandolo in modalità non modale, + la chiamata validate nel riquadro del contenuto quando cambi i componenti. Ho anche modificato il metodo principale per l’esecuzione su EDT e aggiunto alcune chiamate System.out. Se rimuovi la setModal( false ) , vedrai che queste istruzioni non vengono stampate finché non chiudi la finestra di dialogo

Non è necessario rendere la finestra di dialogo non modale. Basta visualizzare la finestra di dialogo dopo aver avviato SwingWorker. Questo può essere fatto dalla class chiamante, quella che esegue lo SwingWorker, chiamando prima execute, e poi mostrandone la finestra di dialogo, oppure può essere fatto da SwingWorker, ma se da quest’ultimo dovresti fare il tuo metodo pseudo-execute che chiama super’s execute, e quindi mostra la finestra di dialogo. Si noti che non è ansible sovrascrivere execute () poiché è definitivo.

Per esempio…

 import java.awt.CardLayout; import java.awt.Window; import java.awt.Dialog.ModalityType; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.concurrent.ExecutionException; import javax.swing.*; @SuppressWarnings("serial") public class SwingTesting2 { private static void createAndShowGui() { final JFrame frame = new JFrame("SwingTesting2"); final JDialog dialog = new JDialog(frame, "Dialog", ModalityType.APPLICATION_MODAL); final DialogPanel dialogPanel = new DialogPanel(); dialog.getContentPane().add(dialogPanel.getMainPanel()); dialog.pack(); dialog.setLocationRelativeTo(frame); JButton button = new JButton(new AbstractAction("Test Me") { @Override public void actionPerformsd(ActionEvent actEvt) { final GuiWorker2 guiWorker = new GuiWorker2(); guiWorker.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent pcEvt) { if (pcEvt.getPropertyName().equals("state")) { if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) { try { dialogPanel.done(guiWorker.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } } } else if (pcEvt.getPropertyName().equals("progress")) { dialogPanel.setProgress((Integer)pcEvt.getNewValue()); } } }); guiWorker.execute(); dialogPanel.start(); dialog.setVisible(true); } }); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(button); frame.pack(); frame.setLocationByPlatform(true); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGui(); } }); } } class GuiWorker2 extends SwingWorker { private static final int MAX_COUNT = 20; private static final long SLEEP_TIME = 100; private int count = 0; @Override protected Integer doInBackground() throws Exception { while (count < MAX_COUNT) { Thread.sleep(SLEEP_TIME); count++; setProgress((100 * count) / MAX_COUNT); } return count; } } @SuppressWarnings("serial") class DialogPanel { public static final String PROGRESS_BAR = "Progress Bar"; public static final String DONE = "Done"; private static final int TIMER_DELAY = 2000; private CardLayout cardLayout = new CardLayout(); private JPanel mainPanel = new JPanel(cardLayout); private JLabel doneLabel = new JLabel("Done", JLabel.CENTER); private JProgressBar progressBar = new JProgressBar(); public DialogPanel() { progressBar.setString("Waiting on time"); progressBar.setStringPainted(true); progressBar.setIndeterminate(false); mainPanel.add(progressBar, PROGRESS_BAR); mainPanel.add(doneLabel, DONE); } public void setProgress(Integer newValue) { progressBar.setValue(newValue); } public void start() { cardLayout.show(mainPanel, PROGRESS_BAR); progressBar.setValue(0); } public void done(int countValue) { doneLabel.setText(DONE + ". Count: " + countValue); cardLayout.show(mainPanel, DONE); new Timer(TIMER_DELAY, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Window win = SwingUtilities.getWindowAncestor(mainPanel); win.dispose(); } }){{setRepeats(false);}}.start(); } public JPanel getMainPanel() { return mainPanel; } }