how to add custom skin for textField in javafx using css? - javafx

I am trying to add a default skin to text Field using css but its not working as i expect it to.
I expect a right button in text Field like one's in Metro theme of Win8.
Here is fxml i am using
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="300.0" prefWidth="400.0" stylesheets="#custom.css" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8">
<children>
<TextField layoutX="126.0" layoutY="138.0" />
</children>
</AnchorPane>
Here is css :
.text-field{
-fx-skin: "application.MetroTextFieldSkin";
}
And here are 2 skin classes i am using :
first one :
package application;
import com.sun.javafx.scene.control.skin.TextFieldSkin;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
/**
* Created by pedro_000 on 12/5/13.
*/
public class MetroTextFieldSkin extends TextFieldWithButtonSkin{
public MetroTextFieldSkin(TextField textField) {
super(textField);
}
protected void rightButtonPressed()
{
getSkinnable().setText("");
}
}
2nd one :
package application;
import com.sun.javafx.scene.control.behavior.TextFieldBehavior;
import com.sun.javafx.scene.control.skin.TextFieldSkin;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.VPos;
import javafx.scene.control.Skin;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
public class TextFieldWithButtonSkin extends TextFieldSkin{
private StackPane rightButton;
private Region rightButtonGraphic;
protected TextField textField;
public TextFieldWithButtonSkin(TextField textField) {
super(textField);
this.textField = textField;
rightButton = new StackPane();
rightButton.getStyleClass().setAll("right-button");
rightButton.setFocusTraversable(false);
rightButtonGraphic = new Region();
rightButtonGraphic.getStyleClass().setAll("right-button-graphic");
rightButtonGraphic.setFocusTraversable(false);
rightButtonGraphic.setMaxWidth(Region.USE_PREF_SIZE);
rightButtonGraphic.setMaxHeight(Region.USE_PREF_SIZE);
rightButton.setVisible(false);
rightButtonGraphic.setVisible(false);
rightButton.getChildren().add(rightButtonGraphic);
getChildren().add(rightButton);
setupListeners();
}
private void setupListeners() {
final TextField textField = getSkinnable();
rightButton.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
rightButtonPressed();
}
});
rightButton.setOnMouseReleased(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
rightButtonReleased();
}
});
textField.textProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
textChanged();
}
});
textField.focusedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
focusChanged();
}
});
}
protected void textChanged()
{
if (textField.getText() == null)
return;
System.out.println(textField.getText().isEmpty());
rightButton.setVisible(!textField.getText().isEmpty());
rightButtonGraphic.setVisible(!textField.getText().isEmpty());
}
protected void focusChanged()
{
if (textField.getText() == null)
return;
rightButton.setVisible(textField.isFocused() && !textField.getText().isEmpty());
rightButtonGraphic.setVisible(textField.isFocused() && !textField.getText().isEmpty());
}
#Override
protected void layoutChildren(double x, double y, double w, double h) {
super.layoutChildren(x, y, w, h);
final double clearGraphicWidth = snapSize(rightButtonGraphic.prefWidth(-1));
final double clearButtonWidth = rightButton.snappedLeftInset() + clearGraphicWidth + rightButton.snappedRightInset();
rightButton.resize(clearButtonWidth, h);
positionInArea(rightButton,
(x+w) - clearButtonWidth, y,
clearButtonWidth, h, 0, HPos.CENTER, VPos.CENTER);
}
protected void rightButtonPressed()
{
}
protected void rightButtonReleased()
{
}
}
Am i missing something which is necessary to make it work.
These are actualy created by pedro for his theme jMetro.

Related

Can't seem to programmatically select TextField from TableCell (TextFieldTableCell-like) when adding a row to TableView (JavaFX 8)

