JavaFX - EventDispatcher和EventFilter之间的区别 [英] JavaFX - Difference between EventDispatcher and EventFilter

查看:191
本文介绍了JavaFX - EventDispatcher和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 EventHandlers. 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 current Event's EventType 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

如果在任何步骤事件(通过 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 EventHandlers 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 EventDispatchers. 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 EventDispatchers 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;
}

步骤如下:


  1. 为捕获阶段派遣事件


    • 此调用所有 EventHandler 已添加为过滤器

    • 使用事件此处将不会停止在
      此步骤中调度事件 ;但是会阻止事件在后续步骤中被处理

  1. Dispatch the Event for the capturing phase
    • This invokes all the EventHandlers that were added as a filter
    • Consuming an Event here will not stop the dispatching of the Event in this step; but will stop the Event from being processed in later steps

  • 如果返回的事件 null ,则表示事件在链的某处消耗
    ,不再需要处理

  • 这会调用所有 EventHandler s作为处理程序添加(其中
    包括通过 onXXX 属性添加的那些)

  • 与步骤#1一样,消耗事件此处不会停止处理
    此步骤
    ;但是会阻止事件在后续步骤中被处理

  • If the returned Event was null that means the Event was consumed somewhere down the chain and no more processing is to be done
  • This invokes all the EventHandlers that where added as a handler (which includes the ones added via the onXXX properties)
  • As with step #1, consuming an Event here does not stop the processing of this step; but will stop the Event from being processed in later steps

  • EventDispatchChain 一样,返回 null 表示事件消耗了
    ,处理事件必须停止

  • As with EventDispatchChain, returning null means the Event has been consumed and processing of the Event 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 EventHandlers. 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 EventHandlers registered for the current phase (if there are to be phases)
    • It must only invoke the EventHandlers registered for the Event's EventType and said EventType's supertypes
    • It must forward the Event to the tail EventDispatchChain
    • It must only return null if the Event 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 another EventHandler while its handle method is executing. This will take place while the EventDispatcher is iterating the EventHandlers in some way.

      • 注意:我不确定这是否实际上是合同的一部分,如果您的实施不需要,可能不是

      这篇关于JavaFX - EventDispatcher和EventFilter之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