为了账号安全,请及时绑定邮箱和手机立即绑定

如何正确设置自定义事件

如何正确设置自定义事件

茅侃侃 2022-12-15 16:19:49
好的 - 我已经为此奋斗了很久,阅读了一百万篇文章、教程等。它们似乎都没有直接解决我在这里想做的事情。我有这个小代码示例来说明。基本上,我希望能够从按钮引发/触发自定义事件并让标签响应该事件。(请注意,除了我在这里尝试使用实际的 Event 对象之外,我没有兴趣寻找其他方法来做到这一点。我非常清楚如何使用更改侦听器等来做到这一点,但我想学习如何这样做。)这是代码,您可以看到它没有得到我正在寻找的结果。其中大部分来自一些示例(对我来说并没有真正起作用),我承认这里有些部分让我“呼呼”。如果有人可以帮助我让它工作,我可以稍后对其进行剖析以确保我了解到底发生了什么。这是代码:import javafx.application.Application;import javafx.beans.property.ObjectProperty;import javafx.beans.property.SimpleObjectProperty;import javafx.event.Event;import javafx.event.EventHandler;import javafx.event.EventType;import javafx.geometry.Insets;import javafx.geometry.Pos;import javafx.scene.Scene;import javafx.sene.control.Button;import javafx.scene.control.Label;import javafx.scene.layout.VBox;import javafx.stage.Stage;//-------------------------------------------------------------------public class MyDemo extends Application {    public static void main(String[] args) {    launch(args);    }    @Override    public void start(Stage primaryStage) {    // label that should receive the event and react to it    MyLabel lblReceiver = new MyLabel("And I Should Receive & React");    // button to firs the event    Button btnSender = new Button("Initate Event");    btnSender.setPrefWidth(200);    btnSender.setOnAction(e -> {        MyEvent.fireEvent(lblReceiver, e); // really confused what the first parameter here is supposed to be.    });    // set up stage and show it    Stage stage = new Stage();    VBox root = new VBox(btnSender, lblReceiver);    root.setSpacing(10);    root.setPadding(new Insets(10, 10, 10, 10));    Scene scene = new Scene(root);    stage.setScene(scene);    stage.show();    }}
查看完整描述

1 回答

?
翻翻过去那场雪

TA贡献2065条经验 获得超13个赞

回答

除了两个问题外,您似乎已正确设置所有内容。


你永远不会添加一个EventHandler监听你的事件的。


实现任意接口不会使您的对象对您的自定义事件做出反应。事件处理系统不知道你的接口,甚至不知道你已经实现了它。如果您希望onMyEvent()在事件到达标签时调用您的方法,则需要执行以下操作:


public MyLabel() {

    //...

    addEventHandler(MyEvent.MY_EVENT, event -> onMyEvent());

}

请注意,我使用addEventHandler的是类本身不依赖于该onMyEvent属性。如果您依赖该属性,则外部代码可能会通过替换EventHandler.


这让我想知道MyEventListener接口是否真的有必要。你不能在里面做你需要的EventHandler吗?


您实际上从未触发过您的MyEvent.


您目前拥有:


btnSender.setOnAction(e -> MyEvent.fireEvent(lblReceiver, e));

这只是将e(an ActionEvent) 重新点燃到lblReceiver. 该fireEvent方法是由static声明的方法javafx.event.Event。为方法调用加上前缀MyEvent不会改变此处实际调用的方法。将其更改为以下内容:


btnSender.setOnAction(e -> Event.fireEvent(lblReceiver, new MyEvent()));

// or...

btnSender.setOnAction(e -> lblReceiver.fireEvent(new MyEvent()));


// The second option is a convenience method and simply forwards to Event.fireEvent

为了在您的标签上实际触发您自己的事件类的实例。

事件派发基础

JavaFX 中的事件处理有两个阶段:

  • 捕获阶段

    • 第一阶段。在这里,事件从其路径的起点向下传播到目标。在此过程中的每一步,都会调用适当的事件过滤器。过滤器是通过诸如Node.addEventFilter(EventType,EventHandler).

  • 冒泡阶段

    • 第二阶段。在这里,事件从目标返回到路径的起点。在此过程中的每一步,都会调用适当的事件处理程序。处理程序是通过诸如 和 之类的方法和Node.addEventHandler(EventType,EventHandler)属性添加的。Node.onKeyPressedButtonBase.onAction

事件处理由以下组件组成:

  • javafx.event.Event(和子类)

    • 实际对象传递过来。携带与事件相关的信息(例如MouseEvents 的光标位置)。

      一个Event也携带来源。但是,来源是动态的;它始终是EventHandler当前处理事件的对象。因此,EventHandler添加到 a的事件Button将具有Button作为事件源的事件,但同一事件将具有父级作为EventHandler添加到父级的源。即使您EventHandler两次使用同一个实例,此行为也不会改变。

  • javafx.event.EventType

    • 细化一类的含义Event。例如,MouseEvent带有MOUSE_PRESSED类型的 a 毫不奇怪地表示鼠标被按下了。一个EventType有一个超类型;这为每种事件形成了所有类型的层次结构。为超类型注册的处理程序也将收到子类型的通知。

      不能有两个或多个EventType具有相同超类型和名称的 s。这就是为什么实例通常public static final是相应事件类的字段。

  • javafx.event.EventHandler

    • 处理其注册的任何事件。这是一个功能接口(可以是 lambda 表达式或方法引用的目标)。执行应用程序级工作的是此接口的实现(即,在触发按钮时执行某些操作)。

  • javafx.event.EventDispatcher

    • 负责将事件分派给适当的处理程序。每个能够成为事件目标的对象通常都有自己的调度程序。例如,每个WindowSceneNodeinstance 都有自己的EventDispatcher实例(保存在属性中)。

      注意:在高度专业化的情况之外,您永远不必直接处理此接口。

  • javafx.event.EventDispatchChain

    • 表示事件在目标处触发时将采用的路径。此接口的实例用作EventDispatchers 的堆栈。触发事件时,将根据事件的目标创建和配置新链。在场景图和目标是 a 的情况下Node,堆栈由EventDispatcher属于 s的 s 组成WindowScene然后每个Node向下到(父到子)并包括目标。事件沿这条链向下传播(捕获阶段),然后返回这条链(冒泡阶段)。

      注意:您可能永远不需要直接使用此界面。

  • javafx.event.EventTarget

    • 事件的实际目标。该EventTarget接口具有一种用于构建EventDispatchChain. 换句话说,目标决定了事件的路径。这是中的第一个参数Event.fireEvent(EventTarget,Event)

      注意:如果您正在创建一个可以(显然)成为事件目标的对象(并且您的对象不是从 的实现扩展的EventTarget),则只需要使用此接口。



查看完整回答
反对 回复 2022-12-15
  • 1 回答
  • 0 关注
  • 85 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信