1

我制作了 CountDown.java 文件并尝试添加我的 Word-trouble.java 文件(这是主小程序),CountDown ct = new CountDown(); 但它没有在主小程序中显示计时器。

这是编码:

package pack.urdu;
import java.awt.*; //windows toolkit

import java.applet.*; //applet support

public class CountDown extends Applet implements Runnable{

int counter; Thread cd;

public void start() { // create thread

counter = 60; cd = new Thread(this); cd.start();

}

public void stop() { cd = null;}

public void run() {  // executed by Thread

while (counter>0 && cd!=null) {

try{Thread.sleep(1000);} catch (InterruptedException e){}

--counter; repaint(); //update screen

}

}

public void paint(Graphics g) {

g.drawString(String.valueOf(counter),25,75);

}

}
4

1 回答 1

0

您犯了一个我看到很多程序员犯的错误:您将经过时间的计算与刷新时间的计算混为一谈。如果由于线程争用而导致睡眠持续时间超过一秒,您的计时器将会漂移。

无需跟踪每秒递增的计数器,只需记录开始时间:

long startTime = System.currentTimeMillis();

然后,您的绘画方法变为:

public void paint(Graphics g) {
    int elapsedSeconds = (int)(System.currentTimeMillis()-startTime)/1000
    g.drawString(String.valueOf(elapsedSeconds),25,75);
}

这个方法可以被多次调用,只要你喜欢,它总是会显示正确的经过的秒数。无需在任何指定时间增加任何内容。

您唯一需要做的就是安排刷新屏幕。(我想说你只需要在用户查看屏幕时刷新屏幕 :-) 但因为我们不知道我们需要更频繁地刷新)。其机制可能取决于图形库。一个懒惰的想法是每秒刷新十次,屏幕大部分时间都是正确的。

如果您确实希望有一个发送重绘事件的线程,您应该在计时器点击到新值时发送这些事件,从而每秒只发送一个。这是通过以下方式完成的:

while (stillRunning) {
    long elapsedTime = System.currentTimeMillis() - startTime;
    long timeTillNextDisplayChange = 1000 - (elapsedTime % 1000);
    Thread.sleep(timeTillNextDisplayChange);
    repaint();
}

请注意,您不要睡眠 1000 毫秒!如果您的系统运行良好,这将非常接近 1000 毫秒,但略低于(1)线程启动延迟,可能是由线程争用引起的,以及(2)此循环的处理时间(即相当小)。在任何情况下,以这种方式计算睡眠将防止计时器漂移,并确保您的显示随着秒值的变化而更新。

在我的网站上查看对定时器的常见误解的扩展讨论。

于 2013-01-15T07:37:02.803 回答