JavaFX - EventDispatcher和EventFilter之间的区别 [英] JavaFX - Difference between EventDispatcher and EventFilter
问题描述
我试图了解何时在JavaFX中使用EventDispatcher。我非常清楚捕获和冒泡的所有事件机制。但我仍然对EventDispatcher的目的感到困惑。因为我可以使用过滤器和放大器完成我的大部分工作。处理程序。
I am trying to understand when to use EventDispatcher in JavaFX. I am pretty much aware of all the event mechanisms of capturing and bubbling. But I am still confused with the purpose of EventDispatcher. Because I can get most of my work done using filters & handlers.
有人可以解释一下实际目的是什么以及如何使用这个EventDispatcher?
Can someone please explain what is the actual purpose and how to use this EventDispatcher?
谢谢。
推荐答案
的目的> EventDispatcher
顾名思义, EventDispatcher
的目的是发送
事件
。它的执行方式取决于实现。但是,
标准实现(JavaFX内部)使 EventDispatcher
成为 EventHandler $的
集合 C $ C>秒。 EventDispatcher
负责在正确的时间调用适当的 EventHandler
。是什么让
一个 EventHandler
合适取决于:
Purpose of EventDispatcher
As the name suggests, the purpose of an EventDispatcher
is to dispatch an
Event
. The way it does this is dependent on the implementation. However, the
standard implementation (internal to JavaFX) makes EventDispatcher
a kind of
"collection" of EventHandler
s. It is the responsibility of the EventDispatcher
to invoke the appropraite EventHandler
at the correct time. What makes
an EventHandler
"appropriate" depends on:
- 如果
EventHandler
已在事件的当前阶段注册
调度周期(捕获或冒泡) - 如果<$> c $ c> EventHandler 已注册当前
事件
的EventType
或
其中一个超类型(即EventType.getSuperType()
)
- If the
EventHandler
was registered for the current phase of the event dispatching cycle (capturing or bubbling) - If the
EventHandler
was registered for the currentEvent
'sEventType
or one of the supertypes (i.e.EventType.getSuperType()
)
如果我们专注于场景图,当事件
被触发,它从场景图的顶部
(窗口
)开始,并通过层次结构传递到
目标(通常是 Node
,但至少是
EventTarget
的实现)。这是事件调度周期的捕获阶段。在
到达目标后,它会返回场景图,直到再次到达
窗口
。这是周期的冒泡阶段。
If we focus on the scene-graph, when an Event
is fired it starts at the top
of the scene-graph (the Window
) and travels through the hierarchy to
the target (usually a Node
, but at the very least an implementation of
EventTarget
). This is the "capturing" phase of the event dispatch cycle. After
reaching the target it travels back up the scene-graph until it reaches the
Window
again. This is the "bubbling" phase of the cycle.
-
窗口
- >场景
- >根节点
- >中间节点
- >EventTarget
Window
->Scene
->Root Node
->Middle Node
->EventTarget
-
窗口
< -场景
< -根节点
< -中间节点
< -EventTarget
Window
<-Scene
<-Root Node
<-Middle Node
<-EventTarget
如果在任何步骤事件$ c消费$ c>(通过
Event.consume()
)然后将
转发到下一步。这有效地阻止了在链中所需步骤处理
事件
。
If at any step the Event
is consumed (via Event.consume()
) then it will not
be forwarded to the next step. This effectively stops the processing of the
Event
at the desired step in the chain.
方式计算此路径是通过
EventDispatchChain
和 EventTarget
的实现来完成的。 EventTarget
必须使用以下方法实现
:
The way this path is computed is done by an implementation of
EventDispatchChain
and the EventTarget
. An EventTarget
must implement
the following method:
EventDispatchChain buildEventDispatchChain(EventDispatchChain tail);
当事件
被触发时,它有一个指定 EventTarget
。由于
EventTarget
将位于场景图的底部,因此自下而上构建的链是
。它通过在层次结构中的每个级别将 EventDispatcher
添加到
EventDispatchChain
来实现此目的(使用
EventDispatchChain.prepend(EventDispatcher)
)。这是 EventDispatcher
开始进入的地方。
When an Event
is fired it has a designated EventTarget
. Since the
EventTarget
will be at the bottom of the scene-graph the chain is
built from the bottom up. It does this by prepending an EventDispatcher
to the
EventDispatchChain
at each level in the hierarchy (using
EventDispatchChain.prepend(EventDispatcher)
). This is where EventDispatcher
starts to comes in.
每个 EventTarget
通常有自己的 EventDispatcher
与之关联。标准JavaFX中的 EventTarget
的
实现( Window
, Scene
,节点
,
MenuItem
等等......)提供自己的此事件
。在
这方面你不必担心如何使用 EventDispatcher
。你不用
甚至直接使用它。而是通过
[add | remove] EventHandler
和 EventHandler
s > [添加|删除] EventFilter 方法以及
各种 onXXX
属性。
Each EventTarget
usually has its own EventDispatcher
associated with it. The
implementations of EventTarget
in standard JavaFX (Window
, Scene
, Node
,
MenuItem
, etc...) provide their own implementations of EventDispatcher
. In
this regard you don't have to worry about how to use EventDispatcher
. You don't
even use it directly. Rather, you add EventHandler
s via the
[add|remove]EventHandler
and [add|remove]EventFilter
methods as well as
he various onXXX
properties.
当调用 buildEventDispatchChain
时,例如按钮
,按钮
将
的 EventDispatcher
预先添加到给定的 EventDispatchChain
。然后它在 Parent
上调用
buildEventDispatchChain
(如果有的话)。这继续高达
场景
的根节点
。根节点
在场景
buildEventDispatchChain
>在加上 EventDispatcher
之后,在
上对它附加的 Window
执行相同的操作。
When buildEventDispatchChain
is called on say, a Button
, the Button
prepends
its EventDispatcher
to the given EventDispatchChain
. It then calls
buildEventDispatchChain
on its Parent
if it has one. This continues up to
the root Node
of the Scene
. The root Node
calls buildEventDispatchChain
on said Scene
which, after prepending its EventDispatcher
, does the same on
the Window
it is attached to.
此时 EventDispatchChain
已完全构建,可以处理
事件
。如果不是很明显, EventDispatchChain
基本上只是
EventDispatcher
的堆栈。换句话说,它是一个高度专业化的
java.util.Deque
但没有实际扩展该接口。
At this point the EventDispatchChain
is fully built and is ready to process
the Event
. If not obvious yet, the EventDispatchChain
is fundamentally just
a "stack" of EventDispatcher
s. In other words, it is a highly specialized
java.util.Deque
but without actually extending that interface.
注意: EventDispatchChain
还为情况提供追加(EventDispatcher)
方法
其中前置是错误的操作。
一旦 EventDispatchChain
完全构建,就可以实际调度
事件
。这是通过在 EventDispatchChain
上调用此方法来完成的:
Once the EventDispatchChain
is fully built it is time to actually dispatch the
Event
. This is done by calling this method on the EventDispatchChain
:
Event dispatchEvent(Event event);
这有 EventDispatchChain
get(pop)
上的第一个 EventDispatcher
堆栈并调用其方法:
This has the EventDispatchChain
get (pop) the first EventDispatcher
on
the stack and call its method:
Event dispatchEvent(Event event, EventDispatchChain tail);
Side注意:不幸的是 EventDispatcher
该方法与
EventDispatchChain.dispatchEvent(Event)
具有类似的签名,这可能会导致混淆。
Side Note: Unfortunately EventDispatcher
's method has a similar signature to
EventDispatchChain.dispatchEvent(Event)
which may cause confusion.
附注2:尾部
将在$ b中与 EventDispatchChain
相同$ b整个过程。
Side Note #2: The tail
will be the same EventDispatchChain
throughout the
entire process.
这是实际使用 EventDispatcher
的地方。以下是内部
com.sun.javafx.event.BasicEventDispatcher <定义的每个
EventDispatcher
使用的算法
/ code> class(Java 10源代码):
This is where the EventDispatcher
s are actually used. Here is the algorithm
used by each EventDispatcher
as defined by the internal
com.sun.javafx.event.BasicEventDispatcher
class (Java 10 source code):
@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;
}
步骤如下:
- 为捕获阶段派遣
事件
- 此调用所有
EventHandler
已添加为过滤器 - 使用
事件
此处将不会停止在
此步骤中调度事件
;但是会阻止事件
在后续步骤中被处理
- 此调用所有
- Dispatch the
Event
for the capturing phase- This invokes all the
EventHandler
s that were added as a filter - Consuming an
Event
here will not stop the dispatching of theEvent
in this step; but will stop theEvent
from being processed in later steps
- This invokes all the
- 如果返回的
事件
为null
,则表示事件
在链的某处消耗
,不再需要处理 - 这会调用所有
EventHandler
s作为处理程序添加(其中
包括通过onXXX
属性添加的那些) - 与步骤#1一样,消耗
事件
此处不会停止处理
此步骤;但是会阻止事件
在后续步骤中被处理
- If the returned
Event
wasnull
that means theEvent
was consumed somewhere down the chain and no more processing is to be done - This invokes all the
EventHandler
s that where added as a handler (which includes the ones added via theonXXX
properties) - As with step #1, consuming an
Event
here does not stop the processing of this step; but will stop theEvent
from being processed in later steps
- 与
EventDispatchChain
一样,返回null
表示事件
消耗了
,处理事件
必须停止
- As with
EventDispatchChain
, returningnull
means theEvent
has been consumed and processing of theEvent
must stop
这是为每个 EventDispatcher
完成的 EventDispatchChain
。调用
到 tail.dispatchEvent
基本上是一个递归操作(没有它是
真正的递归)。实际上,这段代码向下遍历堆栈(调用
tail.dispatchEvent
),然后向上走回堆栈(当尾部时。 dispatchEvent
返回)。并且链中的每个链接在递归
调用(捕获阶段)之前和递归调用返回之后(冒泡
阶段)进行处理。
This is done for each EventDispatcher
in the EventDispatchChain
. The call
to tail.dispatchEvent
is bascially a "recursive" operation (without it being
"real" recursion). In effect this code walks down the stack (the calls to
tail.dispatchEvent
) and then walks back up the stack (when tail.dispatchEvent
returns). And each "link in the chain" does processing before the "recursive"
call (the capturing phase) and after the "recursive" call returns (the bubbling
phase).
但请注意,在每一步中, EventDispatcher
实际上是
实际调用每个相应的事件处理程序
秒。 这是如何使用
EventDispatcher
。
Notice here, though, that at each step it is the EventDispatcher
that is
actually invoking each of the appropriate EventHandler
s. This is how an
EventDispatcher
is used.
扩展已实现<$ c的类时$ c> EventTarget 那么当绝对需要时,你应该只有
创建你自己的 EventDispatcher
。如果你的目标是
控制,如果事件
达到某个 EventTarget
那么你的首选应该是
是在适当的地方消费事件
(Jai在
评论中提到)。如果你想改变一些关于 Event
路径的信息,那么你
可能需要提供你自己的 EventDispatcher
。但是,由于内部 EventDispatcher
实现的封闭式
性质,加上
的事实 EventDispatcher
接口有限,您可能会限制
来包装您自己的实现中的原始 EventDispatcher
,并在必要时委托
。我已经在其他人的代码中看到了这一点(甚至可能在JavaFX本身看到了
)但是我记不起代码就足以给你
的例子。
When extending a class that already implements EventTarget
then you should only
create your own EventDispatcher
when absolutely needed. If your goal is to
control if an Event
reaches a certain EventTarget
then your first choice should
be to consume the Event
at the appropriate place (mentioned by Jai in the
comments). If you want to alter something about the path of the Event
then you
might need to provide your own EventDispatcher
. However, due to the closed
nature of the internal EventDispatcher
implementations, coupled with the fact
that the EventDispatcher
interface is limited, you will probably be restricted
to wrapping the original EventDispatcher
in your own implementation and delegating
when necessary. I've seen this done in other people's code (might have even seen
it in JavaFX itself) but I can't remember the code well enough to give you
examples of this.
如果您从头创建拥有 <$ em> c> EventTarget ,那么您将需要
来实现您的拥有 EventDispatcher
。如果你做
,要注意的一些事情需要你自己的实现:
If you are creating your own EventTarget
from scratch then you will have to
implement your own EventDispatcher
. Some things to keep in mind if you do
need your own implementation:
- 它只能调用
EventHandler
已注册当前阶段(如果
将有阶段) - 它必须只调用
EventHandler
注册事件
的EventType
并说EventType
的超类型 - 它必须将
事件
转发到尾部EventDispatchChain
- 如果
事件必须只返回
null
已消耗code> - 必须能够通过相同的
线程进行并发修改
- 原因是因为
EventHandler
可能会自行删除或
添加/删除另一个EventHandler
,而其句柄
方法正在执行。这个
将在EventDispatcher
以某种方式迭代EventHandler
s
时发生。
- It must only invoke the
EventHandler
s registered for the current phase (if there are to be phases) - It must only invoke the
EventHandler
s registered for theEvent
'sEventType
and saidEventType
's supertypes - It must forward the
Event
to the tailEventDispatchChain
- It must only return
null
if theEvent
has been consumed - It must be capable of concurrent modification by the same
Thread
- The reason for this is because an
EventHandler
may remove itself or add/remove anotherEventHandler
while itshandle
method is executing. This will take place while theEventDispatcher
is iterating theEventHandler
s in some way.
- 注意:我不确定这是否实际上是合同的一部分,如果您的实施不需要,可能不是
。
这篇关于JavaFX - EventDispatcher和EventFilter之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- The reason for this is because an
- 原因是因为