Java 默认情况下,为什么按钮鼠标事件处理程序使用事件?

Java 默认情况下,为什么按钮鼠标事件处理程序使用事件?,java,events,javafx,Java,Events,Javafx,谢谢你对我上一篇文章的帮助(这也是我的第一篇文章)。我是新来的。我要是早点加入这个团体就好了。这里的人们非常有礼貌,乐于助人 无论如何,我一直在努力更好地理解javafx事件。对你们中的一些人来说,这可能是另一个简单或“愚蠢”的问题为什么默认情况下按钮鼠标事件处理程序似乎使用事件? 从中,在页面底部,它指出“请注意,JavaFXUI控件的默认处理程序通常使用大多数输入事件。”这是我不知道的附加到按钮的默认处理程序吗?为什么我必须在目标节点显式地触发事件,以使其在事件调度链中冒泡 再次感谢您的回复

谢谢你对我上一篇文章的帮助(这也是我的第一篇文章)。我是新来的。我要是早点加入这个团体就好了。这里的人们非常有礼貌,乐于助人

无论如何,我一直在努力更好地理解javafx事件。对你们中的一些人来说,这可能是另一个简单或“愚蠢”的问题为什么默认情况下按钮鼠标事件处理程序似乎使用事件?

从中,在页面底部,它指出“请注意,JavaFXUI控件的默认处理程序通常使用大多数输入事件。”这是我不知道的附加到按钮的默认处理程序吗?为什么我必须在目标节点显式地触发事件,以使其在事件调度链中冒泡

再次感谢您的回复!:)


默认按钮皮肤实现调用。如果不希望出现这种行为,请覆盖默认蒙皮并将该值设置为false

btn.setSkin(new ButtonSkin(btn) {
    {
        this.consumeMouseEvents(false);
    }
});
然后,单击示例应用程序按钮的输出将为:

btn mouse pressed...
layout mouse pressed...
root mouse pressed...
scene mouse pressed...
为什么会这样,我说不清。我的猜测是,如果皮肤消耗了事件,那么这有助于防止控件不必要地传播鼠标事件,例如当控件分层或堆叠在另一个控件上时。这可能是您几乎一直想要的行为,因此是一个合理的默认值。

您链接的文档中的“输入事件”指的是包中的事件子类。这些是“低级”事件,例如
MouseEvent
KeyEvent
。通常,对于控件,您对这样的事件不感兴趣,而是对更高级别的“语义”事件感兴趣,例如

以按钮为例,您通常编写在用户打算使用按钮提交“操作”时调用的代码。这实际上可能是由用户用鼠标单击按钮,或者在按钮具有键盘焦点时按空格键,或者如果按钮是默认按钮,则按enter键,或者按与按钮关联的助记符匹配的某个按键来实现的。在所有这些示例中,用户打算通过“物理”操作实现相同的含义:这是与按钮关联的“操作”

因此,为了便于您编写代码,该按钮封装了所有这些不同的行为,并将它们重新打包为“操作”。它通过注册低级事件(鼠标按下和按键等)的侦听器来实现这一点。如果发生这些情况,则按钮本身会处理它们并触发一个操作事件。由于低级事件现在被视为已被处理,因此会被消耗,从而防止其在场景图层次结构中冒泡

因此,通常应在控件(如按钮)上查找“高级”或“语义”事件:

btn.setOnAction(e -> System.out.println("Action performed on button"));
如果用户点击一个按钮,它(显然)被认为是该按钮上的一个“动作”,而不是点击持有该按钮的任何容器。我不能完全解释为什么要做出这个设计决定,但通常我认为没有在按钮的父级上触发鼠标点击事件是有意义的

如果确实需要侦听鼠标在容器上的单击,即使它们实际上发生在容器所包含的控件上,也可以使用事件筛选器在它们到达控件之前处理它们:

layout.addEventFilter(MouseEvent.MOUSE_PRESSED, 
    e -> { System.out.println("layout mouse pressed...");});

问题是“为什么事件不会在组件层次结构中冒泡?”我认为您需要重新表述您的问题…@Juan和MeltingDog在oracle文档中这样说:“在达到事件目标并且所有注册的筛选器都处理完事件之后,事件将沿着从目标到根节点的调度链返回。”我想我应该按照Juan的建议重新表述这个问题。你们可能会注意到,如果我注释掉“layout.firevent(e)”,事件调度链上就不会出现任何事件。我只是想知道为什么?为什么事件不沿着调度链从目标(在这里是按钮)返回到根节点(场景)?@James和jewelsea你们都回答了我的问题。我想这就是为什么文档中说“默认处理程序…消耗了大部分输入事件”如果不是jewelsea向我展示了底层实现和James的解释,我仍然会挠头。我认为sun应该在他们的文档上工作。我的猜测是,文档在这里故意含糊不清,因为这样更易于维护,只是说“使用大部分输入事件”将涵盖其他可能使用的输入事件,例如按键事件、触摸事件以及鼠标事件。试图按事件类型对此进行详尽的文档记录可能会导致文档不一致,并且随着时间的推移,文档维护会变得困难。一般来说,文档中给出的描述在大多数情况下都是“足够好的”,如果你真的想了解更多,你可以运行一些测试或查看源代码。顺便说一句,好问题。关于“为什么它会这样工作?”问题,我遇到过希望与不支持拖动手势识别器的Java 1.1兼容的实现,因此默认情况下使用事件意味着可以保留回退拖动实现以实现向后兼容。显然,随着时间的推移,这一点不再那么重要,但可能有助于深入了解为什么最初是这样做的。
layout.addEventFilter(MouseEvent.MOUSE_PRESSED, 
    e -> { System.out.println("layout mouse pressed...");});