Краткое описание: Запуск простой программы JavaFX, которая иллюстрирует AnimationTimer, приводит к тому, что мой компьютер почти зависает.Программа отлично работает на других ПК и на моем ПК при загрузке с другими версиями Linux.Подробное описание приведено ниже.
При корректировке новой версии онлайн-учебника по Java я столкнулся с проблемой запуска примера программы из книги, иллюстрирующей JavaFX AnimationTimer.Исходный код программы - SimpleAnimationTimer.java.Увидеть ниже.Это очень простая программа, которая просто отображает текущий номер кадра и истекшее время в секундах.Ожидаемый результат - «60 кадров в секунду»;то есть отображаемый номер кадра, деленный на отображаемое прошедшее время, должен составлять 60.
При компиляции и запуске на моем компьютере он так сильно заполняет окно приложения, что я почти не могу переместить свою мышь в другое окно, поэтомучто я могу убить запущенную программу.Когда я уведомил автора книги, он ответил, что программа отлично работает на всех его компьютерах (Ubuntu, Linux Mint, Mac, Windows).На моем компьютере установлена Fedora 27.
Я скачал и запустил последнюю версию Linux Mint с живого USB, затем протестировал там программу, используя ту же Java, что и для Fedora 27. Программа там работает без ошибок.
Далее я перезагрузил старую Fedora 24 и протестировал программу там.Он работал без ошибок.
Я скачал и запустил Fedora 28 с живого USB.Программа имеет проблему там.
Сводка моей среды тестирования и результаты.
Версия Java - 1.8.0_181.Это из Oracle.
Linux Mint 19 kernel 4.15.0-20-generic.Нет проблем.
ядро 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