JavaFX:鼠标落后于绘图

时间:2015-10-21 13:38:53

标签: java javafx javafx-8

我有一个JavaFX应用程序,我在画布上绘制。图纸跟随鼠标。这种移动有点滞后,因为渲染需要一些时间。到目前为止还不错。但是当我停止鼠标时,它的坐标有时仍处于旧位置。

以下代码重现了该问题:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.SceneBuilder;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Ellipse;
import javafx.scene.shape.EllipseBuilder;
import javafx.stage.Stage;

public class TestApp extends Application
{
    public static void main(String[] args)
    {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception
    {
        Pane p = new Pane();

        final Ellipse ellipse = EllipseBuilder.create().radiusX(10).radiusY(10).fill(Color.RED).build();
        p.getChildren().add(ellipse);

        p.setOnMouseMoved(event ->
        {
            ellipse.setCenterX(event.getX());
            ellipse.setCenterY(event.getY());
            Platform.runLater(() -> doSomeWork());
        });

        Scene scene = SceneBuilder.create().root(p).width(1024d).height(768d).build();
        primaryStage.setScene(scene);

        primaryStage.show();
    }

    void doSomeWork()
    {
        try
        {
            Thread.sleep(100);
        }
        catch (Exception ignore) { }
    }
}

当你快速移动鼠标并突然停止时,圆圈有时不在鼠标下面。

我使用过或不使用Platform.runLater()或通话订单。没有成功。

修改 我无法在Windows下重现此行为。

1 个答案:

答案 0 :(得分:1)

我的假设是在UI-Thread和onMouseMoved上调用Platform.runLater。这会阻止UI-Thread,因此,最后onMouseMoved次调用将被丢弃(这使得该圈位于onMouseMoved的最后一次调用的位置)。正如Platform.runLater-Doc

中所定义
  

此外,长时间运行的操作应尽可能在后台线程上完成,从而释放JavaFX应用程序线程以进行GUI操作。

因此,尝试在额外线程上完成工作,并在计算完成后通过runLater 将其发布到用户界面:

public class TestApp extends Application
{

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

    @Override
    public void start(Stage primaryStage) throws Exception
    {
        Pane p = new Pane();

        final Ellipse ellipse = EllipseBuilder.create().radiusX(10).radiusY(10).fill(Color.RED).build();
        p.getChildren().add(ellipse);

        p.setOnMouseMoved(event ->
        {
            ellipse.setCenterX(event.getX());
            ellipse.setCenterY(event.getY());
            doSomeWork();
        });

        Scene scene = SceneBuilder.create().root(p).width(1024d).height(768d).build();
        primaryStage.setScene(scene);

        primaryStage.show();
    }

    void doSomeWork()
    {
        new Thread(){
            public void run(){

                try
                {
                    Thread.sleep(100);
                    Platform.runLater(() -> {
                        // ui updates
                    });
                }
                catch (Exception ignore) { }
            }
        }.start();
    }
}