2012-04-19 11 views
15

Ho creato il mio esempio SwingWorker per familiarizzare con il suo funzionamento.Come faccio a far funzionare correttamente il mio esempio SwingWorker?

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 si apre ma non scompare mai. (Mai rimuove la barra di avanzamento dopo 10 secondi e non mette l'etichetta verso l'alto)

Ecco uno 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 actionPerformed(ActionEvent e) { 
       new GuiWorker().execute(); 
      } 
     }); 
     button.setText("Test Me"); 
     frame.getContentPane().add(button); 
     frame.pack(); 
     frame.setVisible(true); 
    } 
} 

class GuiWorker extends SwingWorker<Integer, Integer> { 

    /* 
    * 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); 
    } 

} 
+2

È possibile dare un'occhiata a [questa risposta] (http://stackoverflow.com/questions/8916721/java-swing-update-label/8917565#8917565) e confronta con il tuo codice. Il tutorial di Swing contiene anche un esempio (il collegamento è disponibile nella classe javadoc di 'JProgressBar') – Robin

risposta

12

Ecco una versione aggiornata del proprio 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 actionPerformed(ActionEvent e) { 
      new GuiWorker().execute(); 
      } 
     }); 
     button.setText("Test Me"); 
     frame.getContentPane().add(button); 
     frame.pack(); 
     frame.setVisible(true); 
     } 
    }); 

    } 
} 

class GuiWorker extends SwingWorker<Integer, Integer> { 

    /* 
    * 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(); 
    } 

} 

Punto chiave è l'impostazione di una finestra di dialogo del modello con blocchi visibili fino alla disposizione della finestra di dialogo. Quindi, impostandolo in modalità non modale, + la chiamata validate nel riquadro del contenuto quando si cambiano i componenti. Ho anche modificato il metodo principale per l'esecuzione su EDT e aggiunto alcune chiamate System.out. Se si rimuove la chiamata setModal(false), si vedrà che tali istruzioni non verranno stampate finché non si chiude la finestra di dialogo

+1

Grazie per averlo indicato! Credo che avrei dovuto cercare di vedere se esisteva un metodo 'setModal' in primo luogo. Ho anche preso nota del cambiamento in main, grazie per averlo indicato. Ho appena letto su di esso qui: http://java.sun.com/developer/technicalArticles/javase/swingworker/ Ho un problema con esso però, cambiando Modal a false, consente all'utente di fare clic sul pulsante più di una volta. – WilliamShatner

+0

@WilliamShatner: non è necessario rendere la finestra di dialogo non modale. Basta visualizzare la finestra di dialogo dopo aver avviato SwingWorker. Questo può essere fatto dalla classe 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. Nota che non puoi sovrascrivere 'execute()' dato che è definitivo. –

+1

@WilliamShatner è possibile disattivare il pulsante quando si avvia SwingWorker e riattivarlo in seguito – Robin

10

Non è necessario rendere la finestra di dialogo non modale. Basta visualizzare la finestra di dialogo dopo aver avviato SwingWorker. Questo può essere fatto dalla classe 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 è possibile 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 actionPerformed(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<Integer, Integer> { 
    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; 
    } 

} 
+0

d'accordo Posso vedere anche questo – mKorbel

+1

@Hovercraft L'esempio è stato ottimo. Testato e ha funzionato bene. Non ho molta familiarità con ciò che fa il codice, ma ho giocato con esso. Non mi piace anche aggiungere un'altra classe alla foto, ma sono contento che tu abbia postato questo. Votato :) – WilliamShatner

+0

@William: grazie per i commenti. Buona fortuna con il tuo progetto! –

Problemi correlati