JavaFX-EventDispatcher和EventFilter之间的区别

时间:2018-06-25 02:10:17

标签: javafx event-handling

我试图了解何时在JavaFX中使用EventDispatcher。我非常了解捕获和冒泡的所有事件机制。但是我仍然对EventDispatcher的目的感到困惑。因为我可以使用过滤器和处理程序来完成大部分工作。

有人可以解释一下实际目的以及如何使用此EventDispatcher吗?

谢谢。

1 个答案:

答案 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()在链中所需的步骤。

此路径的计算方式由的实现实现 EventEventDispatchChainEventTarget必须实现 以下方法:

EventTarget

触发EventDispatchChain buildEventDispatchChain(EventDispatchChain tail); 时,它具有指定的Event。自从 EventTarget将在场景图的底部,链是 从头开始。它是通过在EventTarget前面添加{ EventDispatcher在层次结构的每个级别(使用 EventDispatchChain)。这是EventDispatchChain.prepend(EventDispatcher) 开始出现。

每个EventDispatcher通常都有自己的EventTarget关联。的 EventDispatcher在标准JavaFX(EventTargetWindowSceneNode等)提供自己的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

步骤是:

  1. 为捕获阶段调度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在后​​续步骤中得到处理
  2. 如果EventHandler被消耗,则返回Event,否则将Event转发到 Event,然后等待返回
  3. 如果Event不返回null,则分派Event 起泡阶段
    • 如果返回的tailtail.dispatchEvent,则意味着null已被消耗 链中的某个地方,无需进行其他处理
    • 这会调用所有添加为 handler Event( 包括通过Event属性添加的内容)
    • 与步骤#1一样,在这里消耗null 不会停止处理 此步骤;但会阻止Event在后​​续步骤中得到处理
  4. 如果EventHandler被消耗,则返回onXXX,否则返回Event
    • Event一样,返回Event表示nullEvent的消耗和处理必须停止

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
    • 注意:我不确定这是否实际上是合同的一部分,并且可能不是 如果您的实现不需要它,则为必需。