我正在尝试使用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位上。
答案 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();
}
}