如何发出和处理自定义事件?

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

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

一般来说:

  1. 创建所需的EventType 。
  2. 创建相应的事件 。
  3. 调用Node.fireEvent() 。
  4. 为感兴趣的EventType添加处理程序和/或filter 。

一些解释:

如果要创建事件级联,请以“全部”或“任何”类型开头,这将是所有EventType的根:

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

这样就可以创建这种类型的后代:

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

然后编写MyEvent类(扩展Event )。 应该为此事件类键入EventTypes(就像我的示例一样)。

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

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

如果你想抓住这个事件:

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

这是一个(稍微过于复杂)的示例应用程序,演示了eckig在其(优秀)答案中概述的一些概念。

该示例创建了一个视野,该视野是反应堆节点的平铺窗格。 自定义闪电事件会定期发送到随机节点,该节点在收到事件时会闪烁黄色。 filter和处理程序将添加到父字段,并将其调用报告给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 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 { @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 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 getEventType() { return (EventType) super.getEventType(); } } }