如何制作自定义事件,该事件在Stage.setScene()
上触发?
在我的代码中,该按钮可切换场景,效果很好。但是,我想扩展舞台,使其具有一个额外的事件,当按钮或其他任何元素触发setScene时会触发该事件。
示例:
package sample;
import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
Application.launch(args);
}
@Override
public void start(Stage stage) {
Group g1 = new Group();
Button b1 = new Button("2");
g1.getChildren().setAll(b1);
Scene scene1 = new Scene(g1, 50, 50);
Group g2 = new Group();
Button b2 = new Button("1");
g2.getChildren().setAll(b2);
Scene scene2 = new Scene(g2, 50, 50);
stage.setScene(scene1);
stage.setTitle("JavaFX Application Life Cycle");
b1.setOnAction(actionEvent -> {
System.out.println("1");
stage.setScene(scene2);
});
b2.setOnAction(actionEvent -> {
System.out.println("2");
stage.setScene(scene1);
});
stage.show();
}
}
答案 0 :(得分:5)
您可以像这样在您的ChangeListener<Scene>
中添加一个Stage
:
stage.sceneProperty().addListener((observable, oldScene, newScene) -> {
System.out.println("New scene: " + newScene);
System.out.println("Old scene: " + oldScene);
});
答案 1 :(得分:1)
我相信,如the answer by @M.S.所示,使用监听器可能是对场景变化做出反应的最佳和最简单的方法。但是,您询问如何制作一个“自定义事件”,以便在场景更改时可以触发该事件。通过“事件”,我假设您的意思是javafx.event.Event
的子类。因此,尽管我建议坚持使用简单的侦听器,但这是自定义事件的示例。
首先,您需要一个自定义事件类:
import javafx.event.Event;
import javafx.event.EventType;
import javafx.scene.Scene;
import javafx.stage.Window;
public class SceneChangedEvent extends Event {
public static final EventType<SceneChangedEvent> SCENE_CHANGED =
new EventType<>(Event.ANY, "SCENE_CHANGED");
public static final EventType<SceneChangedEvent> ANY = SCENE_CHANGED;
private transient Window window;
private transient Scene oldScene;
private transient Scene newScene;
public SceneChangedEvent(Window window, Scene oldScene, Scene newScene) {
super(window, window, SCENE_CHANGED);
this.window = window;
this.oldScene = oldScene;
this.newScene = newScene;
}
public Window getWindow() {
return window;
}
public Scene getOldScene() {
return oldScene;
}
public Scene getNewScene() {
return newScene;
}
}
我不确定您希望随事件携带哪些信息,因此我只添加了源Window
以及新旧Scene
。如果您对ANY = SCENE_CHANGED
感到疑惑,我只是遵循javafx.event.ActionEvent
使用的模式(它也只有一个事件类型)。
然后,您只需要在场景更改时触发事件即可。为了实现这一点,您仍然需要一个变更监听器。正如您提到的要扩展Stage
一样,下面是一个示例:
import javafx.beans.NamedArg;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.event.EventHandler;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class CustomStage extends Stage {
private final ObjectProperty<EventHandler<? super SceneChangedEvent>> onSceneChanged =
new SimpleObjectProperty<>(this, "onSceneChanged") {
@Override
protected void invalidated() {
setEventHandler(SceneChangedEvent.SCENE_CHANGED, get());
}
};
public final void setOnSceneChanged(EventHandler<? super SceneChangedEvent> handler) {
onSceneChanged.set(handler);
}
public final EventHandler<? super SceneChangedEvent> getOnSceneChanged() {
return onSceneChanged.get();
}
public final ObjectProperty<EventHandler<? super SceneChangedEvent>> onSceneChangedProperty() {
return onSceneChanged;
}
public CustomStage() {
this(StageStyle.DECORATED);
}
public CustomStage(@NamedArg(value = "style", defaultValue = "DECORATED") StageStyle style) {
super(style);
sceneProperty().addListener((obs, ov, nv) -> fireEvent(new SceneChangedEvent(this, ov, nv)));
}
}
这将使您使用以下任何一种方式对场景变化做出反应:
CustomStage stage = new CustomStage();
// addEventFilter/addEventHandler
stage.addEventFilter(SceneChangedEvent.SCENE_CHANGED, e -> { ... });
stage.addEventHandler(SceneChangedEvent.SCENE_CHANGED, e -> { ... });
// setOnSceneChanged
stage.setOnSceneChanged(e -> { ... });
请记住,该事件将仅针对CustomStage
实例。换句话说,只有添加到CustomStage
实例的事件处理程序才会收到该事件的通知。正如您所看到的,这比简单地向scene
的{{1}}属性添加更改侦听器要复杂得多。