我尝试在自定义类中注册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));
}
}
自定义事件 MyEvent
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;
}
}
最后是MyObject
package sample;
public class MyObject {
private String text;
MyObject(String text) {
this.text = text;
}
public String getText() {
return text;
}
}
注意(和问题):我也尝试使用ObservableList
个MyObject
个实例,但我认为没有通知更新实例属性。
答案 0 :(得分:5)
Event
是使用Event.fireEvent
解雇的,分为两步:
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
s Oracle网站上的文章JavaFX: Handling Events - 1 Processing Events对此进行了详细介绍。
重要的细节是:
source
个对象。EventHandler
s / EventFilter
(2。)。这解释了为什么source
值是意外的。
addEventHandler
如果你忽略事件捕获和冒泡,那就不难做到这一点。您只需要在EventHandler
中按类型存储Map<EventType, Collection>>
,并为EventHandler
层次结构中的每种类型调用EventType
:
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);
}
}