Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to emit and handle custom events?

There are several predefined event classes in javafx. Event.ANY, KeyEvent.KEY_TYPED, MouseEvent.ANY and so on. There is also advanced filtering and handling system for events. And I'd like to reuse it to send some custom signals.

How can I create my custom event type CustomEvent.Any, emit this event programmatically and handle it in a node?

like image 426
ayvango Avatar asked Dec 11 '14 06:12

ayvango


People also ask

Which method is used to publish your own custom event?

Publishing custom events To publish custom events, we will need an instance of ApplicationEventPublisher and then call the method ApplicationEventPublisher#publishEvent(..) . Another way to publish event is to use ApplicationContext#publishEvent(....) .

What are the two types of custom events?

Custom events can be created in two ways: Using the Event constructor. Using the CustomEvent constructor.

Which module allows us to create and handle custom events?

Node. js uses events module to create and handle custom events. The EventEmitter class can be used to create and handle custom events module.


2 Answers

In general:

  1. Create a desired EventType.
  2. Create the corresponding Event.
  3. Call Node.fireEvent().
  4. Add Handlers and/or Filters for EventTypes of interest.

Some explanations:

If you want to create an event cascade, start with an "All" or "Any" type, that will be the root of all of the EventTypes:

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

This makes possible creating descendants of this type:

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

Then write the MyEvent class (which extends Event). The EventTypes should be typed to this event class (as is my example).

Now use (or in other words: fire) the event:

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

If you want to catch this event:

Node node = ....; node.addEventHandler(OPTIONS_ALL, event -> handle(...)); node.addEventHandler(BEFORE_STORE, event -> handle(...)); 
like image 198
eckig Avatar answered Sep 20 '22 15:09

eckig


Here is a (slightly over-complicated) sample application demonstrating some of the concepts that eckig outlines in his (excellent) answer.

The sample creates a visual field which is a tiled pane of reactor nodes. A custom lightning event is periodically sent to a random node, which will flash yellow when it receives the event. Filters and handlers are added to the parent field and their invocation reported to system.out so that you can see the event bubbling and capturing phases in action.

The code for the LightningEvent itself was mainly copied directly from the standard ActionEvent code in the JavaFX source, your event code could probably be a little simpler.

enter image description here

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();         }      }  } 
like image 44
jewelsea Avatar answered Sep 19 '22 15:09

jewelsea