简体   繁体   English

使用JavaFX AnimationTimer停止屏幕撕裂

[英]Stop screen tearing with JavaFX AnimationTimer

In JavaFX, it seems appropriate to me to use AnimationTimer for frequently updating Canvas Nodes; 在JavaFX中,使用AnimationTimer频繁更新Canvas节点对我来说似乎很合适。 that is, for rasterized animations instead of vector animations. 也就是说,用于光栅化动画而不是矢量动画。 I'm running into an issue, which may be VSync related. 我遇到了一个问题,可能与VSync有关。 I have a singular Canvas on my Scene which contains 2D data that changes frequently (the rest of the program is done with Nodes). 我的场景上有一个单一的Canvas,其中包含频繁更改的2D数据(程序的其余部分由Nodes完成)。 I tend to get a tearing down the middle of the screen when I do this, which implies that the AnimationTimer may be falling out of sync with the monitor refresh rate. 当我这样做时,我倾向于在屏幕中间撕裂,这意味着AnimationTimer可能与监视器刷新率不同步。

This (simplified) code shows the error in detail. 此(简化的)代码详细显示了错误。 Note that I have no idea whether it's display hardware dependent, and the exact position of the tear may shift slightly. 请注意,我不知道它是否取决于显示硬件,并且撕裂的确切位置可能会略有偏移。

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());
    }

}

Moving the mouse cursor over the scene will cause the canvas to shift in background color. 将鼠标光标移到场景上将导致画布的背景色发生变化。 As you move the mouse, you will notice (presumably) a tearing in the frame. 当您移动鼠标时,您会发现(大概)框架有裂痕。

It is quite possible that I'm simply being a N00B at JavaFX, and there's a perfectly friendly .sync()-ish method I'm supposed to call somewhere; 我很可能只是在JavaFX上成为N00B,而我应该在某个地方调用一个非常友好的.sync()-ish方法; but I haven't found it yet. 但是我还没有找到。 I've found bugs submitted to Oracle that look similar to this. 我发现提交给Oracle的错误看起来类似 My answer may simply be dodging using Canvas and AnimationTimer for animations. 我的答案可能只是使用Canvas和AnimationTimer来躲避动画。 All the same, even if there isn't a solution at this time, if someone has a workaround, I would love to hear about it! 都一样,即使目前没有解决方案,如果有人有解决方法,我也很想听听!

Thanks! 谢谢!

Found the issue (thank you to @VGR for pointing out the lack of system behavioral congruity)! 找到了问题(感谢@VGR指出缺少系统行为一致性)! Seems that it wasn't Java at all; 似乎根本不是Java。 it was Marco. 是马可。 I switched Desktop Windowing Managers, to Compiz specifically; 我将桌面窗口管理器专门切换为Compiz。 and the tearing is now gone. 现在眼泪已经消失了。

Evidently this isn't a bug in Java at all; 显然,这根本不是Java中的错误。 it's a trade-off for using Marco. 这是使用Marco的权衡。 This is a relief! 这是一种解脱!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM