JavaFX. Register eventHandler in custom class

后端 未结 1 1248
礼貌的吻别
礼貌的吻别 2021-02-06 19:30

I try register eventHandler in my custom class. I don\'t know what interface or methods I have to implement for having addEventHandler method in my custom class. Fo

相关标签:
1条回答
  • 2021-02-06 20:00

    Basics of Events

    Events are fired using Event.fireEvent which works in 2 steps:

    1. Build the EventDispatchChain using EventTarget.buildEventDispatchChain.
    2. Pass the Event to the first EventDispatcher in the resulting EventDispatchChain.

    This code snippet demonstrates the behaviour:

    EventTarget target = new EventTarget() {
    
        @Override
        public EventDispatchChain buildEventDispatchChain(EventDispatchChain tail) {
            return tail.append(new EventDispatcher() {
    
                @Override
                public Event dispatchEvent(Event event, EventDispatchChain tail) {
                    System.out.println("Dispatch 1");
                    tail.dispatchEvent(event);
                    return event;
                }
            }).append(new EventDispatcher() {
    
                @Override
                public Event dispatchEvent(Event event, EventDispatchChain tail) {
                    System.out.println("Dispatch 2");
                    tail.dispatchEvent(event);
                    return event;
                }
            });
        }
    };
    
    Event.fireEvent(target, new Event(EventType.ROOT));
    

    It prints

    Dispatch 1
    Dispatch 2
    

    As you can see, the way the EventTarget constructs the EventDispatchChain is totally up to the EventTarget.

    This explains why you have to implement addEventHandler ect. yourself.

    How it's done for Nodes

    This is described in detail in the article JavaFX: Handling Events - 1 Processing Events on the Oracle website.

    The important details are:

    • Different source objects are used during the event handling.
    • EventHandlers / EventFilters are used during the event dispatching (2.).

    This explains why the source value is unexpected.

    How to implement addEventHandler

    It's not that hard to do this, if you leave out the event capturing and bubbling. You just need to store the EventHandlers by type in a Map<EventType, Collection>> and call the EventHandlers for each type in the EventType hierarchy:

    public class EventHandlerTarget implements EventTarget {
    
        private final Map<EventType, Collection<EventHandler>> handlers = new HashMap<>();
        
        public final <T extends Event> void addEventHandler(EventType<T> eventType, EventHandler<? super T> eventHandler) {
            handlers.computeIfAbsent(eventType, (k) -> new ArrayList<>())
                    .add(eventHandler);
        }
    
        public final <T extends Event> void removeEventHandler(EventType<T> eventType, EventHandler<? super T> eventHandler) {
            handlers.computeIfPresent(eventType, (k, v) -> {
                v.remove(eventHandler);
                return v.isEmpty() ? null : v;
            });
        }
        
        @Override
        public final EventDispatchChain buildEventDispatchChain(EventDispatchChain tail) {
            return tail.prepend(this::dispatchEvent);
        }
    
        private void handleEvent(Event event, Collection<EventHandler> handlers) {
            if (handlers != null) {
                handlers.forEach(handler -> handler.handle(event));
            }
        }
    
        private Event dispatchEvent(Event event, EventDispatchChain tail) {
            // go through type hierarchy and trigger all handlers
            EventType type = event.getEventType();
            while (type != Event.ANY) {
                handleEvent(event, handlers.get(type));
                type = type.getSuperType();
            }
            handleEvent(event, handlers.get(Event.ANY));
            return event;
        }
    
        public void fireEvent(Event event) {
            Event.fireEvent(this, event);
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题