In JavaFX 8, I have created a custom TableCell with a TextField to get more control than with a "regular" TextFieldTableCell. What I want to achieve is to have that TextField automatically selected when an Add button is clicked (so the user doesn't have to click on that TextField or Tab to it after the Add-Record button is fired. Unfortunately, I only manage to select the row/cell but not the underlying TextField (and the startEdit() method doesn't seem to be reached).
Here is my code (Main FX Application code, POJO, FXML code created in Scene Builder, Controller code, and CustomTextFieldTableCell class):
Main.java
package test;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
POJO
package test;
import javafx.beans.property.SimpleStringProperty;
class TestObject {
private final SimpleStringProperty field1 = new SimpleStringProperty();
private final SimpleStringProperty field2 = new SimpleStringProperty();
public SimpleStringProperty field1Property() {
return field1;
}
public void setField1(String string) {
field1.set(string);
}
public SimpleStringProperty field2Property() {
return field2;
}
public void setField2(String string) {
field2.set(string);
}
}
FXMLDocument.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane id="AnchorPane" prefHeight="425.0" prefWidth="517.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.171" fx:controller="test.FXMLDocumentController">
<children>
<Label fx:id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" />
<TableView fx:id="tableView" layoutX="14.0" layoutY="52.0" prefHeight="359.0" prefWidth="489.0" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="14.0" AnchorPane.topAnchor="52.0">
<columns>
<TableColumn fx:id="col1" prefWidth="150.0" text="C1" />
<TableColumn fx:id="col2" minWidth="0.0" prefWidth="141.0" text="C2" />
</columns>
</TableView>
<Button fx:id="btnAdd" layoutX="14.0" layoutY="14.0" onAction="#handleAdd" text="_Add" />
</children>
</AnchorPane>
FXMLDocumentController.java
package test;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
public class FXMLDocumentController implements Initializable {
#FXML
private Button btnAdd;
#FXML
private TableView<TestObject> tableView;
#FXML
private TableColumn<TestObject, String> col1;
#FXML
private TableColumn<TestObject, String> col2;
#FXML
private void handleAdd(ActionEvent event) {
TestObject testObject = new TestObject();
tableView.getItems().add(testObject);
tableView.edit(tableView.getItems().indexOf(testObject), col1);
}
#Override
public void initialize(URL url, ResourceBundle rb) {
col1.setCellValueFactory(cellData -> cellData.getValue().field1Property());
col1.setCellFactory((final TableColumn<TestObject, String> column) -> new CustomTextFieldTableCell());
col1.setOnEditStart((TableColumn.CellEditEvent<TestObject, String> event) -> {
//Inside code doesn't seem to ever get reached
System.out.println("Edit started");
});
col2.setCellValueFactory(cellData -> cellData.getValue().field2Property());
col2.setCellFactory((final TableColumn<TestObject, String> column) -> new TableCell<>());
}
}
CustomTextFieldTableCell.java
package test;
import javafx.event.ActionEvent;
import javafx.scene.control.TableCell;
import javafx.scene.control.TextField;
public class CustomTextFieldTableCell extends TableCell<TestObject, String> {
private final TextField textField;
public CustomTextFieldTableCell() {
textField = new TextField();
textField.setOnAction((ActionEvent event) -> {
commitEdit(textField.getText());
event.consume();
});
textField.prefWidthProperty().bind(prefWidthProperty().subtract(3));
}
/** {#inheritDoc} */
#Override
public void startEdit() {
if (!isEditable()
|| getTableView() == null
|| getTableColumn() == null
|| getTableView() != null && !getTableView().isEditable()
|| getTableColumn() != null && !getTableColumn().isEditable()) {
return;
}
super.startEdit();
if (isEditing()) {
/*
textField.setText(getItem().trim());
this.setText(textField.getText());
*/
//Platform.runLater(() -> textField.requestFocus());
textField.requestFocus();
}
}
/** {#inheritDoc} */
#Override
public void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
setText(null);
if (empty) {
setGraphic(null);
} else {
textField.setText(item == null ? "" : item.trim());
setGraphic(textField);
}
}
}
What visually occurs:
What I need my code to do is to have caret placed inside the TextField or TextField focused, but this doesn't occur with my code right now.
Any idea what I am missing out?

How to add a custom component to a JavaFX TableView column?

