Сделать всплывающее окно с помощью 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);
Предостережение: код не скомпилирован и не протестирован. Там могут быть ошибки, поскольку он был напечатан с манжеты.