简短说明:运行一个简单的JavaFX程序,该程序 说明了AnimationTimer结果在我的PC中几乎处于锁定状态 起来该程序可以在其他PC和我的PC上正常运行时 与其他版本的Linux一起启动。详细说明
在校对在线Java教科书的新版本时 我在运行本书中的示例程序时遇到了问题 说明了JavaFX AnimationTimer。程序源 是SimpleAnimationTimer.java。见下文。这很简单 仅显示当前帧号的程序 经过的时间(以秒为单位)。预期的输出是看 “每秒60帧”;即显示的帧号 除以显示的经过时间应为60。
编译并在我的PC上运行时,它将淹没应用程序 窗口太大了,几乎无法将鼠标移到 另一个窗口,以便我可以杀死正在运行的程序。什么时候 我通知了该书的作者,他回答说该程序 在他的所有PC(Ubuntu,Linux Mint,Mac,Windows)上均可正常运行。 我的电脑正在运行Fedora27。
我通过实时USB下载并运行了最新的Linux Mint, 然后使用与所使用的相同的Java测试程序 适用于Fedora27。该程序在那里正确运行。
接下来,我重新启动了较旧的Fedora 24并测试了该程序 那里。它运行无误。
我从实时USB下载并运行Fedora 28。的 程序那里有问题。
我的测试环境和结果的摘要。
Java版本为1.8.0_181。它是来自Oracle的。
Linux Mint 19内核4.15.0-20(通用)。没问题。
Fedora 24内核4.11.12。没问题。
Fedora 27内核4.17.17。有问题。
Fedora 28内核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.java。
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