如何发出和处理自定义事件?
Posted
技术标签:
【中文标题】如何发出和处理自定义事件?【英文标题】:How to emit and handle custom events? 【发布时间】:2015-02-09 13:51:14 【问题描述】:javafx 中有几个预定义的事件类。 Event.ANY、KeyEvent.KEY_TYPED、MouseEvent.ANY 等等。还有用于事件的高级过滤和处理系统。而且我想重用它来发送一些自定义信号。
如何创建自定义事件类型 CustomEvent.Any,以编程方式发出此事件并在节点中处理它?
【问题讨论】:
【参考方案1】:一般:
-
创建所需的EventType。
创建对应的Event。
致电Node.fireEvent()。
为感兴趣的 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();
【讨论】:
以上是关于如何发出和处理自定义事件?的主要内容,如果未能解决你的问题,请参考以下文章