2012-04-19 6 views
15

Я сделал свой собственный пример SwingWorker, чтобы ознакомиться с тем, как он работает.Как я могу правильно использовать пример SwingWorker?

Что я хочу сделать, это следующее: Когда кнопка нажата, я хочу, чтобы индикатор выполнения отображался до завершения задачи. Я хочу просто удалить индикатор выполнения и добавить строку в диалог.

Когда кнопка нажата, индикатор выполнения появляется, но никогда не исчезает. (Никогда не удаляет индикатор через 10 секунд и никогда не ставит метку вверх)

Вот 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

Вы посмотрите на может [этот ответ] (http://stackoverflow.com/questions/8916721/java-swing-update-label/8917565#8917565) и сравнить с вашим кодом. Учебник Swing также содержит пример (ссылка доступна в классе javadoc 'JProgressBar') – Robin

ответ

12

Здесь обновленная версия кода, который работает

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

} 

Ключевой момент что установка диалогового окна модели видима до тех пор, пока диалог не будет удален. Поэтому, делая его немодальным, он фиксирует + validate, когда вы переключаете компоненты на панель содержимого. Я также скорректировал ваш основной метод для запуска на EDT и добавил некоторые вызовы System.out. Если вы удалите вызов setModal(false), вы увидите, что эти инструкции не печатаются, пока вы не закроете диалог.

+1

Спасибо, что указали это! Наверное, я должен был посмотреть, есть ли в первую очередь метод setModal. Я также принял к сведению изменение в главном, спасибо за указание на это. Я просто прочитал об этом здесь: http://java.sun.com/developer/technicalArticles/javase/swingworker/ У меня есть одна проблема с ним, хотя, изменяя Modal на false, он позволяет пользователю нажимать кнопку больше, чем один раз. – WilliamShatner

+0

@WilliamShatner: нет необходимости делать диалог немодальным. Просто запустите диалоговое окно после запуска SwingWorker. Это может быть сделано либо из вызывающего класса, либо из исполняющего SwingWorker, путем первого вызова execute, а затем отображения диалогового окна, или это можно сделать из SwingWorker, но если из последнего вы должны будете сделать свой собственный pseudo-execute, который вызывает выполнение super, а затем показывает диалог. Обратите внимание, что вы не можете переопределить 'execute()', так как это окончательно. –

+1

@WilliamShatner вы можете отключить кнопку при запуске SwingWorker и снова включить ее после этого – Robin

10

Не нужно делать диалог немодальным. Просто запустите диалоговое окно после запуска SwingWorker. Это может быть сделано либо из вызывающего класса, либо из исполняющего SwingWorker, путем первого вызова execute, а затем отображения диалогового окна, или это можно сделать из SwingWorker, но если из последнего вы должны будете сделать свой собственный pseudo-execute, который вызывает выполнение super, а затем показывает диалог. Обратите внимание, что вы не можете переопределить execute(), поскольку он является окончательным.

Например ...

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

согласен, я тоже вижу это – mKorbel

+1

@Hovercraft. Пример был замечательный. Протестировал его, и он работал красиво. Я не слишком хорошо знаком с тем, что делает весь код, но я играл с ним. Я тоже не слишком люблю добавлять на картине еще один класс, но я рад, что вы разместили это. Upvoted :) – WilliamShatner

+0

@William: спасибо за комментарии. Удачи вам в вашем проекте! –

Смежные вопросы