我试图了解何时在JavaFX中使用EventDispatcher。我非常了解捕获和冒泡的所有事件机制。但是我仍然对EventDispatcher的目的感到困惑。因为我可以使用过滤器和处理程序来完成大部分工作。
有人可以解释一下实际目的以及如何使用此EventDispatcher吗?
谢谢。
答案 0 :(得分:5)
EventDispatcher
顾名思义,EventDispatcher
的目的是分发一个
Event
。其执行方式取决于实现方式。然而
标准实现(JavaFX内部)使EventDispatcher
成为一种
EventHandler
的“集合”。这是EventDispatcher
的责任
在正确的时间调用适当的EventHandler
。是什么使得
EventHandler
的“适当”取决于:
EventHandler
已为活动的当前阶段注册
调度周期(捕获或冒泡)EventHandler
已为当前Event
的{{1}}注册,或者
超型之一(即EventType
)如果我们专注于场景图,则在触发EventType.getSuperType()
时会从顶部开始
(Event
)的场景图,然后遍历层次结构
目标(通常是Window
,但至少要实现
Node
)。这是事件分发周期的“捕获”阶段。后
到达目标后,它会返回场景图,直到到达目标
再次EventTarget
。这是周期的“冒泡”阶段。
Window
-> Window
-> Scene
-> Root Node
-> Middle Node
EventTarget
<-Window
<-Scene
<-Root Node
<-Middle Node
如果在任何步骤中EventTarget
被消耗(通过Event
),那么它将不会
被转发到下一步。这有效地停止了
Event.consume()
在链中所需的步骤。
此路径的计算方式由的实现实现
Event
和EventDispatchChain
。 EventTarget
必须实现
以下方法:
EventTarget
触发EventDispatchChain buildEventDispatchChain(EventDispatchChain tail);
时,它具有指定的Event
。自从
EventTarget
将在场景图的底部,链是
从头开始。它是通过在EventTarget
前面添加{
EventDispatcher
在层次结构的每个级别(使用
EventDispatchChain
)。这是EventDispatchChain.prepend(EventDispatcher)
开始出现。
每个EventDispatcher
通常都有自己的EventTarget
关联。的
EventDispatcher
在标准JavaFX(EventTarget
,Window
,Scene
,
Node
等)提供自己的MenuItem
实现。在
就这一点而言,您不必担心如何使用EventDispatcher
。你不
甚至直接使用它。相反,您可以通过以下方式添加EventDispatcher
EventHandler
和[add|remove]EventHandler
方法以及
他拥有各种[add|remove]EventFilter
属性。
当onXXX
被调用时,buildEventDispatchChain
前置
其Button
到给定的Button
。然后调用
EventDispatcher
的{{1}}上有{。这一直持续到
EventDispatchChain
的根buildEventDispatchChain
。根Parent
调用Node
在所说的Scene
上,在其Node
之前,在
buildEventDispatchChain
所附加。
此时Scene
已完全构建并可以处理
EventDispatcher
。如果还不明显,Window
基本上只是
EventDispatchChain
个“堆栈”。换句话说,它是高度专业化的
Event
,但实际上没有扩展该接口。
注意:EventDispatchChain
还提供了一种EventDispatcher
方法
对于前置错误操作的情况。
java.util.Deque
完全构建之后,就该实际分发
EventDispatchChain
。这是通过在append(EventDispatcher)
上调用此方法来完成的:
EventDispatchChain
这使Event
上的第一个EventDispatchChain
得到(弹出)
堆栈并调用其方法:
Event dispatchEvent(Event event);
侧面注意:不幸的是EventDispatchChain
的方法具有与
EventDispatcher
可能会引起混乱。
旁注2:Event dispatchEvent(Event event, EventDispatchChain tail);
在整个{
整个过程。
这是实际使用EventDispatcher
的地方。这是算法
由内部定义的每个EventDispatchChain.dispatchEvent(Event)
使用
tail
类(Java 10源代码):
EventDispatchChain
步骤是:
EventDispatcher
EventDispatcher
com.sun.javafx.event.BasicEventDispatcher
不会 停止分发@Override
public Event dispatchEvent(Event event, final EventDispatchChain tail) {
event = dispatchCapturingEvent(event);
if (event.isConsumed()) {
return null;
}
event = tail.dispatchEvent(event);
if (event != null) {
event = dispatchBubblingEvent(event);
if (event.isConsumed()) {
return null;
}
}
return event;
}
此步骤;但会阻止Event
在后续步骤中得到处理EventHandler
被消耗,则返回Event
,否则将Event
转发到
Event
,然后等待返回Event
不返回null
,则分派Event
起泡阶段
tail
是tail.dispatchEvent
,则意味着null
已被消耗
链中的某个地方,无需进行其他处理Event
(
包括通过Event
属性添加的内容)null
不会停止处理
此步骤;但会阻止Event
在后续步骤中得到处理EventHandler
被消耗,则返回onXXX
,否则返回Event
Event
一样,返回Event
表示null
已
Event
的消耗和处理必须停止对EventDispatchChain
中的每个null
完成。通话
Event
基本上是“递归”操作(不包含
“真实”递归)。实际上,这段代码沿栈走了(
Event
),然后返回堆栈(当EventDispatcher
返回)。并且每个“链中的链接”都在“递归”之前进行处理
调用(捕获阶段),然后在“递归”调用之后返回(冒泡
阶段)。
不过请注意,每一步都是EventDispatchChain
实际上调用了每个适当的tail.dispatchEvent
。 这就是
使用了tail.dispatchEvent
。
tail.dispatchEvent
在扩展已经实现EventDispatcher
的类时,您应该只
在绝对需要时创建自己的EventHandler
。如果您的目标是
控制EventDispatcher
是否达到某个EventDispatcher
,那么您的第一选择应该是
在适当的地方食用EventTarget
(Jai在
注释)。如果您想更改EventDispatcher
的路径,则可以
可能需要提供自己的Event
。但是,由于封闭
内部EventTarget
实现的性质以及事实
Event
界面受到限制,您可能会受到限制
在您自己的实现中包装原始Event
并委派
必要时。我已经在其他人的代码中看到了这一点(甚至可能已经看到
它在JavaFX本身中),但我记不清代码足以给您
这样的例子。
如果您要从头开始创建自己的自己 EventDispatcher
,则必须
实现自己的EventDispatcher
。如果要注意一些事情
需要您自己的实现:
EventDispatcher
(如果
有阶段)EventDispatcher
的{{1}}注册的EventTarget
并说EventDispatcher
的超类型EventHandler
转发到尾部EventHandler
Event
已被消耗,它只能返回EventType
EventType
进行并发修改
Event
可能会将自己删除或
在执行其EventDispatchChain
方法时添加/删除另一个null
。这个
将在Event
迭代Thread
时发生
以某种方式。EventHandler
的来源”。在标准JavaFX实现中
每个EventHandler
会将handle
的源更新为EventDispatcher
与该EventHandler
(例如Event
)相关联。这是在
上述EventDispatcher
的子类。
“修复源”的方法是Event