如何在JavaFX中获得当前打开的阶段?

时间:2015-10-03 12:14:01

标签: java javafx

有没有办法在JavaFX中获取当前打开的Stage,如果有一个打开的话?

这样的事情:

Stage newStage = new Stage();
newStage.initOwner(JavaFx.getCurrentOpenedStage()); //Like this

4 个答案:

答案 0 :(得分:10)

这没有内置功能。在大多数用例中,由于用户操作而打开新的Stage,因此您可以在发生操作的节点上调用getScene().getWindow()以获取“当前”窗口。

在其他用例中,您必须自己编写代码来跟踪当前窗口。当然,多个窗口可能是打开的,因此您需要在某种集合中跟踪它们。我建议创建一个工厂类来管理阶段并为阶段的打开和关闭注册事件处理程序,这样您就可以更新属性和/或列表。你可能希望这是一个单身人士。这是一个示例实现:这里getOpenStages()给出了一个可观察的开放阶段列表 - 最后一个是最近打开的阶段 - 而currentStageProperty()给出了关注阶段(如果有的话)。您的确切实施可能会有所不同,具体取决于您的确切需求。

public enum StageFactory {
    INSTANCE ;

    private final ObservableList<Stage> openStages = FXCollections.observableArrayList();

    public ObservableList<Stage> getOpenStages() {
        return openStages ;
    }

    private final ObjectProperty<Stage> currentStage = new SimpleObjectProperty<>(null);
    public final ObjectProperty<Stage> currentStageProperty() {
        return this.currentStage;
    }
    public final javafx.stage.Stage getCurrentStage() {
        return this.currentStageProperty().get();
    }
    public final void setCurrentStage(final javafx.stage.Stage currentStage) {
        this.currentStageProperty().set(currentStage);
    }

    public void registerStage(Stage stage) {
        stage.addEventHandler(WindowEvent.WINDOW_SHOWN, e -> 
                openStages.add(stage));
        stage.addEventHandler(WindowEvent.WINDOW_HIDDEN, e -> 
                openStages.remove(stage));
        stage.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
            if (isNowFocused) {
                currentStage.set(stage);
            } else {
                currentStage.set(null);
            }
        });
    }

    public Stage createStage() {
        Stage stage = new Stage();
        registerStage(stage);
        return stage ;
    }

}

请注意,这只允许您跟踪从StageFactory.INSTANCE.createStage()获取或在其他位置创建并传递到StageFactory.INSTANCE.registerStage(...)方法的阶段,因此您的代码必须与该要求协作。另一方面,它让您有机会集中初始化阶段的代码,这可能是有益的。

这是一个使用它的简单示例:

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

public class SceneTrackingExample extends Application {

    int count = 0 ;

    @Override
    public void start(Stage primaryStage) {
        StageFactory factory = StageFactory.INSTANCE ;
        factory.registerStage(primaryStage);

        configureStage(primaryStage);
        primaryStage.show();
    }

    private void configureStage(Stage stage) {
        StageFactory stageFactory = StageFactory.INSTANCE;
        Stage owner = stageFactory.getCurrentStage() ;
        Label ownerLabel = new Label();
        if (owner == null) {
            ownerLabel.setText("No owner");
        } else {
            ownerLabel.setText("Owner: "+owner.getTitle());
            stage.initOwner(owner);
        }
        stage.setTitle("Stage "+(++count));
        Button newStage = new Button("New Stage");
        newStage.setOnAction(e -> {
            Stage s = stageFactory.createStage();
            Stage current = stageFactory.getCurrentStage() ;
            if (current != null) {
                s.setX(current.getX() + 20);
                s.setY(current.getY() + 20);
            }
            configureStage(s);
            s.show();
        });

        VBox root = new VBox(10, ownerLabel, newStage);
        root.setAlignment(Pos.CENTER);
        stage.setScene(new Scene(root, 360, 150));
    }

    public enum StageFactory {
        INSTANCE ;

        private final ObservableList<Stage> openStages = FXCollections.observableArrayList();

        public ObservableList<Stage> getOpenStages() {
            return openStages ;
        }

        private final ObjectProperty<Stage> currentStage = new SimpleObjectProperty<>(null);
        public final ObjectProperty<Stage> currentStageProperty() {
            return this.currentStage;
        }
        public final javafx.stage.Stage getCurrentStage() {
            return this.currentStageProperty().get();
        }
        public final void setCurrentStage(final javafx.stage.Stage currentStage) {
            this.currentStageProperty().set(currentStage);
        }

        public void registerStage(Stage stage) {
            stage.addEventHandler(WindowEvent.WINDOW_SHOWN, e -> 
                    openStages.add(stage));
            stage.addEventHandler(WindowEvent.WINDOW_HIDDEN, e -> 
                    openStages.remove(stage));
            stage.focusedProperty().addListener((obs, wasFocused, isNowFocused) -> {
                if (isNowFocused) {
                    currentStage.set(stage);
                } else {
                    currentStage.set(null);
                }
            });
        }

        public Stage createStage() {
            Stage stage = new Stage();
            registerStage(stage);
            return stage ;
        }

    }

    public static void main(String[] args) {
        launch(args);
    }
}

答案 1 :(得分:5)

Java 9通过添加javafx.stage.Window.getWindows()方法实现了这一点。因此,您只需获取Windows列表并查看正在显示的内容

List<Window> open = Stage.getWindows().filtered(window -> window.isShowing());

答案 2 :(得分:2)

如果需要事件处理程序方法中的当前阶段引用,则可以从ActionEvent参数中获取它。例如:

    @FXML
    public void OnButtonClick(ActionEvent event) {

        Stage stage = (Stage)((Node) event.getSource()).getScene().getWindow();

       (...)
    }

您也可以从控制器中声明的任何控件中获取它:

@FXML
private Button buttonSave;

(...)    

Stage stage = (Stage) buttonSave.getScene().getWindow();

答案 3 :(得分:0)

您可以在java fxml中创建标签。

然后在你的控制器类中引用你的标签:

@FXML private Label label;

然后在控制器类的任何函数中,您可以通过以下代码块访问当前阶段:

private void any_function(){
        Stage stage;
        stage=(Stage) label.getScene().getWindow();
}