1

A snippet of my code is as follows:

//button clicked method
@FXML
public void newHeatExchanger2ButtonClicked(ActionEvent event) throws Exception {

    //new pane created
    Pane pane = new Pane();

    //method call everytime the button is clicked
    create2DExchanger(pane);

   }

//method declaration
private void create2DExchanger(Pane pane) {

    EventHandler<MouseEvent> panePressed = (e -> {
        if (e.getButton() == MouseButton.SECONDARY){

            do stuff
        }

        if (e.getButton() == MouseButton.PRIMARY){
            do stuff
        }
    });

    EventHandler<MouseEvent> paneDragged = (e -> {
        if (e.getButton() == MouseButton.PRIMARY){
            do stuff
        }
    });
    EventHandler<MouseEvent> paneReleased = (e -> {
        if (e.getButton() == MouseButton.PRIMARY){
            do stuff;
        }

    });
    EventHandler<MouseEvent> paneMoved = (t -> {
        do stuff;
    });
    EventHandler<MouseEvent> paneClicked = (t -> {
        //I need this filter to remove itself right here
        t.consume();
        pane.removeEventFilter(MouseEvent.MOUSE_MOVED, paneMoved);
        pane.addEventHandler(MouseEvent.MOUSE_PRESSED, panePressed);
        pane.addEventHandler(MouseEvent.MOUSE_DRAGGED, paneDragged);
        pane.addEventHandler(MouseEvent.MOUSE_RELEASED, paneReleased);
    });
    pane.removeEventHandler(MouseEvent.MOUSE_PRESSED, panePressed);
    pane.removeEventHandler(MouseEvent.MOUSE_DRAGGED, paneDragged);
    pane.removeEventHandler(MouseEvent.MOUSE_RELEASED, paneReleased);
    pane.addEventFilter(MouseEvent.MOUSE_MOVED, paneMoved);
    pane.addEventFilter(MouseEvent.MOUSE_PRESSED, paneClicked);


}

Initially I set the pane to have only the event filters of mouse_moved, and mouse_pressed. As soon as the mouse is clicked I need the mouse filter for mouse_pressed and mouse_moved to go away and add the eventHandlers as I do in the paneClicked filter llamda. I need the first set of events to be filters because there are children nodes I do not want to receive the event (i.e. an event filter on an arc that is a child of the pane). The second set need to be handlers because the arc event filter needs to consume the event before the pane eventHandlers receive it.

Convenience events like:

    pane.setOnMousePressed() 

can remove themselves by calling

    pane.setOnMousePressed(null); 

but I need this initial event filter to remove itself. I will need the functionality of an event removing itself later as well in the code, but if I try to add

    pane.removeEventFilter(MouseEvent.MOUSE_PRESSED, paneClicked);

to

    EventHandler<MouseEvent> paneClicked = (t -> {
        //I need this filter to remove itself right here
        t.consume();
        pane.removeEventFilter(MouseEvent.MOUSE_MOVED, paneMoved);
        pane.addEventHandler(MouseEvent.MOUSE_PRESSED, panePressed);
        pane.addEventHandler(MouseEvent.MOUSE_DRAGGED, paneDragged);
        pane.addEventHandler(MouseEvent.MOUSE_RELEASED, paneReleased);
    });

It will not compile. I have been researching for a couple of days on how to get the functionality of an eventFilter or eventHandler to remove itself but I am coming up short. I have not found anything online or on stackexchange in my Google searches either. I would really appreciate being able to figure this thing out. Thanks.

Brian Stallter
  • 159
  • 1
  • 1
  • 16

1 Answers1

4

I believe the problem stems from the fact that you try to access paneClicked before it was fully declared.

You can overcome this using an anonymous class with the this keyword:

EventHandler<MouseEvent> paneClicked =  new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent event) {
        event.consume();
        pane.removeEventFilter(MouseEvent.MOUSE_PRESSED, this);
        pane.removeEventFilter(MouseEvent.MOUSE_MOVED, paneMoved);
        pane.addEventHandler(MouseEvent.MOUSE_PRESSED, panePressed);
        pane.addEventHandler(MouseEvent.MOUSE_DRAGGED, paneDragged);
        pane.addEventHandler(MouseEvent.MOUSE_RELEASED, paneReleased);
    }
};

Or by referencing a fully qualified static function:

public class ContainingClass {
    ...
    private static EventHandler<MouseEvent> paneClicked = (t -> {
        t.consume();
        pane.removeEventFilter(
            MouseEvent.MOUSE_PRESSED, ContainingClass.paneClicked
        );
    });
}

See also:

Community
  • 1
  • 1
Itai
  • 6,641
  • 6
  • 27
  • 51
  • Thanks for the extra info @jewelsea . The second option looks interesting - does this mean the JVM assigns the (pointer to the) static member before the value is set? – Itai Feb 23 '16 at 06:51
  • Nevermind, I think I understand - the fact it's a fully-qualified name allows to JVM to resolve it during runtime, that is - after the variable had been initialized. – Itai Feb 23 '16 at 06:58
  • Thanks a lot @jewelsea. I knew this would be intuitive for you. I really like what you do in JavaFX and enjoy your answers here. I code after work, so I'll give it a try tonight. Can I then create a class "Containing Class" that just houses all of my eventhandlers and eventfilters for uniformity and I just constantly draw from there everytime I need to use one? – Brian Stallter Feb 23 '16 at 19:52
  • I guess you could define your event handlers centrally if that works well for your architecture and design. Otherwise, if you don't need to reuse the event handlers outside of your controller classes (which is probably pretty likely), you could just define the event handlers statically, locally within the controller class and reference them via the controller class name. Note that the solution of anonymous classes is a bit more flexible, even though slightly more verbose, as it doesn't require static definitions which can sometimes be a bit problematic. – jewelsea Feb 23 '16 at 20:13
  • Wow. Jewelsea. It's really cool you answered my post and gave me the exact answer I needed. Anyone who has a similar problem will now have the solution. I went with the anonymous class inside the controller and solved the problem I'd been researching for days immediately. Much honor to you sir. I wish I could download your knowledge in my brain. – Brian Stallter Feb 24 '16 at 05:01
  • By the way how would I be able to pass pane into the class if I did choose that method? – Brian Stallter Feb 24 '16 at 06:24