Search code examples
eventsvariablesjavafxlocalfinal

JavaFX Events Using Local Variables


I have a method that creates an ImageView, called createImageView(), which uses EventHanlders to call vaious events. I would like to be able to use local variables in this method. What I usually do is assign final variables to use within the handle(Event) method.

In the method described below, when I go to use final I get the following errors:

The final local variable initY cannot be assigned, since it is defined in an enclosing type
The final local variable initY cannot be assigned, since it is defined in an enclosing type
The final local variable dragAnchor cannot be assigned, since it is defined in an enclosing type

Of course, removing final gives me this message:

Cannot refer to a non-final variable initX inside an inner class defined in a different method

So what do I have to do to make this method work?

private ImageView createImageView() {
    double initX;
    double initY;
    Point2D dragAnchor;

    imgView.setOnMousePressed(new EventHandler < MouseEvent > () {
        public void handle(MouseEvent me) {
            //when mouse is pressed, store initial position
            initX = imgView.getTranslateX();
            initY = imgView.getTranslateY();
            dragAnchor = new Point2D(me.getSceneX(), me.getSceneY());
            me.consume();
        }
    });

    imgView.setOnMouseDragged(new EventHandler < MouseEvent > () {
        public void handle(MouseEvent me) {
            double dragX = me.getSceneX() - dragAnchor.getX();
            double dragY = me.getSceneY() - dragAnchor.getY();

            double newXPosition = initX + dragX;
            double newYPosition = initY + dragY;
            imgView.setTranslateX(newXPosition);
            imgView.setTranslateY(newYPosition);
            me.consume();
        }
    });

    imgView.setOnMouseEntered(new EventHandler < MouseEvent > () {
        public void handle(MouseEvent event) {
            imgView.setEffect(new Glow(0.5));
            event.consume();
        }
    });

    imgView.setOnMouseExited(new EventHandler < MouseEvent > () {
        public void handle(MouseEvent event) {
            imgView.setEffect(new Glow(0.0));
            event.consume();
        }
    });
    return imgView;
}

Solution

  • Use JavaFX properties instead of primitive types.

    For example:

    final DoubleProperty initX = new SimpleDoubleProperty();
    final ObjectProperty<Point2D> dragAnchor = new SimpleObjectProperty<>();
    ...
    // in event handler
    initX.set(
      imageView.getTranslateX()
    );
    dragAnchor.set(
      new Point2D(
        me.getSceneX(), 
        me.getSceneY()
      )
    );