I want to add a custom component (SwitchButton) to a column in a JavaFX TableView. I've looked at some examples with buttons and I'm just not understanding so far how to do it. Below is my practice table code along with the SwitchButton code I want to be able to put in the Active/Inactive column. The value for the SwitchButton (Active or Inactive) will be read from the database and when the user switches it, I'll want to trigger an action to write it to the database.
TableWithSwitchButtonView.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="248.0" prefWidth="271.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1" fx:controller="tabletest.TableWithSwitchButtonController">
<children>
<TableView fx:id="configTableView" prefHeight="240.0" prefWidth="271.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<columns>
<TableColumn fx:id="configColumn" prefWidth="138.0" text="Configuration Name" />
<TableColumn fx:id="activeColumn" prefWidth="131.0" text="Active/Inactive" />
</columns>
</TableView>
</children>
</AnchorPane>
TableWithSwitchButtonController.java:
package tabletest;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
public class TableWithSwitchButtonController implements Initializable
{
#FXML
private TableColumn<Config, String> configColumn;
#FXML
private TableColumn<Config, String> activeColumn;
#FXML
private TableView<Config> configTableView;
#Override
public void initialize(URL url, ResourceBundle rb)
{
// Add Cell Value Factory
configColumn.setCellValueFactory(new PropertyValueFactory<Config,
String>("configName"));
activeColumn.setCellValueFactory(new PropertyValueFactory<Config,
String>("configActive"));
// populate the Column lists (this will be coming from the database)
ObservableList<Config> configList =
FXCollections.<Config>observableArrayList(
new Config("Config 1", "active"),
new Config("Config 2", "active"),
new Config("Config 3", "inactive")
);
configTableView.getItems().addAll(configList);
}
public class Config
{
private String configName;
private String configActive;
public Config(String name, String active)
{
configName = name;
configActive = active;
}
public String getConfigName()
{
return configName;
}
public void setConfigName(String name)
{
configName = name;
}
public String getConfigActive()
{
return configActive;
}
public void setConfigActive(String active)
{
configActive = active;
}
};
}
TableTest.java:
package tabletest;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class TableTest extends Application
{
#Override
public void start(Stage primaryStage)
{
try
{
FXMLLoader loader = new FXMLLoader(getClass().getResource("TableWithSwitchButtonView.fxml"));
Scene scene = new Scene((Parent) loader.load());
primaryStage.setScene(scene);
primaryStage.setTitle("Table Test");
primaryStage.show();
}
catch (IOException ignored)
{
}
}
public static void main(String[] args)
{
launch(args);
}
}
SwitchButton.java:
package tabletest;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.Label;
public class SwitchButton extends Label
{
private SimpleBooleanProperty switchedOn = new SimpleBooleanProperty(true);
public SwitchButton()
{
Button switchBtn = new Button();
switchBtn.setPrefWidth(40);
switchBtn.setOnAction(new EventHandler<ActionEvent>()
{
#Override
public void handle(ActionEvent t)
{
switchedOn.set(!switchedOn.get());
}
});
setGraphic(switchBtn);
switchedOn.addListener(new ChangeListener<Boolean>()
{
#Override
public void changed(ObservableValue<? extends Boolean> ov,
Boolean t, Boolean t1)
{
if (t1)
{
setText("ACTIVE");
setStyle("-fx-background-color: green;-fx-text-fill:white;");
setContentDisplay(ContentDisplay.RIGHT);
}
else
{
setText("INACTIVE");
setStyle("-fx-background-color: grey;-fx-text-fill:black;");
setContentDisplay(ContentDisplay.LEFT);
}
}
});
switchedOn.set(false);
}
public SimpleBooleanProperty switchOnProperty() { return switchedOn; }
}

how to blend JFXNodeList from the code

I am having a JFXNodeList
<JFXNodesList fx:id="algorithmList" layoutX="285.0" layoutY="215.0" prefHeight="1.0" prefWidth="10.0" />
How can I close (blend the JFXNodeList), from my controller java code, if a user click one button ?
Environment:
JavaFX , Java 8, jfoenix:8.0.3
To close (collapse) JFXNodeList you can use this method:
nodesList.animateList(false);
Complete example:
// src/toumi_jfoenix/Controller.java:
package toumi_jfoenix;
import com.jfoenix.controls.JFXButton;
import com.jfoenix.controls.JFXNodesList;
import javafx.fxml.FXML;
import javafx.scene.control.Tooltip;
public class Controller {
#FXML
public JFXNodesList nodesList;
#FXML
private void initialize() {
JFXButton btnMenu = new JFXButton("Menu");
JFXButton btnOption1 = new JFXButton("Option 1");
JFXButton btnOption2 = new JFXButton("Option 2");
JFXButton btnCollapse = new JFXButton("<<");
btnCollapse.setTooltip(new Tooltip("Collapse menu"));
btnCollapse.setOnAction(e->nodesList.animateList(false));
nodesList.addAnimatedNode(btnMenu);
nodesList.addAnimatedNode(btnOption1);
nodesList.addAnimatedNode(btnOption2);
nodesList.addAnimatedNode(btnCollapse);
}
}
// src/toumi_jfoenix/sample.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.Pane?>
<?import com.jfoenix.controls.JFXNodesList?>
<Pane xmlns="http://javafx.com/javafx"
xmlns:fx="http://javafx.com/fxml"
fx:controller="toumi_jfoenix.Controller">
<JFXNodesList fx:id="nodesList" layoutX="20.0" layoutY="10.0" rotate="-90" spacing="50"/>
</Pane>
// src/toumi_jfoenix/Main.java:
package toumi_jfoenix;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Scene scene = new Scene(root, 430, 200);
primaryStage.setScene(scene);
primaryStage.show();
}
}

