Как должен работать простой обратный отсчет GUI?
Я пытаюсь написать простой обратный отсчет GUI. Я нашел в интернете какой-то код, но он уже слишком необычен для меня. Я стараюсь сделать это как можно проще. Итак, я просто хочу, чтобы у меня было окно с надписью "У вас осталось 10 секунд". Число секунд должно уменьшаться каждую секунду с 10 до 0. Я написал код. И я думаю, что я близок к рабочему решению. Но я все еще что-то упустил. Не могли бы вы помочь мне выяснить, что не так? Вот мой код:
import javax.swing.*;
public class Countdown {
static JLabel label;
// Method which defines the appearance of the window.
private static void showGUI() {
JFrame frame = new JFrame("Simple Countdown");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = new JLabel("Some Text");
frame.add(label);
frame.pack();
frame.setVisible(true);
}
// Define a new thread in which the countdown is counting down.
static Thread counter = new Thread() {
public void run() {
for (int i=10; i>0; i=i-1) {
updateGUI(i,label);
try {Thread.sleep(1000);} catch(InterruptedException e) {};
}
}
};
// A method which updates GUI (sets a new value of JLabel).
private static void updateGUI(final int i, final JLabel label) {
SwingUtilities.invokeLater(new Runnable(i,label) {
public Runnable(int i, JLabel label) {
this.i = i;
this.label = label;
}
public void run() {
label.setText("You have " + i + " seconds.");
}
});
}
// The main method (entry point).
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
showGUI();
//counter.start();
}
});
//counter.start();
}
}
И у меня есть несколько конкретных вопросов об этом коде:
Где я должен разместить
counter.start();
? (В моем коде я поставил его на 2 места. Какое из них правильное?)Почему компилятор жалуется на конструктор для Runnable? Это говорит о том, что у меня недопустимое объявление метода, и мне нужно указать возвращаемый тип.
ДОБАВЛЕНО: Я внес предложенные исправления. И тогда я выполняю код и получаю:
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at Worker.run(Worker.java:12)
В Worker.java в строке 12 у меня есть: label.setText("You have " + i + " seconds.");
,
2 ответа
Вызов counter.start()
внутри работающего:
// The main method (entry point).
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
showGUI();
counter.start();
}
});
}
Вы действительно хотите определенный порядок вызовов, если вы разместите его вне потока, то счетчик запустится еще до того, как GUI существует, и он не будет работать на вас.
По второму вопросу:
// A method which updates GUI (sets a new value of JLabel).
private static void updateGUI(final int i, final JLabel label) {
SwingUtilities.invokeLater(new Worker(i, label));
}
Вот рабочий:
import javax.swing.JLabel;
public class Worker implements Runnable{
private int i;
private JLabel label;
public Worker(int i, JLabel label) {
this.i = i;
this.label = label;
}
public void run() {
label.setText("You have " + i + " seconds.");
}
}
И ваша главная сейчас:
// The main method (entry point).
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
Countdown.showGUI();
counter.start();
}
});
}
ОБНОВИТЬ:
Или, если вы все еще хотите использовать анонимный шаблон, тогда:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
public class Countdown {
static JLabel label;
// Method which defines the appearance of the window.
public static void showGUI() {
JFrame frame = new JFrame("Simple Countdown");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
label = new JLabel("Some Text");
frame.add(label);
frame.pack();
frame.setVisible(true);
}
// Define a new thread in which the countdown is counting down.
public static Thread counter = new Thread() {
public void run() {
for (int i=10; i>0; i=i-1) {
updateGUI(i,label);
try {Thread.sleep(1000);} catch(InterruptedException e) {};
}
}
};
// A method which updates GUI (sets a new value of JLabel).
private static void updateGUI(final int i, final JLabel label) {
SwingUtilities.invokeLater(
new Runnable() {
public void run() {
label.setText("You have " + i + " seconds.");
}
}
);
}
}
Анонимный пример в ответе работает отлично.
Что касается 1-го ответа, счетчик работает, но графический интерфейс не отображается, и каждую секунду появляется следующее исключение
Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at com.aramco.ecc.licenseoptimizer.gui.Worker.run(Worker.java:23)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:209)
at java.awt.EventQueue.dispatchEvent(EventQueue.java:597)
at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269)
at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169)
at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161)
at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)