JavaFX AnimationTimer以超过60 fps的速度运行
简短描述:运行一个简单的JavaFX程序 演示了AnimationTimer导致我的电脑几乎锁定 向上的该程序在其他电脑和我的电脑上运行良好 使用其他版本的Linux启动。详细说明 接着 在校对新版本的在线Java教科书时 我在运行书中的示例程序时遇到了一个问题 这说明了JavaFXAnimationTimer。程序源 是SimpleAnimationTimer.java。见下文。这是一个非常简单的问题 仅显示当前帧编号和 已用时间(以秒为单位)。预期的输出是 “每秒60帧”;即,显示的帧编号 除以显示的经过时间应为60 在我的电脑上编译和运行时,它会淹没应用程序 窗口太大,我几乎无法移动鼠标 另一个窗口,以便我可以终止运行的程序。什么时候 我通知了这本书的作者,他回答说 在他所有的电脑(Ubuntu、LinuxMint、Mac、Windows)上运行良好。 我的电脑正在运行Fedora27 我从一个实时USB下载并运行了最新的Linux Mint, 然后在那里使用与使用的Java相同的Java测试程序 给27号软呢帽。程序在那里运行没有错误 接下来,我重新启动了一个旧的Fedora24并测试了程序 那里它运行正常 我从一个实时USB下载并运行Fedora28。这个 程序有问题 我的测试环境和结果的摘要 Java版本是1.8.0_181。这是来自甲骨文的 Linux Mint 19内核4.15.0-20-generic。没问题 Fedora24内核4.11.12。没问题 Fedora27内核4.17.17。有问题 Fedora28内核4.16.3。有问题 看起来Linux内核之间发生了一些变化 导致问题的版本4.15和4.16 修改了原始SimpleAnimationStarter.java源代码 在60帧后停止。Test02SimpleAnimationStarter.java 如下所示的源代码就是这样做的。运行此程序时 显示的帧数为60,与预期一致,显示的 运行时间为0.3秒,而不是预期的1秒 目前我不知该怎么办。这是吗 JavaFX问题?这是Linux内核的问题吗?某物 还有别的吗 如有任何建议/意见,将不胜感激。也, 运行这两个程序时看到结果会很好 在其他平台上——Windows、Mac和其他Linux版本 警告:首先运行Test02版本!确保时间已过 时间是一秒钟 消息来源如下。首先是SimpleAnimationStarter.java,然后是 Test02SimpleAnimationStarter.javaJavaFX AnimationTimer以超过60 fps的速度运行,java,linux,javafx,Java,Linux,Javafx,简短描述:运行一个简单的JavaFX程序 演示了AnimationTimer导致我的电脑几乎锁定 向上的该程序在其他电脑和我的电脑上运行良好 使用其他版本的Linux启动。详细说明 接着 在校对新版本的在线Java教科书时 我在运行书中的示例程序时遇到了一个问题 这说明了JavaFXAnimationTimer。程序源 是SimpleAnimationTimer.java。见下文。这是一个非常简单的问题 仅显示当前帧编号和 已用时间(以秒为单位)。预期的输出是 “每秒60帧”;即,显示的帧编号
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.layout.BorderPane;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
/**
* This file can be used to create very simple animations. Just fill in
* the definition of drawFrame with the code to draw one frame of the
* animation, and possibly change a few of the values in the rest of
* the program as noted below.
*/
public class SimpleAnimationStarter extends Application {
/**
* Draws one frame of an animation. This subroutine should be called
* about 60 times per second. It is responsible for redrawing the
* entire drawing area. The parameter g is used for drawing. The frameNumber
* starts at zero and increases by 1 each time this subroutine is called.
* The parameter elapsedSeconds gives the number of seconds since the animation
* was started. By using frameNumber and/or elapsedSeconds in the drawing
* code, you can make a picture that changes over time. That's an animation.
* The parameters width and height give the size of the drawing area, in pixels.
*/
public void drawFrame(GraphicsContext g, int frameNumber, double elapsedSeconds, int width, int height) {
/* NOTE: To get a different animation, just erase the contents of this
* subroutine and substitute your own.
*/
g.setFill(Color.WHITE);
g.fillRect(0, 0, width, height); // First, fill the entire image with a background color!
g.setFill(Color.BLACK);
g.fillText( "Frame number " + frameNumber, 40, 50 );
g.fillText( String.format("Elapsed Time: %1.1f seconds", elapsedSeconds), 40, 80);
}
//------ Implementation details: DO NOT EXPECT TO UNDERSTAND THIS ------
private int frameNum;
private long startTime;
public void start(Stage stage) {
int width = 800; // The width of the image. You can modify this value!
int height = 600; // The height of the image. You can modify this value!
Canvas canvas = new Canvas(width,height);
drawFrame(canvas.getGraphicsContext2D(), 0, 0, width, height);
BorderPane root = new BorderPane(canvas);
root.setStyle("-fx-border-width: 4px; -fx-border-color: #444");
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Simple Animation"); // STRING APPEARS IN WINDOW TITLEBAR!
stage.show();
stage.setResizable(false);
AnimationTimer anim = new AnimationTimer() {
public void handle(long now) {
if (startTime < 0)
startTime = now;
frameNum++;
drawFrame(canvas.getGraphicsContext2D(), frameNum, (now-startTime)/1e9, width, height);
}
};
startTime = -1;
anim.start();
}
public static void main(String[] args) {
launch();
}
} // end SimpleAnimationStarter
import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.scene.layout.BorderPane;
import javafx.scene.Scene;
import javafx.stage.Stage;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.paint.Color;
/**
* This file can be used to create very simple animations. Just fill in
* the definition of drawFrame with the code to draw one frame of the
* animation, and possibly change a few of the values in the rest of
* the program as noted below.
*/
public class Test02SimpleAnimationStarter extends Application {
/**
* Draws one frame of an animation. This subroutine should be called
* about 60 times per second. It is responsible for redrawing the
* entire drawing area. The parameter g is used for drawing. The frameNumber
* starts at zero and increases by 1 each time this subroutine is called.
* The parameter elapsedSeconds gives the number of seconds since the animation
* was started. By using frameNumber and/or elapsedSeconds in the drawing
* code, you can make a picture that changes over time. That's an animation.
* The parameters width and height give the size of the drawing area, in pixels.
*/
public void drawFrame(GraphicsContext g, int frameNumber, double elapsedSeconds, int width, int height) {
/* NOTE: To get a different animation, just erase the contents of this
* subroutine and substitute your own.
*/
g.setFill(Color.WHITE);
g.fillRect(0, 0, width, height); // First, fill the entire image with a background color!
g.setFill(Color.BLACK);
g.fillText( "Frame number " + frameNumber, 40, 50 );
g.fillText( String.format("Elapsed Time: %1.1f seconds", elapsedSeconds), 40, 80);
}
//------ Implementation details: DO NOT EXPECT TO UNDERSTAND THIS ------
private int frameNum;
private long startTime;
AnimationTimer anim = null; // Moved outside start() so handle() can call anim.stop()
public void start(Stage stage) {
int width = 800; // The width of the image. You can modify this value!
int height = 600; // The height of the image. You can modify this value!
Canvas canvas = new Canvas(width,height);
drawFrame(canvas.getGraphicsContext2D(), 0, 0, width, height);
BorderPane root = new BorderPane(canvas);
root.setStyle("-fx-border-width: 4px; -fx-border-color: #444");
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Simple Animation"); // STRING APPEARS IN WINDOW TITLEBAR!
stage.show();
stage.setResizable(false);
// AnimationTimer anim = new AnimationTimer() {
anim = new AnimationTimer() {
// Constants: change NUM_SECS and/or framesPerSec
private final int NUM_SECS = 1; // Desired number of seconds.
private final int framesPerSec = 60; // Expected frames per second.
private final int NUM_FRAMES = NUM_SECS*framesPerSec;
public void handle(long now) {
if (startTime < 0)
startTime = now;
frameNum++;
if (frameNum < NUM_FRAMES+1)
{
drawFrame(canvas.getGraphicsContext2D(),
frameNum,
(now-startTime)/1e9,
width, height);
}
else if (frameNum == NUM_FRAMES+1)
{
anim.stop();
System.out.println("Animation stopped");
}
else if (frameNum == NUM_FRAMES+2)
{
System.out.println("Animation kept going after stop ???");
}
}
};
startTime = -1;
anim.start();
}
public static void main(String[] args) {
launch();
}
} // end Test02SimpleAnimationStarter
导入javafx.animation.AnimationTimer;
导入javafx.application.application;
导入javafx.scene.layout.BorderPane;
导入javafx.scene.scene;
导入javafx.stage.stage;
导入javafx.scene.canvas.canvas;
导入javafx.scene.canvas.GraphicsContext;
导入javafx.scene.paint.Color;
/**
*此文件可用于创建非常简单的动画。只需填写
*drawFrame的定义,代码用于绘制
*动画,并可能更改其余部分中的一些值
*该计划如下所述。
*/
公共类SimpleAnimationStarter扩展了应用程序{
/**
*绘制动画的一帧。应调用此子例程
*大约每秒60次。它负责重新绘制
*整个绘图区域。参数g用于绘图。帧编号
*从零开始,每次调用此子例程时增加1。
*参数elapsedSeconds给出自动画开始的秒数
*已启动。通过在图形中使用frameNumber和/或elapsedSeconds
*代码,你可以制作一个随时间变化的图片。这是一个动画。
*“宽度”和“高度”参数给出绘图区域的大小(以像素为单位)。
*/
公共无效绘图框(GraphicsContext g、int frameNumber、双elapsedSeconds、int width、int height){
/*注意:要获得不同的动画,只需删除此动画的内容
*子例程并替换您自己的。
*/
g、 设置填充(颜色:白色);
g、 fillRect(0,0,宽度,高度);//首先,用背景色填充整个图像!
g、 设置填充(颜色:黑色);
g、 填充文本(“帧编号”+帧编号,40,50);
g、 fillText(String.format(“运行时间:%1.1f秒”,elapsedSeconds),40,80);
}
//------实施细节:不要期望理解这一点------
私有int-frameNum;
私人长启动时间;
公众假期开始(阶段){
int width=800;//图像的宽度。您可以修改此值!
int height=600;//图像的高度。您可以修改此值!
画布=新画布(宽度、高度);
drawFrame(canvas.getGraphicsContext2D(),0,0,宽度,高度);
BorderPane根=新的BorderPane(画布);
root.setStyle(“-fx边框宽度:4px;-fx边框颜色:#444”);
场景=新场景(根);
舞台场景;
stage.setTitle(“简单动画”);//字符串出现在窗口标题栏中!
stage.show();
阶段。可设置大小(假);
AnimationTimer anim=新的AnimationTimer(){
公共无效句柄(长){
如果(开始时间<0)
开始时间=现在;
frameNum++;
drawFrame(canvas.getGraphicsContext2D(),frameNum,(现在开始时间)/1e9,宽度,高度);
}
};
开始时间=-1;
anim.start();
}
公共静态void main(字符串[]args){
发射();
}
}//结束SimpleImationStarter
导入javafx.animation.AnimationTimer;
导入javafx.application.application;
导入javafx.scene.layout.BorderPane;
导入javafx.scene.scene;
导入javafx.stage.stage;
英普