自定义事件调度程序 - JavaFX

尤克

有谁知道如何基于 javafx.event 包编写自定义事件调度程序?我在 Google & Co. 中搜索过,但没有找到一个很好的例子。

有没有人给我一个简约的例子?那会很好 - 我尝试了几次以理解它,但我失败了。

色拉

首先要意识到的是 JavaFX 是如何调度事件的。

当 anEvent被触发时,它有一个关联的EventTarget. 如果目标在场景图中,则路径从Event开始Window并沿着场景图向下直到EventTarget到达。Event随后进入备份的场景图,直到它到达Window一次。这分别称为“捕获阶段”和“冒泡阶段”。在捕获阶段调用事件过滤器,在冒泡阶段调用事件处理程序EventHandler使用onXXX属性(例如onMouseClicked设置s是特殊类型的处理程序(即不是过滤器)。

EventDispatcher接口有以下方法:

public Event dispatchEvent(Event event, EventDispatChain tail) { ... }

在这里,eventEvent被调度的,tailEventDispatchChain构建的,可能是递归的,由EventTarget.buildEventDispatchChain(EventDispatchChain)null如果event在方法执行期间消耗了 ,这将返回

EventDispatchChain是一个堆栈EventDispatcher每次你打电话时,tail.dispatchEvent(event)你本质上都是EventDispatcher从顶部弹出一个并调用它。

@Override
public Event dispatchEvent(Event event, EventDispatchChain tail) {
    // First, dispatch event for the capturing phase
    event = dispatchCapturingEvent(event);

    if (event.isConsumed()) {
        // One of the EventHandlers invoked in dispatchCapturingEvent
        // consumed the event. Return null to indicate processing is complete
        return null;
    }

    // Forward the event to the next EventDispatcher in the chain
    // (i.e. on the stack). This will start the "capturing" on the
    // next EventDispatcher. Returns null if event was consumed down
    // the chain
    event = tail.dispatchEvent(event);

    // once we've reached this point the capturing phase has completed

    if (event != null) {
        // Not consumed from down the chain so we now handle the
        // bubbling phase of the process
        event = dispatchBubblingEvent(event);

        if (event.isConsumed()) {
            // One of the EventHandlers invoked in dispatchBubblingEvent
            // consumed the event. Return null to indicate processing is complete
            return null;
        }
    }

    // return the event, or null if tail.dispatchEvent returned null
    return event;
}

您可能想知道dispatchCapturingEventdispatchBubblingEvent在哪里定义的。这些方法将由您创建并调用适当的EventHandlers。您可能还想知道为什么这些方法返回Event. 原因很简单:在的处理Event这些方法,伴随着tail.dispatchEvent,可能会改变Eventconsume()然而,除了 之外Event它的子类基本上是不可变的。这意味着任何其他更改都需要创建一个新的Event. 事件处理过程的其余部分应该使用这个新的 Event

对 的调用tail.dispatchEvent实际上总是返回 的新实例Event这是由于每一个这样的事实EventDispatcherEventDispatchChain通常与它自己的相关联的(例如一个LabelWindow)。EventHandler被调用的源Event 必须是相同的Object,该EventHandler所注册的; 如果 anEventHandler是用 a 注册的,Window那么在 said的执行过程中event.getSource()必须返回那个实现这一点的方法是使用该方法。WindowEventHandlerEvent.copyFor(Object,EventTarget)

Event oldEvent = ...;
Event newEvent = oldEvent.copyFor(newSource, oldEvent.getTarget());

如您所见,EventTarget通常始终保持不变。此外,子类可以覆盖,copyFor而其他子类,例如MouseEvent,也可以定义重载。

事件实际上是如何发送到EventHandlers 的?好吧, 的内部实现EventDispatcher使它们成为EventHandlers的一种“集合” 每个都EventDispatcher跟踪onXXX已添加到其关联源(例如Node或从中删除的所有过滤器、处理程序和属性处理程序()。EventDispatcher没有这样做,但它需要一种方法来访问无论你存储EventHandler秒。

在捕获阶段的EventDispatcher调用所有适当 EventHandlers可通过加入addEventFilter(EventType,EventHandler)然后,在冒泡阶段,EventDispatcher调用通过(例如添加的所有适当的 EventHandlers addEventHandler(EventType,EventHandler) setOnXXXsetOnMouseClicked

我所说的适当是什么意思

每个被解雇的人Event都有一个相关的EventType. 说得EventType可能都超了EventType例如,“继承”树MouseEvent.MOUSE_ENTERED是:

Event.ANY
    InputEvent.ANY
        MouseEvent.ANY
            MouseEvent.MOUSE_ENTERED_TARGET
                MouseEvent.MOUSE_ENTERED

在调度 an 时,Event您必须调用EventHandlerEvent'sEventType 所有EventType's 超类型注册所有s。另外,还要注意,食用的Event没有停止在处理Event当前阶段的的电流EventDispatcher,而是完成调用一切适当EventHandler秒。一旦相位 EventDispatcher已经完成,然而,的处理Event停止。

无论您使用何种机制来存储EventHandlers,都必须能够由同一线程进行并发修改这是因为对于相同的阶段,一个人EventHandler可能会EventHandler在相同的来源中添加或删除另一个EventType如果您将它们存储在常规中,List这意味着List在您迭代时可能会对其进行修改。EventHandler可以自行删除的 的现成示例WeakEventHandlerWeakEventHandler如果在“垃圾收集”之后调用它,A将尝试删除自身。

另外,我不知道这是否是必需的,但内部实现不允许EventHandler为相同的源EventType、 和阶段多次注册相同的内容但是请记住,EventHandler添加的 viaaddEventHandler和添加的 viasetOnXXX是分开处理的,即使它们都在同一阶段(冒泡)期间被调用。此外,调用会setOnXXX替换EventHandler同一属性的任何先前设置。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章