I have following code:
package pl.javastart.youtufy.controller;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;
public class ConnectionErrorController implements Initializable {
#FXML
private Label infoLabel;
#FXML
private Button tryButton;
#FXML
private Button exitButton;
#Override
public void initialize(URL location, ResourceBundle resources) {
MainController mc = new MainController();
infoLabel.setText("Connection lost, please try again");
tryButton.setText("try again");
exitButton.setText("exit");
tryButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
WebEngine webEngine = mc.getContentPaneController().getVideoWebView().getEngine(); // 1
ToggleButton playButton = mc.getControlPaneController().getPlayButton(); // 2
Node source = (Node) event.getSource();
Stage stage = (Stage) source.getScene().getWindow();
if (mc.testInet()) {
stage.close();
mc.play(webEngine, playButton);
} else {
stage.close();
MainController.exist = false;
}
}
});
exitButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Platform.exit();
}
});
}
}
I am trying to use WebEngine and ToggleButton Objects from controllers in MainController (I generated getters and setters to them in MainController):
public class MainController implements Initializable {
#FXML
private ContentPaneController contentPaneController;
#FXML
private ControlPaneController controlPaneController;
#FXML
private MenuPaneController menuPaneController;
#FXML
private SearchPaneController searchPaneController;
private Youtube youtubeInstance;
public static boolean exist = false;
public ControlPaneController getControlPaneController() {
return controlPaneController;
}
public void setControlPaneController(ControlPaneController controlPaneController) {
this.controlPaneController = controlPaneController;
}
public ContentPaneController getContentPaneController() {
return contentPaneController;
}
public void setContentPaneController(ContentPaneController contentPaneController) {
this.contentPaneController = contentPaneController;
}
But its still returns NullPointerException. I had same problem, when I tried simply make references to the controllers in ConnectionErrorController. How to refer to the ToggleButton i WebEngine Objects from controllers in ConnectionErrorController properly?
Regards
You are creating a controller instance "by hand" with
MainController mc = new MainController();
#FXML-annotated fields are initialized by the FXMLLoader when it creates the controller for you as part of the process of loading the FXML file. Since the controller you created is not the controller instance created by the FXMLLoader, its #FXML-annotated fields are uninitialized (i.e. they are null), and hence you get a null pointer exception.
You can get a reference to the controller created by the FXMLLoader by calling getController() on the FXMLLoader instance after calling load().
If you want one controller to communicate with another, then pass the reference to one controller to the other controller, by defining appropriate methods in the second controller:
public class ConnectionErrorController implements Initializable {
private MainController mainController ;
public void setMainController(MainController mainController) {
this.mainController = mainController ;
}
// ...
#Override
public void initialize(URL location, ResourceBundle resources) {
infoLabel.setText("Connection lost, please try again");
tryButton.setText("try again");
exitButton.setText("exit");
tryButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
WebEngine webEngine = mainController.getContentPaneController().getVideoWebView().getEngine(); // 1
ToggleButton playButton = mainController.getControlPaneController().getPlayButton(); // 2
if (mainController.testInet()) {
mainController.play(webEngine, playButton);
} else {
// obviously you can now do something better than the "public static field hack" here:
MainController.exist = false;
}
tryButton.getScene().getWindow().hide();
}
});
// ...
}
}
Assuming you are loading the second fxml file in a method in MainController, you can then just do something like:
public class MainController {
// ...
public void showConnectionErrorWindow(String fileName) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/ConnectionError.fxml"));
Parent root = loader.load();
ConnectionErrorController connectionErrorController = loader.getController();
connectionErrorController.setMainController(this);
Scene scene = new Scene(root);
Stage stage = new Stage();
// etc...
}
// ...
}
Note that there are much more elegant ways of solving this problem, such as passing the ConnectionErrorController a callback function (in the form of a lambda expression) to process the call to play(...), which avoid the tight coupling between the ConnectionErrorController and the MainController. However, as you seem to be new to Java, this simpler approach might be more suitable.
See Passing Parameters JavaFX FXML for more information on passing values to controllers.
Related
Please help me solve the problem. There are two fxml files and their controllers:
sample.fxml, its controller ControllerMain (main window of the program)
find_win.fxml, its ControllerFind controller (modal window "text search")
In the modal window find_win.fxml there is a TextField into which the search text is entered, and the Find button, when clicked, ControllerFind must process the click and call the search method and highlight the search text in the TextArea element of the sample.fxml window.
<fx: include source = "sample.fxml" fx: id = "textAreaOne" />
and the inheritance of the ControllerMain by the ControllerFind controller does not help to achieve a solution - in the first case the entire window markup is included in the modal window completely, in the second case, the java.lang.reflect.InvocationTargetException is returned during an operation on the TextArea.
How to implement actions on elements of one window from another window?
I've found a solution elsewhere. Thanks to Comrade Antizam, who tried to help, but did not quite understand what I needed.
The solution described here is .
In short, it is necessary to create an instance of a controller-parent and a method that takes an instance of a controller-parent as a parameter in the controller-child. When a new window is opened from a controller-parent, get an instance of the controller-child and indicate to it through the created method "this".
Further, in the controller-child, it will be possible to access the elements of the parent controller.
controller-parent:
package sample;
public class ControllerMain {
private ControllerFind children; // controller-child
//main-window
#FXML
public TextArea textAreaOne;
#FXML
public MenuItem findMenuItem;
public void findAction(ActionEvent actionEvent) {
try {
Stage stageFind = new Stage();
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("FXML/find_win.fxml"));
Parent root = loader.load();
stageFind.setTitle("Find");
stageFind.setMinHeight(200);
stageFind.setMinWidth(150);
stageFind.setResizable(false);
stageFind.setScene(new Scene(root));
stageFind.getIcons().add(new Image("image/search.png"));
stageFind.initModality(Modality.NONE);
stageFind.show();
children = loader.getController(); //getting controller of window find_win.fxml
children.setParent(this); //setting parent of the controller-child - this
} catch (IOException e) {
e.printStackTrace();
}
}
}
controller-child:
package sample.Controllers;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
import sample.Classes.DialogManager;
import sample.ControllerMain;
public class ControllerFind {
//Window "Find"
#FXML public TextField searchTextField;
#FXML public Label findTextLabel;
#FXML public Button okTextFindButton;
#FXML public Button cancelTextFindButton;
private String text;
private ControllerMain controller;
public void setParent (ControllerMain controller){
this.controller = controller;
}
public ControllerFind getThis(){
return this;
}
public void initialize(){
System.out.println("psvm");
}
public void textFindOkButtonAction(ActionEvent actionEvent) {
text = (searchTextField.getText());
if (text.equals("")) {
DialogManager.showInfoDialog("Error!", "Enter text what you are looking for!");
} else {
if (controller.textAreaOne.getText() != null && !controller.textAreaOne.getText().isEmpty()) {
int index = controller.textAreaOne.getText().indexOf(text);
if (index == -1) {
DialogManager.showInfoDialog("Result", "There isn't text what you are looking for");
} else {
controller.textAreaOne.selectRange(index, index + text.length());
}
} else {
DialogManager.showInfoDialog("Error", "TextArea is empty!");
}
}
}
public void textFindCancelButtonAction(ActionEvent actionEvent) {
Node source = (Node) actionEvent.getSource();
Stage stage = (Stage) source.getScene().getWindow();
stage.close();
}
}
Vis-a-vis windows communication in this situation, it's optimal to use TextInputDialog something like this:
#Override
public void start(Stage primaryStage){
Button btn=new Button("Click");
VBox vbox=new VBox();
vbox.setAlignment(Pos.CENTER);
vbox.getChildren().addAll(btn);
Scene scene=new Scene(vbox, 200,200);
btn.setOnAction(e->
{
TextInputDialog dialog=new TextInputDialog();
Optional<String> result = dialog.showAndWait();
if (result.isPresent()){
System.out.println(result.get());
}
});
primaryStage.setScene(scene);
primaryStage.show();
}
but text highlighting is not something that can be done easy.
You could do String search of TextArea text, compare it to result from another window then highlight it via
textArea.getSelectedRange(firstIndex, lastIndex);
firstIndex and lastIndex being indexes of textArea text for the word we are searching. Then having button on every click displaying next word occurancy inside text and highlighting it. But if you insist on highlighting every instance of word at the same time I would suggest using RichTextFX.
I have two separate views one which contains a button say view A and another a TabPane with 3 tabs call it view B. These two views are controlled by two separate view controller classes. I want to be able to click a button in view A and be able to to open a specific tab in view B's TabPane.
So far I have tried extending the controller for view A with view B such that I can get the TabPane defined in view B's controller then call myTabPane.getSelectionModel().select(myTab); however this hasn't worked as it throws a NullPointerException.
My question is it possible to click a button in view A such that it opens view B and opens a specific Tab on view B's TabPane.
I have also looked at these links with no luck 1. setting selected tab, 2. switch through tabs programatically, 3. switch between tabs in tabpane
Lets say the above image is view A and when u click right it should open view B and open a specific tab in view B's TabPane.
Lets say the above image is view B and when the button right on view A is clicked it should open view B and set the tab to tab C.
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.Initializable;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.stage.Stage;
import javafx.scene.control.SelectionModel;
public class SucessfulCreateProjectViewController extends AdminViewController {
#FXML
private Button OkButton;
#FXML
void handleCreateTasksButtonAction(ActionEvent event) {
try{
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("AdminView.fxml"));
Scene scene = new Scene(fxmlLoader.load());
Stage stage = new Stage();
stage.setScene(scene);
stage.show();
AdminTabPane.getSelectionModel().select(1);;
}catch(Exception e){
ErrorHandlerController.infoBox("Error Opening AdminPage", "Fail", null);
e.printStackTrace();
}
}
#FXML
void handleOKButtonAction(ActionEvent event) {
Stage stage = (Stage) OkButton.getScene().getWindow();
stage.close();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
// TODO
} }
Mediator is a design pattern that is used to communicate between objects that do not know each other.
This is an example of a mediator that would have done your job.
public class Mediator {
private static Mediator instance;
private Consumer<String> consumer;
public static Mediator getInstance() {
if(instance == null) {
instance = new Mediator();
}
return instance;
}
private Mediator() {
}
public void register(Consumer<String> consumer) {
this.consumer = consumer;
}
public void fireEvent(String string) {
if(consumer != null) {
consumer.accept(string);
}
}
}
and respectively, the two controllers
public class ViewAController {
#FXML
private Button btnL, btnR;
#FXML
private void initialize() {
btnL.setOnAction(event -> Mediator.getInstance().fireEvent("left"));
btnR.setOnAction(event -> Mediator.getInstance().fireEvent("right"));
}
}
public class ViewBController {
#FXML
private TabPane tabPane;
#FXML
private void initialize() {
Mediator.getInstance().register(s -> {
switch (s) {
case "left":
tabPane.getSelectionModel().select(0);
break;
case "right":
tabPane.getSelectionModel().select(2);
break;
}
});
}
}
and this is a test application that opens two windows at once.
public class Main extends Application {
#Override
public void start(Stage stageA) throws Exception{
Parent viewA = FXMLLoader.load(getClass().getResource("view_a.fxml"));
Parent viewB = FXMLLoader.load(getClass().getResource("view_b.fxml"));
stageA.setTitle("View A");
stageA.setScene(new Scene(viewA));
stageA.show();
Stage stageB = new Stage();
stageB.setTitle("View B");
stageB.setScene(new Scene(viewB));
stageB.show();
}
public static void main(String[] args) {
launch(args);
}
}
if you do not want to use two windows at once, just change the middleman.
I have following code:
package pl.javastart.youtufy.controller;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ToggleButton;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;
public class ConnectionErrorController implements Initializable {
#FXML
private Label infoLabel;
#FXML
private Button tryButton;
#FXML
private Button exitButton;
#Override
public void initialize(URL location, ResourceBundle resources) {
MainController mc = new MainController();
infoLabel.setText("Connection lost, please try again");
tryButton.setText("try again");
exitButton.setText("exit");
tryButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
WebEngine webEngine = mc.getContentPaneController().getVideoWebView().getEngine(); // 1
ToggleButton playButton = mc.getControlPaneController().getPlayButton(); // 2
Node source = (Node) event.getSource();
Stage stage = (Stage) source.getScene().getWindow();
if (mc.testInet()) {
stage.close();
mc.play(webEngine, playButton);
} else {
stage.close();
MainController.exist = false;
}
}
});
exitButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
Platform.exit();
}
});
}
}
I am trying to use WebEngine and ToggleButton Objects from controllers in MainController (I generated getters and setters to them in MainController):
public class MainController implements Initializable {
#FXML
private ContentPaneController contentPaneController;
#FXML
private ControlPaneController controlPaneController;
#FXML
private MenuPaneController menuPaneController;
#FXML
private SearchPaneController searchPaneController;
private Youtube youtubeInstance;
public static boolean exist = false;
public ControlPaneController getControlPaneController() {
return controlPaneController;
}
public void setControlPaneController(ControlPaneController controlPaneController) {
this.controlPaneController = controlPaneController;
}
public ContentPaneController getContentPaneController() {
return contentPaneController;
}
public void setContentPaneController(ContentPaneController contentPaneController) {
this.contentPaneController = contentPaneController;
}
But its still returns NullPointerException. I had same problem, when I tried simply make references to the controllers in ConnectionErrorController. How to refer to the ToggleButton i WebEngine Objects from controllers in ConnectionErrorController properly?
Regards
You are creating a controller instance "by hand" with
MainController mc = new MainController();
#FXML-annotated fields are initialized by the FXMLLoader when it creates the controller for you as part of the process of loading the FXML file. Since the controller you created is not the controller instance created by the FXMLLoader, its #FXML-annotated fields are uninitialized (i.e. they are null), and hence you get a null pointer exception.
You can get a reference to the controller created by the FXMLLoader by calling getController() on the FXMLLoader instance after calling load().
If you want one controller to communicate with another, then pass the reference to one controller to the other controller, by defining appropriate methods in the second controller:
public class ConnectionErrorController implements Initializable {
private MainController mainController ;
public void setMainController(MainController mainController) {
this.mainController = mainController ;
}
// ...
#Override
public void initialize(URL location, ResourceBundle resources) {
infoLabel.setText("Connection lost, please try again");
tryButton.setText("try again");
exitButton.setText("exit");
tryButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
WebEngine webEngine = mainController.getContentPaneController().getVideoWebView().getEngine(); // 1
ToggleButton playButton = mainController.getControlPaneController().getPlayButton(); // 2
if (mainController.testInet()) {
mainController.play(webEngine, playButton);
} else {
// obviously you can now do something better than the "public static field hack" here:
MainController.exist = false;
}
tryButton.getScene().getWindow().hide();
}
});
// ...
}
}
Assuming you are loading the second fxml file in a method in MainController, you can then just do something like:
public class MainController {
// ...
public void showConnectionErrorWindow(String fileName) {
FXMLLoader loader = new FXMLLoader(getClass().getResource("path/to/ConnectionError.fxml"));
Parent root = loader.load();
ConnectionErrorController connectionErrorController = loader.getController();
connectionErrorController.setMainController(this);
Scene scene = new Scene(root);
Stage stage = new Stage();
// etc...
}
// ...
}
Note that there are much more elegant ways of solving this problem, such as passing the ConnectionErrorController a callback function (in the form of a lambda expression) to process the call to play(...), which avoid the tight coupling between the ConnectionErrorController and the MainController. However, as you seem to be new to Java, this simpler approach might be more suitable.
See Passing Parameters JavaFX FXML for more information on passing values to controllers.
My stage contains a ToggleSwitch and two StackPanes which we'll call A and B. Both StackPanes are located in the same space within the parent StackPane. This means that if both A and B are visible and set to managed, they each take up half the allocated space like this:
I'm trying to hide StackPane B upon initalization so that StackPane A takes up the full space... and then when I click the toggle button, it should hide StackPane A and show StackPane B, making B take up the full space.
The initial hiding of StackPane B works fine, but I'm having trouble writing a change listener for the ToggleSwitch in my controller class. Here is my code, and where I'm having trouble:
application class:
public class showPanes extends Application {
Stage stage = new Stage();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws IOException {
StackPane root = (StackPane) FXMLLoader.load(Drag.class.getResource("twoPanes.fxml"));
Scene scene = new Scene(root);
stage.setTitle("Pane Switcher");
scene.getStylesheets().add("styleMain.css");
stage.setScene(scene);
stage.show();
}
}
The answer found here uses Toggle Groups, and James' answer here uses Buttons. I can't find a solution for ToggleSwitch. I tried to adapt the first answer for use with ToggleSwitch but it's producing an error like:
and says
Cannot resolve method 'addListener(anonymous
javafx.beans.value.ChangeListener)'
How do I fix the listener?
controller class:
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.scene.layout.StackPane;
import java.net.URL;
import java.util.ResourceBundle;
import org.controlsfx.control.ToggleSwitch;
public class compsController implements Initializable {
#FXML
private StackPane paneA, paneB;
#FXML
private ToggleSwitch toggleSwitch;
#Override
public void initialize(URL location, ResourceBundle resources) {
paneB.setManaged(false);
paneB.setVisible(false);
toggleSwitch.selectedProperty().addListener(new ChangeListener < ToggleSwitch > () {
#Override
public void changed(ObservableValue < ? extends ToggleSwitch > ov, ToggleSwitch t, ToggleSwitch t1) {
paneA.setManaged(false);
paneA.setVisible(false);
paneB.setManaged(true);
paneB.setVisible(true);
}
});
}
}
You could also use the Binding API of JavaFx like below,
#Override
public void initialize(URL location, ResourceBundle resources) {
paneA.managedProperty().bind(toggleSwitch.selectedProperty());
paneA.visibleProperty().bind(toggleSwitch.selectedProperty());
paneB.managedProperty().bind(toggleSwitch.selectedProperty().not());
paneB.visibleProperty().bind(toggleSwitch.selectedProperty().not());
}
}
Is there a way to get the current opened Stage in JavaFX, if there is one open?
Something like this:
Stage newStage = new Stage();
newStage.initOwner(JavaFx.getCurrentOpenedStage()); //Like this
Java 9 makes this possible by the addition of the javafx.stage.Window.getWindows() method. Therefore you can just get list of Windows and see which are showing
List<Window> open = Stage.getWindows().stream().filter(Window::isShowing);
If you need the current stage reference inside an event handler method, you can get it from the ActionEvent param. For example:
#FXML
public void OnButtonClick(ActionEvent event) {
Stage stage = (Stage)((Node) event.getSource()).getScene().getWindow();
(...)
}
You can also get it from any control declared in your controller:
#FXML
private Button buttonSave;
(...)
Stage stage = (Stage) buttonSave.getScene().getWindow();
There's no built-in functionality for this. In most use cases, you open a new Stage as a result of user action, so you can call getScene().getWindow() on the node on which the action occurred to get the "current" window.
In other use cases, you will have to write code to track current windows yourself. Of course, multiple windows might be open, so you need to track them in some kind of collection. I'd recommend creating a factory class to manage the stages and registering event handlers for the stages opening and closing, so you can update a property and/or list. You'd probably want this to be a singleton. Here's a sample implementation: here getOpenStages() gives an observable list of open stages - the last one is the most recently opened - and currentStageProperty() gives the focused stage (if any). Your exact implementation might be different, depending on your exact needs.
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 ;
}
}
Note this only allows you to track stages obtained from StageFactory.INSTANCE.createStage() or created elsewhere and passed to the StageFactory.INSTANCE.registerStage(...) method, so your code has to collaborate with that requirement. On the other hand, it gives you the chance to centralize code that initializes your stages, which may be otherwise beneficial.
Here's a simple example using this:
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);
}
}
You can create a label in your java fxml.
Then in your controller class refer your label like this :
#FXML
private Label label;
Then in any function of the controller class you can access the current stage by this block of code :
private void any_function(){
Stage stage;
stage=(Stage) label.getScene().getWindow();
}