javafx中有几个预定义的事件类。 Event.ANY,KeyEvent.KEY_TYPED,MouseEvent.ANY等。还有用于事件的高级过滤和处理系统。我想重复使用它来发送一些自定义信号。
如何创建自定义事件类型CustomEvent.Any,以编程方式发出此事件并在节点中处理它?
答案 0 :(得分:40)
一般来说:
一些解释:
如果您想创建一个事件级联,请从"全部"开始。或"任何" type,它将是所有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(...));
答案 1 :(得分:20)
这是一个(稍微过于复杂)的示例应用程序,展示了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();
}
}
}