How to launch a window on java(fx)?

I'm having an issue, I've put an exception around part of my code and it returns
"Caught expection :
/Users/delorszimi/Documents/Documents/Java%20CW/JavaFXbasics/bin/Main.fxml:8"
It seems there's a problem with the anchorPane section in my fxml file that's stopping it from launching. Most of my code is below...
package application;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
public class Main extends Application {
static Stage window = new Stage();
#Override
public void start(Stage window) throws Exception {
try{
window.setTitle("Sprite Editor");
BorderPane pane = new BorderPane();
Scene sc = new Scene(pane,300,300);
Parent content = FXMLLoader.load(getClass().getClassLoader().getResource("Main.fxml"));
pane.setCenter(content);
window.setScene(sc);
window.show();
window.setOnCloseRequest(e -> closeWindow());
}
catch(Exception e){
System.err.println("Caught expection : " + e.getMessage());
}
}
private void closeWindow() {
Boolean decision = ConfirmBox.display("Are you sure you want to exit?", "Title");
if(decision)
window.close();
}
public static void main(String[] args) {
launch(args);
}
}
FXML file
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.canvas.Canvas?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="432.0" prefWidth="498.0"
xmlns="http://javafx.com/javafx/8.0.141" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="MainController">
<children>
<Canvas fx:id="Canvas1" height="240.0" layoutX="81.0" layoutY="39.0"
width="308.0" />
</children>
</AnchorPane>
package application;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.control.ColorPicker;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
public class MainController {
#FXML
public void initialize(){
Button botao = new Button("Browse Files");
Button exit = new Button("Exit");
exit.setOnAction(e -> System.exit(0));
StackPane layout = new StackPane();
layout.getChildren().addAll(botao,exit);
final Canvas canvas1 = new Canvas(500,300);
GraphicsContext gc = canvas1.getGraphicsContext2D();
gc.setStroke(Color.BLACK);
gc.setLineWidth(1);
ColorPicker cp = new ColorPicker();
layout.getChildren().addAll(canvas1,cp);
Scene sc = new Scene(cp);
sc.setOnMousePressed(e->{
gc.beginPath();
gc.lineTo(e.getSceneX(), e.getSceneY());
gc.stroke();
});
sc.setOnMouseDragged(e->{
gc.lineTo(e.getSceneX(), e.getSceneY());
gc.stroke();
});
}
public void size(){
double width,height;
}
public void fileSelection(ActionEvent evento){
}
}
In FXML file you take a AnchorPane but in code section you create a borderpane instance, don't understand this part. And remove getClassLoader() and try once. I am not sure but you can check for once.

How to switch stages in JavaFX

