I am trying to create a canvas with javafx 2 in which the user can pan and zoom. For static content my solution works, but as soon as the content gets updated while the user is panning, the mouse events stop working until the mouse button is released and pressed again.
The following is a minimal example which demonstrates the problem. If you click in a white area you can pan around, but if you start the panning with a click on the red rectangle it gets interrupted when the content is updated.
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();
}
}
I’m on Windows 8 64 bit with JDJ7u7.
Well I think your code is OK, seems to run fine for me and operate without any clear issue using jdk7u7 on windows 7.
I think maybe you want to call
rect.setMouseTransparent(true), so that the rectangles don’t catch the clicks. The mouse transparency thing isn’t to do with the adding and removing of rectangles, it’s just the way that picking works in JavaFX.You may want to consider placing your Test node in a pannable
ScrollPanerather than implementing the panning yourself – might need to wrap it in aGroupto get the appropriate behaviour. But the code you have is simple and seems to work fine, so perhaps use of aScrollPaneis unnecessary and may even confuse things more.There is a
Canvasclass in Java, which is something different from what you have, so calling your node something other thanCanvasis probably a good idea.Not to do with your question, but using a
Timelineis my preferred way to handle animation rather than aTimer, though theTimermethod will still work as long as you correctly usePlatform.runLateras you are doing.Here’s a modified sample using a
Timelineand.mouseTransparent()with an added frame counter so that it is clear that animation is happening.