【问题标题】:How to emit and handle custom events?如何发出和处理自定义事件?
【发布时间】:2015-02-09 13:51:14
【问题描述】:

javafx 中有几个预定义的事件类。 Event.ANY、KeyEvent.KEY_TYPED、MouseEvent.ANY 等等。还有用于事件的高级过滤和处理系统。而且我想重用它来发送一些自定义信号。

如何创建自定义事件类型 CustomEvent.Any,以编程方式发出此事件并在节点中处理它?

【问题讨论】:

    标签: java events javafx


    【解决方案1】:

    一般:

    1. 创建所需的EventType
    2. 创建对应的Event
    3. 致电Node.fireEvent()
    4. 为感兴趣的 EventType 添加 Handlers 和/或 Filters

    一些解释:

    如果要创建事件级联,请从“All”或“Any”类型开始,这将是所有 EventTypes 的根:

    EventType<MyEvent> OPTIONS_ALL = new EventType<>("OPTIONS_ALL");
    

    这使得创建这种类型的后代成为可能:

    EventType<MyEvent> BEFORE_STORE = new EventType<>(OPTIONS_ALL, "BEFORE_STORE");
    

    然后编写MyEvent 类(扩展Event)。 EventTypes 应该输入到这个事件类中(就像我的例子一样)。

    现在使用(或换句话说:触发)事件:

    Event myEvent = new MyEvent();
    Node node = ....;
    node.fireEvent(myEvent);
    

    如果你想抓住这个事件:

    Node node = ....;
    node.addEventHandler(OPTIONS_ALL, event -> handle(...));
    node.addEventHandler(BEFORE_STORE, event -> handle(...));
    

    【讨论】:

      【解决方案2】:

      这是一个(有点过于复杂的)示例应用程序,展示了 eckig 在他的(优秀)答案中概述的一些概念。

      该示例创建了一个视野,该视野是反应器节点的平铺窗格。自定义闪电事件会定期发送到随机节点,当它收到事件时会闪烁黄色。过滤器和处理程序被添加到父字段,并将它们的调用报告给 system.out,以便您可以看到事件冒泡和捕获阶段的动作。

      LightningEvent 本身的代码主要是直接从 JavaFX 源中的标准 ActionEvent 代码中复制而来,您的事件代码可能会简单一些。

      import javafx.animation.*;
      import javafx.application.Application;
      import javafx.event.*;
      import javafx.scene.Scene;
      import javafx.scene.layout.TilePane;
      import javafx.scene.paint.Color;
      import javafx.scene.shape.Rectangle;
      import javafx.stage.Stage;
      import javafx.util.Duration;
      
      import java.util.Random;
      
      public class LightningSimulator extends Application {
          private static final int FIELD_SIZE = 10;
      
          private static final Random random = new Random(42);
      
          @Override
          public void start(Stage stage) throws Exception {
              TilePane field = generateField();
      
              Scene scene = new Scene(field);
              stage.setScene(scene);
              stage.setResizable(false);
              stage.show();
      
              field.addEventFilter(
                      LightningEvent.PLASMA_STRIKE,
                      event -> System.out.println(
                              "Field filtered strike: " + event.getI() + ", " + event.getJ()
                      )
              );
      
              field.addEventHandler(
                      LightningEvent.PLASMA_STRIKE,
                      event -> System.out.println(
                              "Field handled strike: " + event.getI() + ", " + event.getJ()
                      )
              );
      
              periodicallyStrikeRandomNodes(field);
          }
      
          private void periodicallyStrikeRandomNodes(TilePane field) {
              Timeline timeline = new Timeline(
                      new KeyFrame(
                              Duration.seconds(0),
                              event -> strikeRandomNode(field)
                      ),
                      new KeyFrame(
                              Duration.seconds(2)
                      )
              );
      
              timeline.setCycleCount(Timeline.INDEFINITE);
              timeline.play();
          }
      
          private void strikeRandomNode(TilePane field) {
              LightningReactor struckNode = (LightningReactor)
                      field.getChildren()
                              .get(
                                      random.nextInt(
                                              FIELD_SIZE * FIELD_SIZE
                                      )
                              );
              LightningEvent lightningStrike = new LightningEvent(
                      this,
                      struckNode
              );
      
              struckNode.fireEvent(lightningStrike);
          }
      
          private TilePane generateField() {
              TilePane field = new TilePane();
              field.setPrefColumns(10);
              field.setMinWidth(TilePane.USE_PREF_SIZE);
              field.setMaxWidth(TilePane.USE_PREF_SIZE);
      
              for (int i = 0; i < 10; i++) {
                  for (int j = 0; j < 10; j++) {
                      field.getChildren().add(
                              new LightningReactor(
                                      i, j,
                                      new StrikeEventHandler()
                              )
                      );
                  }
              }
              return field;
          }
      
          private class LightningReactor extends Rectangle {
              private static final int SIZE = 20;
              private final int i;
              private final int j;
      
              private FillTransition fillTransition = new FillTransition(Duration.seconds(4));
      
              public LightningReactor(int i, int j, EventHandler<? super LightningEvent> lightningEventHandler) {
                  super(SIZE, SIZE);
      
                  this.i = i;
                  this.j = j;
      
                  Color baseColor =
                          (i + j) % 2 == 0
                                  ? Color.RED
                                  : Color.WHITE;
                  setFill(baseColor);
      
                  fillTransition.setFromValue(Color.YELLOW);
                  fillTransition.setToValue(baseColor);
                  fillTransition.setShape(this);
      
                  addEventHandler(
                          LightningEvent.PLASMA_STRIKE,
                          lightningEventHandler
                  );
              }
      
              public void strike() {
                  fillTransition.playFromStart();
              }
      
              public int getI() {
                  return i;
              }
      
              public int getJ() {
                  return j;
              }
          }
      
          private class StrikeEventHandler implements EventHandler<LightningEvent> {
              @Override
              public void handle(LightningEvent event) {
                  LightningReactor reactor = (LightningReactor) event.getTarget();
                  reactor.strike();
      
                  System.out.println("Reactor received strike: " + reactor.getI() + ", " + reactor.getJ());
      
      
                  // event.consume();  if event is consumed the handler for the parent node will not be invoked.
              }
          }
      
          static class LightningEvent extends Event {
      
              private static final long serialVersionUID = 20121107L;
      
              private int i, j;
      
              public int getI() {
                  return i;
              }
      
              public int getJ() {
                  return j;
              }
      
              /**
               * The only valid EventType for the CustomEvent.
               */
              public static final EventType<LightningEvent> PLASMA_STRIKE =
                      new EventType<>(Event.ANY, "PLASMA_STRIKE");
      
              /**
               * Creates a new {@code LightningEvent} with an event type of {@code PLASMA_STRIKE}.
               * The source and target of the event is set to {@code NULL_SOURCE_TARGET}.
               */
              public LightningEvent() {
                  super(PLASMA_STRIKE);
              }
      
              /**
               * Construct a new {@code LightningEvent} with the specified event source and target.
               * If the source or target is set to {@code null}, it is replaced by the
               * {@code NULL_SOURCE_TARGET} value. All LightningEvents have their type set to
               * {@code PLASMA_STRIKE}.
               *
               * @param source    the event source which sent the event
               * @param target    the event target to associate with the event
               */
              public LightningEvent(Object source, EventTarget target) {
                  super(source, target, PLASMA_STRIKE);
      
                  this.i = ((LightningReactor) target).getI();
                  this.j = ((LightningReactor) target).getJ();
              }
      
              @Override
              public LightningEvent copyFor(Object newSource, EventTarget newTarget) {
                  return (LightningEvent) super.copyFor(newSource, newTarget);
              }
      
              @Override
              public EventType<? extends LightningEvent> getEventType() {
                  return (EventType<? extends LightningEvent>) super.getEventType();
              }
      
          }
      
      }
      

      【讨论】:

        猜你喜欢
        • 2020-02-17
        • 1970-01-01
        • 2014-12-19
        • 1970-01-01
        • 1970-01-01
        • 2018-05-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多