Сделать всплывающее окно с помощью SwingUtilities.invokeLater

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

class CustomBlockerDialog extends JDialog {
/**
 * 
 */
private static final long serialVersionUID = 1L;

public CustomBlockerDialog(Frame owner, String text) {
    super(owner, true);
    setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
    setSize(300, 100); // Adjust if needed
    setTitle("");
    add(new JLabel(text, SwingConstants.CENTER));
} 
}




final CustomBlockerDialog block = new CustomBlockerDialog(null, "Not your turn");

SwingUtilities.invokeLater(new Runnable() {//A

    @Override
    public void run() {
        System.out.println("show");
        block.setVisible(true);
    }
});


boolean one_write_only = true;
while(in.ready()){ /* C*/ 
    if(one_write_only){
        System.out.println("waiting server");
        one_write_only = false;
    }
};

System.out.println("suppose to hide");

SwingUtilities.invokeLater(new Runnable() {//B

    @Override
    public void run() {
    System.out.println("hide");
    block.setVisible(false);
    }
});

Похоже, "A" и "B" выполняются после "C", и я понятия не имею, почему.

2 ответа

Решение

Благодаря Hovercraft Full Of Eels я создал немного другое решение, которое работает в моем случае:

final SwingWorker<Object,Object> worker2 = new SwingWorker<Object, Object>() {
        public Object doInBackground() throws Exception {
          boolean one_write_only = true;
            while(!in.ready()){ /* C*/ 
              if(one_write_only){
                System.out.println("waiting server");
                one_write_only = false;
              }
            }
            return one_write_only;
        }

        protected void done() {
            try {
                block.setVisible(false);
            } catch (Exception ignore) {}
        }

};
worker2.execute();
block.setVisible(true);

Ваша проблема должна быть вызвана тем, что "C" вызывается в потоке событий Swing, а не в фоновом потоке, поскольку звучит так, будто "C" блокирует поток событий от запуска "A". Решение: убедитесь, что "C" не вызывается в потоке событий Swing. Также, если это так, и это можно проверить, запустив SwingUtilities.isEventDispatchThread() метод, тогда вам не нужны все эти другие runnables.

// note that this all must be called on the Swing event thread:
final CustomBlockerDialog block = new CustomBlockerDialog(null, "Not your turn");

System.out.println("show");
// block.setVisible(true);  // !! no this will freeze!

final SwingWorker<Void, Void> worker = new SwingWorker<>() {
   public void doInBackground() throws Exception {
      boolean one_write_only = true;
      while(in.ready()){ /* C*/ 
         if(one_write_only){
            System.out.println("waiting server");
            one_write_only = false;
         }
      }
   }
}

worker.addPropertyChangeListener(new PropertyChangeListener() {
   public void propertyChanged(PropertyChangeEvent pcEvt) {
      if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
         System.out.println("hide");
         block.setVisible(false);

         // call worker's get() method here and catch exceptions
      }
   }
});

worker.execute();

// moved to down here since the dialog is modal!!!
block.setVisible(true);

Предостережение: код не скомпилирован и не протестирован. Там могут быть ошибки, поскольку он был напечатан с манжеты.

Другие вопросы по тегам