简单的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(); } } 

我对这段代码有几个具体的问题:

  1. 我应该在哪里放置counter.start(); ? (在我的代码中,我把它放在2个位置。哪一个是正确的?)

  2. 为什么编译器会抱怨Runnable的构造函数? 它说我有一个无效的方法声明,我需要指定返回的类型。

补充:我做了建议的更正。 然后我执行代码并得到:

 Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException at Worker.run(Worker.java:12) 

在第12行的Worker.java中,我有: label.setText("You have " + i + " seconds.");

在runnable中调用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."); } } ); } } 

答案中的匿名例子非常有效。

至于第一个答案,计数器工作,但没有显示GUI,并在每一秒出现以下exception

 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)