我尝试在我的自定义类中注册eventHandler。我不知道我必须实现什么接口或方法才能在我的自定义类中使用addEventHandler
方法。出于这个原因,我的Model
类扩展Rectangle
(Rectangle
类具有addEventHandler
机制(。
我也不知道为什么分配的源对象不起作用(请参阅类Controller
中的评论(。
创建我通过本教程创建的自定义事件:https://stackoverflow.com/a/27423430/3102393。
项目结构
控制器
package sample;
import javafx.event.Event;
public class Controller {
private Model model;
public Controller() {
model = new Model();
model.addEventHandler(MyEvent.ROOT_EVENT, this::handler);
}
private void handler(MyEvent event) {
if(event.getEventType().equals(MyEvent.INSTANCE_CREATED)) {
// Why is event.getSource() instence of Rectangle and not instance of assigned MyObject?
Object obj = event.getSource();
System.out.println(event.getMyObject().getText());
}
}
public void clickedCreate(Event event) {
model.makeEvent();
}
}
型
package sample;
import javafx.scene.shape.Rectangle;
import java.util.ArrayList;
public class Model extends Rectangle {
private ArrayList<MyObject> objects = new ArrayList<>();
private Integer counter = 0;
public void makeEvent() {
MyObject object = new MyObject((++counter).toString() + "!");
objects.add(object);
fireEvent(new MyEvent(object, null, MyEvent.INSTANCE_CREATED));
}
}
自定义事件我的事件
package sample;
import javafx.event.Event;
import javafx.event.EventTarget;
import javafx.event.EventType;
public class MyEvent extends Event {
public static final EventType<MyEvent> ROOT_EVENT = new EventType<>(Event.ANY, "ROOT_EVENT");
public static final EventType<MyEvent> INSTANCE_CREATED = new EventType<>(ROOT_EVENT, "INSTANCE_CREATED ");
public static final EventType<MyEvent> INSTANCE_DELETED = new EventType<>(ROOT_EVENT, "INSTANCE_DELETED");
private MyObject object;
public MyEvent(MyObject source, EventTarget target, EventType<MyEvent> eventType) {
super(source, target, eventType);
object = source;
}
public MyObject getMyObject() {
return object;
}
}
最后是我的对象
package sample;
public class MyObject {
private String text;
MyObject(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
注意(和问题(:我也尝试使用MyObject
实例的ObservableList
,但我认为没有更新实例属性的通知。
事件基础知识
Event
s 使用 Event.fireEvent
触发,该 分 2 步工作:
- 使用
EventTarget.buildEventDispatchChain
构建EventDispatchChain
。 - 将
Event
传递给生成的EventDispatchChain
中的第一个EventDispatcher
。
此代码片段演示了以下行为:
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));
它打印
Dispatch 1
Dispatch 2
如您所见,EventTarget
构建EventDispatchChain
的方式完全取决于EventTarget
。
这就解释了为什么你必须自己实现addEventHandler
等等。
它是如何为Node
完成的
这在 Oracle 网站上的 JavaFX:处理事件 - 1 处理事件一文中有详细说明。
重要的细节是:
- 在事件处理期间使用不同的
source
对象。 -
EventHandler
s/EventFilter
s 在事件调度期间使用 (2.(。
这就解释了为什么source
值是意外的。
如何实现addEventHandler
如果你省略了事件捕获和冒泡,做到这一点并不难。您只需要将EventHandler
按类型存储在Map<EventType, Collection>>
中,并为EventType
层次结构中的每个类型调用EventHandler
s:
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);
}
}