setvisible метод в системе зависания Java - PullRequest
6 голосов
/ 11 декабря 2010

У меня есть приложение для банковского графического интерфейса, над которым я сейчас работаю, и, похоже, проблема с методом setvisible для моего jdialog. После того, как пользователь снял действительную сумму, я выскакиваю в простое диалоговое окно с надписью «транзакция в процессе». В моем методе dobackground я продолжаю опрос, чтобы проверить, была ли получена транзакция. Я попытался использовать Swingworker, и я не понимаю, почему это не работает. Если я удаляю вызов setvisible, он работает нормально, так почему setvisible вызывает зависание системы? Вот код, который находится внутри моего мышиного прослушивателя jbutton:

SwingWorker<String,Integer> worker = new SwingWorker<String,Integer>(){

  JDialog waitForTrans = new JDialog((JFrame)null,true);
  public String doInBackground() throws Exception {
     waitForTrans.add(new JLabel("Updating balance in system. Please Wait..."));
     waitForTrans.setMinimumSize(new Dimension(300,100));
     waitForTrans.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
     waitForTrans.setVisible(true);
     Bank.getInstance().sendTransaction(currentPin,"-"+withdraw);
     while(!Bank.getInstance().hasCompletedTransaction){

     }
     return null;

  }

  public void done(){
   try {
        this.get();
       } catch (InterruptedException e) {
        e.printStackTrace();
    } catch (ExecutionException e) {

        e.printStackTrace();
    }
    waitForTrans.setVisible(false);
    newField.setText(String.valueOf(Bank.getInstance().getAccountList().get(currentPin).getBalance()));
  }

 };
 worker.execute();

Ответы [ 4 ]

14 голосов
/ 11 декабря 2010

Во-первых, рекомендуется выполнить все обновления графического интерфейса в потоке событий Event Swing, т. Е. С использованием класса SwingUtilites.

Во-вторых, ваш JDialog является модальным и поэтому блокирует поток вкоторый вызывается методом setVisible(true) (в вашем случае это основной поток, в следующем случае - поток обработки событий Swing).

Я не говорю, что следующий код идеален, но он должен поставить вас натрек ...


final JDialog waitForTrans = new JDialog((JFrame) null, true);

SwingWorker worker = new SwingWorker() {

  public String doInBackground() throws Exception {
    Thread.sleep(5000);
    return null;
  }

  public void done() {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        waitForTrans.setVisible(false);
        waitForTrans.dispose();
      }
    });
  }

};

worker.execute();
SwingUtilities.invokeLater(new Runnable() {
  public void run() {
    waitForTrans.add(new JLabel("Please Wait..."));
    waitForTrans.setMinimumSize(new Dimension(300, 100));
    waitForTrans.setVisible(true);
  }
});

Надеюсь, это поможет.

5 голосов
/ 11 декабря 2010

Вы отображаете модальное диалоговое окно, поэтому фоновый код не может выполняться до тех пор, пока диалоговое окно не будет закрыто.

Добавьте оператор System.out.println (...) после setVisible, и вы увидите егоникогда не выполняется.

1 голос
/ 11 декабря 2010

setVisible - это метод, который влияет на GUI, вызывая что-то, что отображается (и, в случае модального диалога, подобного вашему, блокируется до закрытия диалога). Он (как и все, что изменяет видимый интерфейс) должен никогда не вызываться , кроме как в потоке диспетчеризации событий Swing. Вы вызываете его из doInBackground метода SwingWorker, который выполняется в фоновом потоке.

Чтобы исправить это, нужно сделать из waitForClose переменную final, которую вы создаете перед вызовом execute для SwingWorker, а затем сразу вызвать setVisible после начинающий рабочий.

final JDialog waitForTrans = ...
// set up the dialog here

SwingWorker<String, Integer> worker = new SwingWorker<String, Integer>() {
  ...
};
worker.execute(); // start the background process

waitForTrans.setVisible(true); // show the dialog

Вам нужно сделать это в этом порядке, потому что в противном случае модальное диалоговое окно заблокирует вас от запуска работника.

0 голосов
/ 11 декабря 2010

camickr дает вам правильный ответ. Я хочу добавить, что вы не можете изменять пользовательский интерфейс вне нити рассылки событий (как вы делаете в #doInBackground), Swing является однопоточным, поэтому нарушение этого правила может привести к очень хитрые ошибки и странные вещи в вашем интерфейсе.

...