【发布时间】:2018-07-30 23:35:33
【问题描述】:
你们中的任何一位 FX 大师能告诉我为什么这段代码似乎会冻结 FX 屏幕更新吗?循环继续在动画线程中运行,但一段时间后屏幕停止更新。
顺便说一句,我知道以这种方式使用 Thread.sleep 可能会让一些人感到不安,但这是为学生在入门课程中编写的代码,允许他们在不进行任何事件处理的情况下创建动画。
学生的练习是转换动画,使其反弹一个由 100 个随机方向移动的球组成的数组。转换后,冻结往往比单球早得多。
提前致谢!
这是主要的类...
package week6code;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
/**
* Bouncing Balls exercise starter
*
* @author Sam Scott
*/
public class BouncingBalls extends Application {
/**
* Sets up the stage and starts the main thread. Your drawing code should
* NOT go here.
*
* @param stage The first stage
*/
@Override
public void start(Stage stage) {
stage.setTitle("Bouncing Balls!"); // window title here
Canvas canvas = new Canvas(400, 300); // canvas size here
Group root = new Group();
Scene scene = new Scene(root);
root.getChildren().add(canvas);
stage.setScene(scene);
stage.show();
GraphicsContext gc = canvas.getGraphicsContext2D();
// This code starts a "thread" which will run your animation
Thread t = new Thread(() -> animate(gc));
t.start();
}
/**
* Animation thread. This is where you put your animation code.
*
* @param gc The drawing surface
*/
public void animate(GraphicsContext gc) {
// YOUR CODE HERE!
// intial positions and speeds
Ball ball = new Ball(100, 50, -1, -1, 10, Color.RED);
while (true) // loop forever
{
// draw screen
gc.setFill(Color.YELLOW);
gc.fillRect(0, 0, 400, 300);
ball.draw(gc);
// moving
ball.moveOneStep();
// bouncing
if (ball.getX() <= 0 || ball.getX() >= 400 - (ball.getSize() - 1)) {
ball.bounceX();
}
if (ball.getY() <= 0 || ball.getY() >= 300 - (ball.getSize() - 1)) {
ball.bounceY();
}
// pause
pause(1000 / 60);
}
}
/**
* Use this method instead of Thread.sleep(). It handles the possible
* exception by catching it, because re-throwing it is not an option in this
* case.
*
* @param duration Pause time in milliseconds.
*/
public static void pause(int duration) {
try {
Thread.sleep(duration);
} catch (InterruptedException ex) {
}
}
/**
* Exits the app completely when the window is closed. This is necessary to
* kill the animation thread.
*/
@Override
public void stop() {
System.exit(0);
}
/**
* Launches the app
*
* @param args unused
*/
public static void main(String[] args) {
launch(args);
}
}
这是 Ball 类。
package week6solutions;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
/**
* An example of an object that can draw and move itself.
*
* @author Sam Scott
*/
public class Ball {
private double x, y, xSpeed, ySpeed;
private final int size;
private final Color c;
/**
* Creates a Ball instance.
*
* @param x Initial x position (left)
* @param y Initial y position (top)
* @param xSpeed Number of pixels to move horizontally in each step
* (negative for left, positive for right)
* @param ySpeed Number of pixels to move vertically in each step (negative
* for up, positive for down)
* @param size Diameter of ball
* @param c Color of ball
*/
public Ball(double x, double y, double xSpeed, double ySpeed, int size, Color c) {
this.x = x;
this.y = y;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.size = size;
this.c = c;
}
/**
* Increment x and y using the values of xSpeed and ySpeed
*/
public void moveOneStep() {
x += xSpeed;
y += ySpeed;
}
/**
* Reverses the x direction by multiplying it by -1
*/
public void bounceX() {
xSpeed *= -1;
}
/**
* Reverses the y direction by multiplying it by -1
*/
public void bounceY() {
ySpeed *= -1;
}
/**
* Draw the ball in its current location on a Graphics object
*
* @param g The GraphicsContext object to draw on
*/
public void draw(GraphicsContext g) {
g.setFill(c);
g.fillOval((int) Math.round(x), (int) Math.round(y), size, size);
}
/**
* @return the current x location
*/
public double getX() {
return x;
}
/**
* @return the current y location
*/
public double getY() {
return y;
}
/**
* @return the size of the ball
*/
public int getSize() {
return size;
}
}
【问题讨论】:
-
最好的方法是使用
JavaFX'sAnimation类的东西。我的经验法则是,当任务长时间运行但与GUI无关时,使用Thread。当任务长时间运行并使用GUI时,使用Animation。 -
感谢您迄今为止的回复,但正如我所说,我不是在寻找“正确”的方式来做到这一点。我之所以选择这种方法,是因为这对我的学生目前正在接受教育是正确的(他们对循环和学习基本的 OO 感到满意,但还没有接触过事件驱动的编程)。但我很困惑为什么它似乎会在一段时间后冻结 FX 屏幕更新。
-
刚刚运行了您的代码。它在我的机器上运行良好。您经历冻结需要多长时间?
-
哦,也许你的问题是由于没有使用
Platform.runlater();从Thread更新GUI。
标签: java multithreading animation javafx