Вопрос по swing, jdialog, java, swingworker – Как мне заставить мой пример SwingWorker работать правильно?

16

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

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

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

Вот SSCCE:

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

}
</code>
Вы можете взглянуть наthis answer и сравните с вашим кодом. Учебник по Swing также содержит пример (ссылка доступна в классе javadoc:JProgressBar) Robin

Ваш Ответ

2   ответа
13

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 ) позвоните, вы увидите, что эти заявления не будут напечатаны, пока вы не закроете диалог

@ Робин Я думаю, что я придерживаюсь вашего метода, однако я не уверен, как бы я отключил кнопку изнутри ее собственного действия Выполнено, если кнопка не была глобальной? WilliamShatner
Спасибо, что указали на это! Я думаю, я должен был посмотреть, был лиsetModal Метод на первом месте. Я также принял к сведению изменение в основном, спасибо за указание на это. Я просто прочитал об этом здесь:java.sun.com/developer/technicalArticles/javase/swingworker  У меня есть одна проблема с этим, хотя, изменяя значение Modal на false, он позволяет пользователю нажимать кнопку более одного раза. WilliamShatner
@WilliamShatner: нет необходимости делать диалог немодальным. Просто откройте диалоговое окно после запуска SwingWorker. Это можно сделать либо из вызывающего класса, который выполняет SwingWorker, сначала вызвав команду execute, а затем показывая диалоговое окно, либо это можно сделать из SwingWorker, но если из последнего вам придется создать свой собственный метод псевдо-выполнения, который вызывает супер-выполнение, а затем показывает диалог. Обратите внимание, что вы не можете переопределитьexecute() сам, так как это окончательно.
@WilliamShatner вы можете отключить кнопку при запуске SwingWorker, а затем снова включить ее
@WilliamShatner Два решения: вы извлекаете кнопку из ActionEvent # getSource () или делаете кнопку окончательной
10

е окно после запуска SwingWorker. Это можно сделать либо из вызывающего класса, который выполняет SwingWorker, сначала вызвав команду execute, а затем показывая диалоговое окно, либо это можно сделать из SwingWorker, но если из последнего вам придется создать свой собственный метод псевдо-выполнения, который вызывает супер-выполнение, а затем показывает диалог. Обратите внимание, что вы не можете переопределить саму 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;
   }

}
@William: спасибо за комментарии. Желаем удачи в вашем проекте!
@ Ховеркрафт Пример был великолепен. Протестировал, и все заработало. Я не слишком знаком с тем, что делает весь код, но я играл с ним. Я также не очень люблю добавлять другой класс к изображению, но я рад, что вы опубликовали это. Проголосовал :) WilliamShatner
согласился я тоже это вижу
@HovercraftFullOfEels Вы были весьма полезны в каждом из моих постов, и я бы хотел предложить больше, чем просто спасибо. Я все еще учусь и, надеюсь, я смогу вернуться и полностью понять весь приведенный выше код. Я надеюсь, что вы будете в курсе будущих вопросов, потому что я знаю, что у меня будет гораздо больше. Еще раз спасибо! WilliamShatner
@HovercraftFullOfEels Не уверен, что тебя это волнует, но я просто хотел сказать, что твойpropertyChangeListener был отличным примером для нового проекта, который я только начал :) спасибо еще раз! WilliamShatner

Похожие вопросы