在javafx的画布上平移

时间:2012-09-11 17:55:59

标签: java javafx-2

我正在尝试使用javafx 2创建一个画布,用户可以在其中进行平移和缩放。对于静态内容,我的解决方案可以正常工作,但只要在用户平移时内容更新,鼠标事件就会停止工作,直到鼠标按钮被释放并再次按下。

以下是演示该问题的最小示例。如果您在白色区域中单击,则可以平移,但如果您通过单击红色矩形开始平移,则在更新内容时会中断它。

class Test extends StackPane
{
    private Timer timer = new Timer();
    private Rectangle rect;
    private double pressedX, pressedY;

    public Test()
    {
        setMinSize(600, 600);
        setStyle("-fx-border-color: blue;");

        timer.schedule(new TimerTask()
        {
            @Override
            public void run()
            {
                Platform.runLater(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        if (rect != null)
                            getChildren().remove(rect);

                        rect = new Rectangle(10, 10, 200, 200);
                        rect.setFill(Color.RED);
                        getChildren().add(rect);
                    }
                });
            }
        }, 0, 100);

        setOnMousePressed(new EventHandler<MouseEvent>()
        {
            public void handle(MouseEvent event)
            {
                pressedX = event.getX();
                pressedY = event.getY();
            }
        });

        setOnMouseDragged(new EventHandler<MouseEvent>()
        {
            public void handle(MouseEvent event)
            {
                setTranslateX(getTranslateX() + event.getX() - pressedX);
                setTranslateY(getTranslateY() + event.getY() - pressedY);

                event.consume();
            }
        });
    }
}

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

    @Override
    public void start(Stage primaryStage)
    {
        Scene scene = new Scene(new Test());
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

我使用JDJ7u7在Windows 8 64位上。

1 个答案:

答案 0 :(得分:3)

嗯,我认为你的代码没问题,似乎对我运行正常,并且在Windows 7上使用jdk7u7时没有任何明显的问题。

我想也许您想要调用rect.setMouseTransparent(true),以便矩形不会捕获点击次数。鼠标透明度与添加和删除矩形无关,它只是拾取在JavaFX中的工作方式。

您可能需要考虑将Test节点置于pannable ScrollPane而不是自己实现平移 - 可能需要将其包装在Group中以获得适当的行为。但是你拥有的代码很简单,似乎工作正常,所以也许使用ScrollPane是不必要的,甚至可能会混淆更多。

Java中有一个Canvas类,它与您所拥有的类不同,因此调用节点而不是Canvas可能是个好主意。

与您的问题无关,但使用Timeline是我处理动画的首选方式,而不是Timer,尽管只要您正确Timer方法仍可正常工作正如你所做的那样使用Platform.runLater

以下是使用Timeline.mouseTransparent()添加了帧计数器的修改后的示例,以便明确动画正在发生。

import javafx.animation.*;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.*;
import javafx.event.*;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;

class Test extends StackPane {
  private Rectangle rect;
  private double pressedX, pressedY;
  private LongProperty frame = new SimpleLongProperty();

  public Test() {
    setMinSize(600, 600);
    setStyle("-fx-border-color: blue;");
    Label count = new Label();
    count.textProperty().bind(Bindings.convert(frame));
    getChildren().add(count);
    count.setMouseTransparent(true);

    setOnMousePressed(new EventHandler<MouseEvent>() {
      public void handle(MouseEvent event) {
        pressedX = event.getX();
        pressedY = event.getY();
      }
    });

    setOnMouseDragged(new EventHandler<MouseEvent>() {
      public void handle(MouseEvent event) {
        setTranslateX(getTranslateX() + event.getX() - pressedX);
        setTranslateY(getTranslateY() + event.getY() - pressedY);

        event.consume();
      }
    });

    Timeline t = new Timeline(new KeyFrame(Duration.millis(100), new EventHandler<ActionEvent>() {
      @Override public void handle(ActionEvent event) {
        frame.set(frame.get() + 1);

        if (rect != null) {
          getChildren().remove(rect);
        }

        rect = new Rectangle(10, 10, 200, 200);
        rect.setFill(Color.RED);
        rect.setMouseTransparent(true);
        getChildren().add(0, rect);
      }
    }));
    t.setCycleCount(Timeline.INDEFINITE);
    t.play();
  }
}

public class TestApplication extends Application {
  public static void main(String[] args) { launch(args); }
  @Override public void start(Stage stage) {
    stage.setScene(new Scene(new Test()));
    stage.show();
  }
}

Sample program output