Java的Thread.sleep/ Timer/ TimeUnit不起作用。

huangapple go评论82阅读模式
英文:

Java Thread.sleep/ Timer/ TimeUnit not working

问题

我遇到了一个我正在做的有趣小项目的一些问题:我试图实现的是在输出字符串之间延迟几秒钟,因此每次绘制一个字符(转换为字符串),以便产生有人在键入的假象(在JFrame中)。然而,似乎for循环(请参见下文)首先执行要等待的总时间,然后一次性绘制整个字符串,无论我使用哪种尝试的解决方案(try和catch + Thread.sleepTimeUnitjava.swing.timerjava.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(&quot;OCR A Extended&quot;, Font.BOLD, 40);
	maler.setFont(kram);
	
	
	String text = &quot;WILLKOMMEN!&quot;;
	final int  n = 0;
	int p = 90; 
	
	
	
	for (int i= 0; i&lt;=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(&quot;OCR A Extended&quot;, Font.BOLD, 40);
	maler.setFont(kram);
	
	int p = 90; 
	String text = &quot;WILLKOMMEN!&quot;;
	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(
		            		) &lt; 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 = &quot;WILLKOMMEN!&quot;;
    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() &lt; 10) {
                animationState.incrementAndGet();
                repaint();
            } else {
                cancel();
            }
        }
    };
    timer.scheduleAtFixedRate(task, 1000, 1000);
}

When you want the animation to start, you call the runAnimation method.

huangapple
  • 本文由 发表于 2020年8月26日 23:45:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/63601142.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定