I am getting this error
the controller "classname" has no event slot "methodname"
if i add "/" before application in fx:controller="application.MainController">
this error goes but creates
class failed to load
/Users/myname/Documents/workspace/Javafx%20tesr/bin/application/Main.fxml:7
here's the xml file
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="450" prefWidth="500" xmlns="http://javafx.com/javafx/8.0.65" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainController">
<children>
<Button fx:id="genratebutton" layoutX="160.0" layoutY="225.0" mnemonicParsing="false" onAction="#generaterandom" prefHeight="27.0" prefWidth="180.0" text="generate random" />
<Label fx:id="myMessage" layoutX="138.0" layoutY="104.0" prefHeight="89.0" prefWidth="225.0" />
</children>
</AnchorPane>
(sorry new to GUI only know basics of swing)
this is main class
package application;
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 primaryStage) {
try {
Parent root=FXMLLoader.load(getClass().getClassLoader().getResource("/Main.fxml"));
Scene scene = new Scene(root,400,400);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
}
catch(Exception e) {
e.printStackTrace();
System.exit(0);
}
}
public static void main(String[] args) {
launch(args);
}
}
this is another class whose method i want to invoke
package application;
import java.util.Random;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class MainController {
#FXML
private Label myMessage;
void generaterandom (ActionEvent event){
Random rand=new Random();
int myrand=rand.nextInt(50)+1;
myMessage.setText(Integer.toString(myrand));
System.out.println(Integer.toString(myrand));
}
}
Since the controller method is not public, you need to annotate it #FXML:
public class MainController {
#FXML
private Label myMessage;
#FXML
void generaterandom (ActionEvent event){
Random rand=new Random();
int myrand=rand.nextInt(50)+1;
myMessage.setText(Integer.toString(myrand));
System.out.println(Integer.toString(myrand));
}
}
Related
I'm working on a project and I need to display the information of a Medicine object from a ListView to another Scene.
The user would select a Medicine from the ListView and press the Button to see it's details in the next Scene that would be displayed by Labels. The problem now is, I have transferred the info, and the text property of the Label has changed (observed through println and debugging), but the Label just won't display the changed text.
this is the main
package app;
import app.data.MedicineData;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import org.w3c.dom.events.Event;
import java.io.IOException;
public class Pharmachine extends Application {
public static final double WIDTH = 480;
public static final double HEIGHT = 720;
#Override
public void start(Stage stage) throws Exception{
Parent homePage = FXMLLoader.load(getClass().getResource("homepage.fxml"));
Scene homePageScene = newDefaultScene(homePage);
stage.setResizable(false);
stage.setScene(homePageScene);
stage.setTitle("Pharmachine");
stage.show();
}
#Override
public void init(){
MedicineData.getInstance().loadData();
}
public static Scene newDefaultScene(Parent parent){
Scene scene = new Scene(parent, WIDTH, HEIGHT);
scene.addEventHandler(MouseEvent.MOUSE_CLICKED,
(mouseEvent) -> {
Node targetNode = scene.getFocusOwner();
if(targetNode != null && targetNode.isFocused()) {
if(targetNode.getParent() != null)
targetNode.getParent().requestFocus();
mouseEvent.consume();
}
}
);
return scene;
}
public static void navigateTo(ActionEvent actionEvent, String filename){
Stage mainWindow = (Stage) ((Node) actionEvent.getSource()).getScene().getWindow();
Scene currentScene = ((Node) actionEvent.getSource()).getScene();
try {
currentScene.setRoot(FXMLLoader.load(Pharmachine.class.getResource(filename)));
mainWindow.setScene(currentScene);
} catch(IOException e){
e.printStackTrace();
}
}
public static void main(String[] args){ launch(args); }
}
this is the fxml for the list's page
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.ListView?>
<BorderPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
fx:controller="app.ListpageController" fx:id="pageRoot"
stylesheets="#styles/main.css">
<left>
<GridPane fx:id="listArea" alignment="CENTER">
<ListView fx:id="medicineList"
GridPane.rowIndex="1"/>
</GridPane>
</left>
<center>
<GridPane fx:id="buttonsArea" alignment="CENTER"
hgap="10" vgap="10">
<Button text="Back"
onAction="#displayHomePage"
GridPane.halignment="CENTER"/>
<Button text="Details"
onAction="#displayDetailsPage"
GridPane.rowIndex="1"
GridPane.halignment="CENTER"/>
</GridPane>
</center>
</BorderPane>
here is the controller for the list's page
package app;
import app.data.Medicine;
import app.data.MedicineData;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.util.Callback;
import java.io.IOException;
public class ListpageController {
#FXML
private BorderPane pageRoot;
#FXML
private GridPane listArea;
#FXML
private GridPane buttonsArea;
#FXML
private ListView<Medicine> medicineList;
#FXML public void initialize(){
listArea.setMaxWidth(Pharmachine.WIDTH * 3/5);
medicineList.setMinWidth(listArea.getMaxWidth());
medicineList.setMinHeight(Pharmachine.HEIGHT);
medicineList.setItems(MedicineData.getInstance().getMedicines());
medicineList.setCellFactory(new Callback<>() {
#Override
public ListCell<Medicine> call(ListView<Medicine> medicineListView) {
ListCell<Medicine> listCell = new ListCell<>(){
#Override
public void updateItem(Medicine medicine, boolean empty){
super.updateItem(medicine, empty);
if(!empty){
HBox medName = new HBox(new Label(medicine.getName()));
HBox.setHgrow(medName, Priority.ALWAYS);
HBox medPrice = new HBox(new Label(String.format("RM%.2f", medicine.getPrice())));
HBox medLabel = new HBox(medName, medPrice);
setGraphic(medLabel);
}
}
};
listCell.setOnMouseClicked(
(mouseEvent) -> {
if(mouseEvent.getClickCount() == 2){
medicineList.getSelectionModel().clearSelection();
}
}
);
return listCell;
}
});
}
#FXML private void displayHomePage(ActionEvent actionEvent){
Pharmachine.navigateTo(actionEvent, "homepage.fxml");
}
#FXML private void displayDetailsPage(ActionEvent actionEvent){
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("detailspage.fxml"));
try {
loader.load();
} catch(IOException e){
e.printStackTrace();
}
DetailspageController controller = loader.getController();
Medicine selectedMedicine = medicineList.getSelectionModel().getSelectedItem();
if(selectedMedicine != null) {
controller.setInfo(selectedMedicine);
Pharmachine.navigateTo(actionEvent, "detailspage.fxml");
}
}
}
this is the fxml for the next scene (just simple for now)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.text.Text?>
<BorderPane xmlns="http://javafx.com/javafx" xmlns:fx="http://javafx.com/fxml"
fx:id="pageRoot" fx:controller="app.DetailspageController"
stylesheets="#styles/main.css">
<center>
<GridPane fx:id="detailsArea"
alignment="CENTER" hgap="10" vgap="10">
<Label text="Details"/>
<Text text="Name: "
GridPane.rowIndex="1"/>
<Label fx:id="medNameLabel" text="~"
GridPane.rowIndex="1" GridPane.columnIndex="1"/>
<Text text="Price: "
GridPane.rowIndex="2"/>
<Label fx:id="medPriceLabel" text="~"
GridPane.rowIndex="2" GridPane.columnIndex="1"/>
</GridPane>
</center>
</BorderPane>
and this is the scene's controller
package app;
import app.data.Medicine;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import java.net.URL;
import java.util.ResourceBundle;
public class DetailspageController implements Initializable {
private Medicine selectedMedicine;
#FXML
private BorderPane pageRoot;
#FXML
private GridPane detailsArea;
#FXML
private Label medNameLabel;
#FXML
private Label medPriceLabel;
#Override
public void initialize(URL url, ResourceBundle rb){
}
public void setInfo(Medicine medicine){
selectedMedicine = medicine;
medNameLabel.setText(selectedMedicine.getName());
medPriceLabel.setText(String.format("RM%.2f", selectedMedicine.getPrice()));
System.out.println(medNameLabel.textProperty());
System.out.println(medNameLabel.getText());
medNameLabel.setStyle("-fx-background-color: red;");
}
}
The help would mean a lot. Thank you :]
In your displayDetailsPage method, you load a scene from detailspage.fxml, and you update its labels by calling the setInfo method of the controller.
Then, you call Pharmachine.navigateTo, which loads detailspage.xml again and replaces the scene root with the newly loaded root. You updated the text of the labels in the first details page, but the second details page is brand new, so it doesn’t have those changes.
The second argument in the navigateTo method should be of type Parent rather than a String. navigateTo should not attempt to load any .fxml file; let that be the caller’s responsibility.
Side note: When a list has multiple attributes for each data item, you should probably use a TableView rather than a ListView.
I'm really struggling to understand JavaFX controllers, my aim is to write to a TextArea to act as a log.
My code is below, but I want to be able to change values ETC from another class that I can call when needed. I have tried to create a controller class that extents Initializable but i cant get it to work. Could some one steer me in the correct direction?
I want to move the #FXML code at the bottom to another class and it update the Scene.
package application;
import javafx.event.ActionEvent;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("Root.fxml"));
Scene scene = new Scene(root,504,325);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
public Thread thread = new Thread(new webimporter());
#FXML
public Label runningLabel;
#FXML
public TextArea txtArea;
#FXML
void runClick(ActionEvent event) throws IOException{
changeLabelValue("Importer running...");
thread.start();
}
#FXML
protected void stopClick(ActionEvent event){
changeLabelValue("Importer stopped...");
thread.interrupt();
}
#FXML
void changeLabelValue(String newText){
runningLabel.setText(newText);
}
void changeTextAreaValue(String newText1){
txtArea.setText(newText1);
}
}
Don't make the Application class a controller. It's a sin. There are other questions and answers which address this, but my search skills cannot find them at this time.
The reason it is a sin is:
You are only supposed to have one Application instance, and, by default, the loader will make a new instance, so you end up with two application objects.
Referencing the member objects is confusing, because the original launched application doesn't have the #FXML injected fields, but the loader created application instance does have #FXML inject fields.
Also, unrelated advice: Don't start trying to write multi-threaded code until you have the application at least working to the extent where it displays your UI.
A multi-threaded logger for JavaFX is in the answer to Most efficient way to log messages to JavaFX TextArea via threads with simple custom logging frameworks, though unfortunately it is not straight-forward in its implementation and comes with little documentation.
textlogger/Root.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="400.0" spacing="10.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="textlogger.ImportController">
<children>
<HBox alignment="BASELINE_LEFT" minHeight="-Infinity" minWidth="-Infinity" spacing="10.0">
<children>
<Button mnemonicParsing="false" onAction="#run" text="Run" />
<Button mnemonicParsing="false" onAction="#stop" text="Stop" />
<Label fx:id="runningLabel" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</HBox>
<TextArea fx:id="textArea" editable="false" prefHeight="200.0" prefWidth="200.0" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>
textlogger.ImportController.java
package textlogger;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import java.io.IOException;
public class ImportController {
#FXML
private Label runningLabel;
#FXML
private TextArea textArea;
private WebImporter importer;
#FXML
void run(ActionEvent event) throws IOException {
changeLabelValue("Importer running...");
if (importer == null) {
importer = new WebImporter(textArea);
Thread thread = new Thread(
importer
);
thread.setDaemon(true);
thread.start();
}
}
#FXML
void stop(ActionEvent event){
changeLabelValue("Importer stopped...");
if (importer != null) {
importer.cancel();
importer = null;
}
}
private void changeLabelValue(String newText){
runningLabel.setText(newText);
}
}
textlogger.WebImporter.java
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.control.TextArea;
import java.time.LocalTime;
public class WebImporter extends Task<Void> {
private final TextArea textArea;
public WebImporter(TextArea textArea) {
this.textArea = textArea;
}
#Override
protected Void call() throws Exception {
try {
while (!isCancelled()) {
Thread.sleep(500);
Platform.runLater(
() -> textArea.setText(
textArea.getText() + LocalTime.now() + "\n"
)
);
}
} catch (InterruptedException e) {
Thread.interrupted();
}
return null;
}
}
textlogger.TextLoggingSample.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class TextLoggingSample extends Application {
#Override
public void start(Stage stage) {
try {
FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(
getClass().getResourceAsStream(
"Root.fxml"
)
);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
I'm really struggling to understand JavaFX controllers, my aim is to write to a TextArea to act as a log.
My code is below, but I want to be able to change values ETC from another class that I can call when needed. I have tried to create a controller class that extents Initializable but i cant get it to work. Could some one steer me in the correct direction?
I want to move the #FXML code at the bottom to another class and it update the Scene.
package application;
import javafx.event.ActionEvent;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.stage.Stage;
import javafx.scene.Parent;
import javafx.scene.Scene;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
Parent root = FXMLLoader.load(getClass().getResource("Root.fxml"));
Scene scene = new Scene(root,504,325);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
public Thread thread = new Thread(new webimporter());
#FXML
public Label runningLabel;
#FXML
public TextArea txtArea;
#FXML
void runClick(ActionEvent event) throws IOException{
changeLabelValue("Importer running...");
thread.start();
}
#FXML
protected void stopClick(ActionEvent event){
changeLabelValue("Importer stopped...");
thread.interrupt();
}
#FXML
void changeLabelValue(String newText){
runningLabel.setText(newText);
}
void changeTextAreaValue(String newText1){
txtArea.setText(newText1);
}
}
Don't make the Application class a controller. It's a sin. There are other questions and answers which address this, but my search skills cannot find them at this time.
The reason it is a sin is:
You are only supposed to have one Application instance, and, by default, the loader will make a new instance, so you end up with two application objects.
Referencing the member objects is confusing, because the original launched application doesn't have the #FXML injected fields, but the loader created application instance does have #FXML inject fields.
Also, unrelated advice: Don't start trying to write multi-threaded code until you have the application at least working to the extent where it displays your UI.
A multi-threaded logger for JavaFX is in the answer to Most efficient way to log messages to JavaFX TextArea via threads with simple custom logging frameworks, though unfortunately it is not straight-forward in its implementation and comes with little documentation.
textlogger/Root.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefWidth="400.0" spacing="10.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="textlogger.ImportController">
<children>
<HBox alignment="BASELINE_LEFT" minHeight="-Infinity" minWidth="-Infinity" spacing="10.0">
<children>
<Button mnemonicParsing="false" onAction="#run" text="Run" />
<Button mnemonicParsing="false" onAction="#stop" text="Stop" />
<Label fx:id="runningLabel" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</HBox>
<TextArea fx:id="textArea" editable="false" prefHeight="200.0" prefWidth="200.0" />
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>
textlogger.ImportController.java
package textlogger;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.Label;
import javafx.scene.control.TextArea;
import java.io.IOException;
public class ImportController {
#FXML
private Label runningLabel;
#FXML
private TextArea textArea;
private WebImporter importer;
#FXML
void run(ActionEvent event) throws IOException {
changeLabelValue("Importer running...");
if (importer == null) {
importer = new WebImporter(textArea);
Thread thread = new Thread(
importer
);
thread.setDaemon(true);
thread.start();
}
}
#FXML
void stop(ActionEvent event){
changeLabelValue("Importer stopped...");
if (importer != null) {
importer.cancel();
importer = null;
}
}
private void changeLabelValue(String newText){
runningLabel.setText(newText);
}
}
textlogger.WebImporter.java
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.control.TextArea;
import java.time.LocalTime;
public class WebImporter extends Task<Void> {
private final TextArea textArea;
public WebImporter(TextArea textArea) {
this.textArea = textArea;
}
#Override
protected Void call() throws Exception {
try {
while (!isCancelled()) {
Thread.sleep(500);
Platform.runLater(
() -> textArea.setText(
textArea.getText() + LocalTime.now() + "\n"
)
);
}
} catch (InterruptedException e) {
Thread.interrupted();
}
return null;
}
}
textlogger.TextLoggingSample.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class TextLoggingSample extends Application {
#Override
public void start(Stage stage) {
try {
FXMLLoader loader = new FXMLLoader();
Parent root = loader.load(
getClass().getResourceAsStream(
"Root.fxml"
)
);
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
I'm trying to populate the value of a text field in Java FX.
I have the Main Class,the controller and the fxml.I have bind the fxml file with controller and the appropriate field in it. When i try to set its value, it fails.
Main.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
public class Main extends Application {
private Stage primaryStage;
private FlowPane rootLayout;
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(Main.class.getResource("test.fxml"));
rootLayout = (FlowPane) loader.load();
Scene scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
testController.java
package application;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
public class testController {
#FXML
private TextField t1;
public testController() {
System.out.println("hi");
t1 = new TextField("j");
t1.setText("hi");
}
}
FXML file:
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.FlowPane?>
<FlowPane prefHeight="200.0" prefWidth="200.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.testController">
<children>
<TextField fx:id="t1" />
</children>
</FlowPane>
You are doing it in the wrong place! If you need to play around with your controls just before your fxml is loaded, you need to do it in the initialize(). For this your controller should implement the Initializable
So your controller becomes :
public class testController implements Initializable{
#FXML
private TextField t1;
public void initialize() {
System.out.println("hi");
//You should not re-initialize your textfield
//t1 = new TextField("j");
t1.setText("hi");
}
}
I have one main screen with a label firstLabel. There is a button openSecondWindow.
Pressing that button opens up a new window, while leaving the first one on the screen.
How would I lock the first screen so that the user cannot interact with it until the second window is closed?
The second window will have a TextField and Button setFirstLabel. When the user enters text in the text field and hits the button, the text from the first window is changed.
How am I supposed to access the controller class for the first window from the second window's controller?
How do I ensure that only one instance of each window be opened at a time? (No duplicates)
i made a small example for you.
If you click on Stage 1 on the Button to open the second Stage, the Button will be disabled, so you cant open one more Stage.
If you type some text into the TextField on Stage2 and click on the Update Button there, the TextField on Stage 1 will be updated and the second Stage will be closed.
Here is the code:
firstWindow.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="de.professional_webworkx.jfx.twowindows.controller.FirstController">
<children>
<TextField fx:id="textField" layoutX="50.0" layoutY="189.0" prefWidth="500.0" promptText="Waiting for input from second Stage..." />
<Button fx:id="openBtn" layoutX="441.0" layoutY="304.0" mnemonicParsing="false" text="open 2 Stage" />
</children>
</AnchorPane>
Second fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<AnchorPane id="AnchorPane" fx:id="mainPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="de.professional_webworkx.jfx.twowindows.controller.SecondController">
<children>
<TextField fx:id="textField" layoutX="50.0" layoutY="66.0" prefWidth="243.0" promptText="Type some text" />
<Button fx:id="updateBtn" layoutX="50.0" layoutY="118.0" mnemonicParsing="false" text="update Text on Stage 1" />
</children>
</AnchorPane>
FirstController
package de.professional_webworkx.jfx.twowindows.controller;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.stage.Stage;
/**
*
* #author Patrick Ott <Patrick.Ott#professional-webworkx.de>
* #version 1.0
*/
public class FirstController implements Initializable {
#FXML
Button openBtn;
#FXML
TextField textField;
private boolean secondOpen;
private Stage secondStage;
FirstController firstController;
public FirstController() {
}
#Override
public void initialize(URL url, ResourceBundle rb) {
this.firstController = this;
System.out.println(firstController);
openBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
if(!secondOpen) {
openBtn.setDisable(true);
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("second.fxml"));
Parent load = loader.load();
SecondController controller = (SecondController) loader.getController();
controller.setFirstController(firstController);
Scene scene = new Scene(load);
secondStage = new Stage();
secondStage.setScene(scene);
secondStage.show();
secondOpen = true;
} catch (IOException ex) {
Logger.getLogger(FirstController.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
});
}
public void updateText(final String text) {
this.textField.setText(text);
}
public void secondClosed() {
this.secondOpen = false;
this.openBtn.setDisable(false);
secondStage.close();
}
}
SecondController
package de.professional_webworkx.jfx.twowindows.controller;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.AnchorPane;
/**
*
* #author Patrick Ott <Patrick.Ott#professional-webworkx.de>
* #version 1.0
*/
public class SecondController implements Initializable {
#FXML
AnchorPane mainPane;
#FXML
TextField textField;
#FXML
Button updateBtn;
private FirstController firstController;
#Override
public void initialize(URL url, ResourceBundle rb) {
updateBtn.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
String text = textField.getText();
firstController.updateText(text);
firstController.secondClosed();
}
});
}
public void setFirstController(final FirstController firstController) {
this.firstController = firstController;
}
}
And start it
package de.professional_webworkx.jfx.twowindows;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
/**
*
* #author Patrick Ott <Patrick.Ott#professional-webworkx.de>
*/
public class TwoStages extends Application {
#Override
public void start(Stage primaryStage) {
try {
Parent load = FXMLLoader.load(getClass().getResource("firstWindow.fxml"));
Scene scene = new Scene(load);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException ex) {
Logger.getLogger(TwoStages.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
The Magic is, to hand over a FirstController object to the SecondController, that you are able to update the TextField on the first Stage.
Hope this will help.
Patrick