Brian Stallter
Brian Stallter

Reputation: 159

javafx have an eventfilter remove itself

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.

Upvotes: 1

Views: 2467

Answers (1)

Itai
Itai

Reputation: 6911

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:

Upvotes: 4

Related Questions