Как уже упоминалось @Riduidel, важно, чтобы что-то связанное с Swing происходило в потоке диспетчеризации событий, или EDT
.Это потому, что Swing не является потокобезопасным.При вызове popup()
вы должны сделать следующее
if(SwingUtilities.isEventDispatchThread()){
Message.popup(...);
}
else{
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
Message.popup(...);
}
});
}
. Это обеспечит создание JFrame
на EDT
.Кроме того, из фрагмента кода, который вы разместили, может показаться, что Message
должен иметь приватный конструктор.Кроме того, поскольку вы не выполняете никакой пользовательской визуализации, почему бы просто не создать переменную-член JFrame
вместо расширения класса?- мне кажется немного излишним.
В любом случае, вы также никогда не должны sleep
в EDT
, так как это заставит GUI казаться «зависшим» и блокировать выполнение других событий в очереди.При выполнении длительных задач используйте SwingWorker
или, как упоминалось @Riduidel, javax.swing.Timer
.Но если вы предпочитаете использовать java.util.Timer
, используйте служебный класс SwingUtilities
, как показано выше, чтобы опубликовать задачу Runnable
на EventQueue
, которая будет выполнена вEDT
.
РЕДАКТИРОВАТЬ
Вот что я бы сделал (и да, это работает)
public class Message {
// Private constructor to prevent external instantiation
private Message(){
}
public static void createAndShowDialog(final String content, final int time){
final JDialog dialog = new JDialog();
dialog.setLayout(new BorderLayout());
dialog.setUndecorated(true);
JLabel label = new JLabel(content);
label.setFont(new Font("Monospaced", Font.BOLD, 20));
Box b = Box.createHorizontalBox();
b.add(Box.createHorizontalGlue());
b.add(label, BorderLayout.CENTER);
b.add(Box.createHorizontalGlue());
dialog.add(b);
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
// kick-off timer
Timer t = new Timer(time, new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
dialog.dispose();
}
});
t.setRepeats(false);
t.start();
}
}
И где бы вы ни вызывалиcreateAndShowDialog(...)
, сделайте следующее
SwingUtilities.invokeLater(new Runnable(){
@Override
public void run(){
Message.createAndShowDialog("Content", 5000); // wait 5 seconds before disposing dialog
}
});