在“猜测”中
我不喜欢猜测,但似乎我们不会得到一个可运行的示例来清楚地了解问题是如何产生的。
证据...
我确实调用了超级绘制方法,但在绘制方法中。我知道这很好,因为我所有的其他图形都可以正常工作。
这“表明”timer 被称为正常 Swing“绘制”周期的一部分。如果这是真的,它解释了问题的原因。
这...
public void timer (Graphics g,int x){
x=550;
for (int i = time;i>0;i--){
g.setColor(deepPlum);
g.setFont(new Font("Monospaced", Font.PLAIN, 25));
g.drawString("time: "+i, x, 650);
repaint();
}
}
只是在每次绘制周期发生时将所有数字相互绘制,这实际上不是倒计时计时器应该绘制的方式。
相反,它应该简单地绘制剩余时间,单个值,而不是尝试绘制所有时间。
您可以将“绘制周期”视为“帧”,它绘制组件当前状态的快照。您需要绘制许多这样的“帧”,以便为从一个时间点到另一个时间点的变化设置动画。
我再次强烈建议您花时间阅读Performing Custom Painting 和Painting in AWT and Swing,以更好地了解绘画的实际工作原理。
如果没有更多证据,我建议,Swing Timer 将是更好的解决方案。这可用于计算剩余时间并定期安排repaint。
因为我似乎经常做这种事情,所以我将核心功能封装成一个简单的Counter 类,它有一个“持续时间”(或运行时),可以计算出它一直在运行的duration, remaining 时间和 progress 占 duration 和 runTime 的百分比,可能比您需要的更多,但它为您提供了开始的基础。
因为绘画是一种不精确的艺术(绘画周期之间的时间是可变的,即使使用Timer),我使用了基于“时间”的方法,而不是简单的“计数器”。在处理这些类型的场景时,这为您提供了更高水平的精确度
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
// The following two lines just set up the
// "default" size of the frame
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JComponent {
private Counter counter;
public TestPane() {
Timer timer = new Timer(1000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (counter == null) {
counter = new Counter(Duration.of(10, ChronoUnit.SECONDS));
counter.start();
}
repaint();
}
});
timer.start();
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (counter != null) {
Graphics2D g2d = (Graphics2D) g.create();
FontMetrics fm = g2d.getFontMetrics();
long time = counter.getRemaining().getSeconds();
int x = (getWidth() - fm.stringWidth(Long.toString(time))) / 2;
int y = ((getHeight() - fm.getHeight()) / 2) + fm.getAscent();
g2d.drawString(Long.toString(time), x, y);
g2d.dispose();
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
}
public static class Counter {
private Duration length;
private LocalDateTime startedAt;
public Counter(Duration length) {
this.length = length;
}
public Duration getLength() {
return length;
}
public void start() {
startedAt = LocalDateTime.now();
}
public void stop() {
startedAt = null;
}
public Duration getDuration() {
if (startedAt == null) {
return null;
}
Duration duration = Duration.between(startedAt, LocalDateTime.now());
if (duration.compareTo(getLength()) > 0) {
duration = getLength();
}
return duration;
}
public Double getProgress() {
if (startedAt == null) {
return null;
}
Duration duration = getDuration();
return Math.min(1.0, (double) duration.toMillis() / length.toMillis());
}
public Duration getRemaining() {
if (startedAt == null) {
return null;
}
Duration length = getLength();
Duration time = getDuration();
LocalDateTime endTime = startedAt.plus(length);
LocalDateTime runTime = startedAt.plus(time);
Duration duration = Duration.between(runTime, endTime);
if (duration.isNegative()) {
duration = Duration.ZERO;
}
return duration;
}
}
}
在有人告诉我clearRect 将如何解决问题之前,请务必注意clearRect 将做两件事。一,它只会显示循环的“最后”值,这显然不是OP想要的,它会用Graphics上下文的当前背景颜色填充指定区域,“可能”不是什么OP 想要的(因为它会在之前绘制的其他内容的顶部绘制一个漂亮的矩形)。
如果使用得当,Swing 绘制系统会在调用组件的paint 方法之前准备好Graphics 上下文,从而需要使用clearRect 静音