英文:
Java Thread.sleep/ Timer/ TimeUnit not working
问题
我遇到了一个我正在做的有趣小项目的一些问题:我试图实现的是在输出字符串之间延迟几秒钟,因此每次绘制一个字符(转换为字符串),以便产生有人在键入的假象(在JFrame中)。然而,似乎for循环(请参见下文)首先执行要等待的总时间,然后一次性绘制整个字符串,无论我使用哪种尝试的解决方案(try和catch + Thread.sleep
,TimeUnit
或java.swing.timer
和java.awt.timer
)。
这仍然是我在Java中的最初项目之一,所以如果代码很混乱,我深感抱歉。Stackoverflow上没有任何现有的解决方案对我有所帮助。
编辑:错误消息(可能与此无关)告诉我,变量n应该声明为final,因为其作用域不足。但在这种情况下不起作用。
在这个工作部分中仍然存在问题:a)每个字符都显示在相同的位置,而不是增加x值;b)有些字符被跳过(或在它们以三个一组出现之前被跳过)。以下是代码:
AtomicInteger animationState = new AtomicInteger(0);
@Override
public void paintComponent(Graphics maler) {
super.paintComponent(maler);
maler.setColor(Color.WHITE);
maler.fillRect(0, 0, 600, 600);
maler.drawImage(bildchen, 37, 30, this);
maler.setColor(Color.BLACK);
maler.fillRect(0, 0, 600, 600);
maler.setColor(new Color(32, 194, 14));
Font kram = new Font("OCR A Extended", Font.BOLD, 40);
maler.setFont(kram);
int p = 90;
String text = "WILLKOMMEN!";
maler.drawString(Character.toString(text.charAt(animationState.get())), p, 200);
runAnimation();
}
Timer timer = new Timer();
void runAnimation() {
TimerTask task = new TimerTask() {
public void run() {
if (animationState.get() < 11) {
animationState.incrementAndGet();
repaint();
} else {
cancel();
}
}
};
timer.scheduleAtFixedRate(task, 500, 500);
}
以上是您要翻译的内容。
英文:
I am having some trouble with a fun little side project of mine: What I am trying to achieve is a delay of some seconds in between the output of a string and therefore drawing one character (converted to String) at a time, in order to give the illusion of someone typing it (in a JFrame). However it seems like the for-loop (see below), first executes the total added time to wait and then draws the whole string at once, no matter which of the tried solutions i use (try and catch + Thread.sleep
, TimeUnit
or java.swing.timer
and java.awt.timer
).
This is still one of my very first projects in java, so I do apologize if the code is a total mess. None of the pre-existing solutions on stackoverflow have helped me so far.
EDIT: The error message (probably unrelated) tells me by the way that the variable n should be declared final, because its scope isn't sufficient. This wouldn't work in this context.
@Override
public void paintComponent(Graphics maler) {
super.paintComponent(maler);
maler.setColor(Color.WHITE);
maler.fillRect(0, 0, 600, 600);
maler.drawImage(bildchen, 37, 30, this);
maler.setColor(Color.BLACK);
maler.fillRect(0, 0, 600, 600);
maler.setColor(new Color(32, 194, 14));
Font kram = new Font("OCR A Extended", Font.BOLD, 40);
maler.setFont(kram);
String text = "WILLKOMMEN!";
final int n = 0;
int p = 90;
for (int i= 0; i<=10; i++) {
Timer timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
maler.drawString(Character.toString(text.charAt(n)), p, 200);
}
};
timer.scheduleAtFixedRate(task, 1000, 1000);
p = p+34;
n++;
}
In this working part there still persists the problem that a) every characacter is displayed on the same spot instead of increasing x value; b) some characters are skipped over (or before they've been appearing in pairs of three). Here's the code:
AtomicInteger animationState = new AtomicInteger(0);
@Override
public void paintComponent(Graphics maler) {
super.paintComponent(maler);
maler.setColor(Color.WHITE);
maler.fillRect(0, 0, 600, 600);
maler.drawImage(bildchen, 37, 30, this);
maler.setColor(Color.BLACK);
maler.fillRect(0, 0, 600, 600);
maler.setColor(new Color(32, 194, 14));
Font kram = new Font("OCR A Extended", Font.BOLD, 40);
maler.setFont(kram);
int p = 90;
String text = "WILLKOMMEN!";
maler.drawString(Character.toString(text.charAt(animationState.get())), p, 200);
runAnimation();
}
Timer timer = new Timer();
void runAnimation() {
TimerTask task = new TimerTask() {
public void run() {
if (animationState.get(
) < 11) {
animationState.incrementAndGet();
repaint();
} else {
cancel();
}
}
};
timer.scheduleAtFixedRate(task, 500, 500);
}
答案1
得分: 1
你尝试制作动画的方式基本上是错误的,不幸的是。
要正确制作动画,你需要以某种方式存储动画的当前状态,并在paintComponent
绘制时使用动画的状态。
在这种情况下,你只是在为“WILLKOMMEN”文本的外观添加动画效果,所以你需要的状态只是一个数字:应该绘制多少个字母。AtomicInteger
对象适用于这种情况,因此添加一个AtomicInteger
实例变量,并在paintComponent
中使用它:
AtomicInteger animationState = new AtomicInteger(0);
@Override
protected void paintComponent(Graphics maler) {
super.paintComponent(maler);
String text = "WILLKOMMEN!";
int p = 90;
maler.drawString(text.substring(0, animationState.get()), p, 200);
}
要实际使组件动起来,你需要定期改变动画状态并使组件重新绘制。这可以通过定时器线程来完成。在这种情况下,你可以调用incrementAndGet
方法将animationState
更改为animationState + 1
,然后调用repaint
方法来显示更新状态。
Timer timer = new Timer();
void runAnimation() {
TimerTask task = new TimerTask() {
public void run() {
if (animationState.get() < 10) {
animationState.incrementAndGet();
repaint();
} else {
cancel();
}
}
};
timer.scheduleAtFixedRate(task, 1000, 1000);
}
当你想要开始动画时,调用runAnimation
方法。
英文:
The way you are trying to make an animation is fundamentally wrong, unfortunately.
For the right way to make an animation, you need to store the current state of the animation in some way, and make paintComponent
use the state of the animation when it's painting.
In this case you're animating only the appearance of the text WILLKOMMEN, so the state you need is just a number: how many letters should be painted. An AtomicInteger
object works well for this, so add an AtomicInteger
instance variable, and use it from paintComponent:
AtomicInteger animationState = new AtomicInteger(0);
@Override
protected void paintComponent(Graphics maler) {
super.paintComponent(maler);
String text = "WILLKOMMEN!";
int p = 90;
maler.drawString(text.substring(0, animationState.get()), p, 200);
}
To actually get the component to animate, you need to periodically change the animation state and make the component repaint itself. This can be done from a timer thread. In this case, you can call the incrementAndGet
method to change animationState to animationState + 1, and then call the repaint()
method to show the update state.
Timer timer = new Timer();
void runAnimation() {
TimerTask task = new TimerTask() {
public void run() {
if (animationState.get() < 10) {
animationState.incrementAndGet();
repaint();
} else {
cancel();
}
}
};
timer.scheduleAtFixedRate(task, 1000, 1000);
}
When you want the animation to start, you call the runAnimation
method.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论