I have a login stage (300 x 250), I want to open another main stage (fullscreen) if the credentials are correct.
I have figured out how to check the login credentials, but how can I close the login stage and open another stage?
If my application is supposed to work in one window I prefer using a GUI manager singleton class, which manages changing windows. Below I provided the complete code of a simple application which uses this mechanism. Let's assume all the files are in one package, called sample.
Main.java - you initialize the JavaFX components here:
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import java.io.IOException;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("/sample/root.fxml"));
try{
StackPane rootPane;
rootPane = loader.load();
GuiManager guiModel = GuiManager.getInstance();
guiModel.setRootPane(rootPane);
Scene scene = new Scene(rootPane);
primaryStage.setScene(scene);
primaryStage.show();
guiModel.changeWindow("/sample/firstwindow.fxml");
} catch (IOException exception) {
exception.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
root.fxml - all the windows are supposed to be based on it:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.StackPane?>
<StackPane fx:id="rootPane"
xmlns="http://javafx.com/javafx/8.0.60"
xmlns:fx="http://javafx.com/fxml/1"
prefWidth="1" prefHeight="1"/>
firstwindow.fxml - first actual window which will be displayed:
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="sample.FirstWindowController">
<Label text="First window"/>
<Button text="Change window" onAction="#changeWindow"/>
</VBox>
FirstWindowController.java - a controller class of the first window:
package sample;
import javafx.fxml.FXML;
public class FirstWindowController {
#FXML
private void changeWindow() {
GuiManager.getInstance().changeWindow("/sample/secondwindow.fxml");
}
}
secondwindow.fxml - it will be displayed after clicking the button of the first window:
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>
<VBox xmlns:fx="http://javafx.com/fxml" fx:controller="sample.SecondWindowController" >
<Label text="Second window"/>
<Button text="Change window" onAction="#changeWindow"/>
</VBox>
SecondWindowController.java - a controller class of the second window:
package sample;
import javafx.fxml.FXML;
public class SecondWindowController {
#FXML
private void changeWindow() {
GuiManager.getInstance().changeWindow("/sample/firstwindow.fxml");
}
}
GuiManager.java - a class that manages changing windows based on the root:
package sample;
import javafx.collections.ObservableList;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.stage.Window;
import java.io.IOException;
public class GuiManager {
private StackPane rootPane;
private static GuiManager instance;
public static GuiManager getInstance() {
if (instance == null) {
instance = new GuiManager();
}
return instance;
}
private GuiManager() {}
public void changeWindow(String path) {
changeWindow(rootPane, path, this);
rootPane.setPrefWidth(-1);
rootPane.setPrefHeight(-1);
}
public static void changeWindow(Pane pane, String newWindowPath, Object callingController) {
Window window = pane.getScene().getWindow();
double x = window.getX() + getHorizontalMidpoint(window);
double y = window.getY() + getVerticalMidpoint(window);
ObservableList<Node> childrenList = pane.getChildren();
removeAllIncludedChildren(childrenList);
FXMLLoader loader = new FXMLLoader(callingController.getClass().getResource(newWindowPath));
try {
pane.getChildren().add(loader.load());
Stage primaryStage = (Stage) window;
primaryStage.setMinHeight(0);
primaryStage.setMinWidth(0);
window.sizeToScene();
window.setX(x - getHorizontalMidpoint(window));
window.setY(y - getVerticalMidpoint(window));
primaryStage.setMinHeight(window.getHeight());
primaryStage.setMinWidth(window.getWidth());
} catch (IOException exception) {
exception.printStackTrace();
}
}
private static double getHorizontalMidpoint(Window window) {
int horizontalBisectionCoefficient = 2;
return window.getWidth() / horizontalBisectionCoefficient;
}
private static double getVerticalMidpoint(Window window) {
int verticalBisectionCoefficient = 2;
return window.getHeight() / verticalBisectionCoefficient;
}
private static void removeAllIncludedChildren(ObservableList<Node> childrenList) {
for (int childIndex = 0; childIndex < childrenList.size(); childIndex++) {
childrenList.remove(childIndex);
}
}
public void setRootPane(StackPane rootPane) {
this.rootPane = rootPane;
}
}
I just run in the same issue and this answer solved my issue perfectly while being short and clean.
#FXML
private void handleButtonAction(ActionEvent event) {
System.out.println("You clicked me!");
label.setText("Hello World!");
//Here I want to swap the screen!
Stage stageTheEventSourceNodeBelongs = (Stage) ((Node)event.getSource()).getScene().getWindow();
// OR
Stage stageTheLabelBelongs = (Stage) label.getScene().getWindow();
// these two of them return the same stage
// Swap screen
stage.setScene(new Scene(new Pane()));
}
PS.: Remember to click the original answer and upvote it. The guy deserves...
PPS.: I am not sure just copying an answer is okay(instead of just share the link through a comment) but since this doesnt have a correct answer yet i decided to do it for visibility.

Resources