使用JavaFX AnimationTimer停止屏幕撕裂

时间:2015-10-27 20:32:45

标签: java animation javafx

在JavaFX中,使用AnimationTimer来频繁更新Canvas节点似乎是合适的。也就是说,对于栅格化动画而不是矢量动画。我遇到了一个可能与VSync相关的问题。我的场景中有一个单独的画布,其中包含经常更改的2D数据(程序的其余部分使用节点完成)。当我这样做时,我倾向于在屏幕中间撕裂,这意味着AnimationTimer可能与显示器刷新率不同步。

此(简化)代码详细显示错误。请注意,我不知道它是否依赖于显示硬件,并且撕裂的确切位置可能会略有偏移。

import javafx.application.*;
import javafx.animation.*;
import javafx.scene.*;
import javafx.scene.canvas.*;
import javafx.stage.*;
import javafx.event.*;
import javafx.scene.input.*;
import javafx.scene.paint.*;

public class BugDemo extends Application {

    public static void main(String...args) {
        launch(args);
    }

    private Canvas background = new Canvas();
    private Color bgColor = Color.rgb(0, 0, 0);

    @Override
    public void start(Stage primaryStage) throws Exception {
        Group root = new Group();

        startLoops(root);
        Scene scene = new Scene(root);

        initUserControls(scene);
        background.widthProperty().bind(scene.widthProperty());
        background.heightProperty().bind(scene.heightProperty());
        root.getChildren().add(background);

        primaryStage.setScene(scene);

        primaryStage.setTitle("Bug Demo");

        primaryStage.setMaximized(true);
        primaryStage.show();
    }

    /**
     * Initializes all running control managers for game field
     * @param scene primary scene of game
     */
    protected void initUserControls(Scene scene) {
        EventHandler<MouseEvent> handler = new EventHandler<MouseEvent>(){

            @Override
            public void handle(MouseEvent event) {
                bgColor = Color.rgb((int)((event.getX() / background.getWidth()) * 255),
                        (int)((event.getY() / background.getHeight()) * 255),
                        255);
            }};
        scene.getRoot().setOnMouseMoved(handler);
        scene.getRoot().setOnMouseDragged(handler);
    }

    /**
     * Starts all game loops, which will at the beginning of the simulation and often for the extent
     * of it.
     * @param parent Root node
     */
    protected void startLoops(Parent parent) {
        GraphicsContext gc = background.getGraphicsContext2D();

        new AnimationTimer() {

            @Override
            public void handle(long now) {
                drawBackground(gc);
            }}.start();
    }

    protected void drawBackground(GraphicsContext gc) {
        gc.setFill(bgColor);
        gc.fillRect(0, 0, background.getWidth(), background.getHeight());
    }

}

将鼠标光标移动到场景上将导致画布以背景颜色移动。当您移动鼠标时,您会注意到(可能是)框架中的撕裂。

我很可能只是在JavaFX上成为N00B,并且有一个非常友好的.sync() - 我应该在某个地方打电话的方法;但我还没有找到它。我发现提交给Oracle的bug看起来与类似。我的回答可能只是躲避使用Canvas和AnimationTimer进行动画制作。同样,即使目前还没有解决方案,如果有人有解决方法,我很乐意听到它!

谢谢!

1 个答案:

答案 0 :(得分:0)

发现问题(感谢@VGR指出缺乏系统行为一致性)!似乎它根本不是Java;是马可。我专门将桌面窗口管理器切换到了Compiz;撕裂现在已经消失了。

显然,这根本不是Java中的错误;使用Marco是一种权衡。这是一种解脱!