I have the main application class that does the following just fine:
#Override
public void start(Stage primaryStage) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"RecordScreen.fxml"));
Parent root = (Parent) loader.load();
Scene newScene = new Scene(root);
Stage newStage = new Stage();
newStage.setScene(newScene);
newStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
It launches a table view that displays people. I select a person, hit the edit button, and try to launch a window that will let me edit them.
#FXML
public void editPerson() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"PersonEditor.fxml"));
PersonEditorCtrl ctrl = loader.getController();
ctrl.init(table.getSelectionModel().getSelectedItem());
Parent root = (Parent) loader.load();
Scene newScene = new Scene(root);
Stage newStage = new Stage();
newStage.setScene(newScene);
newStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
The problem is, getController is returning null. I have been following this pattern for the past 2 weeks with no problems whatsoever. What am I doing wrong now? These untraceable bugs are aggravating!!!
Here are my two fxmls:
The screen with tableview:
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="application.RecordsCtrl">
<!-- TODO Add Nodes -->
<children>
<VBox id="VBox" alignment="CENTER" spacing="0.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<TableView fx:id="table" prefHeight="-1.0" prefWidth="-1.0">
<columns>
<TableColumn prefWidth="75.0" text="Name" fx:id="nameCol" />
<TableColumn prefWidth="75.0" text="Age" fx:id="ageCol" />
</columns>
</TableView>
<Button mnemonicParsing="false" onAction="#editPerson" text="Edit" />
</children>
</VBox>
</children>
</AnchorPane>
The person editor:
<AnchorPane xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="application.PersonEditorCtrl">
<!-- TODO Add Nodes -->
<children>
<VBox layoutX="0.0" layoutY="0.0" prefHeight="-1.0" prefWidth="-1.0">
<children>
<TextField fx:id="nameField" prefWidth="200.0" />
<TextField fx:id="ageField" prefWidth="200.0" />
<Button mnemonicParsing="false" text="Button" />
</children>
</VBox>
</children>
</AnchorPane>
Change this
#FXML
public void editPerson() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"PersonEditor.fxml"));
PersonEditorCtrl ctrl = loader.getController();
ctrl.init(table.getSelectionModel().getSelectedItem());
Parent root = (Parent) loader.load();
Scene newScene = new Scene(root);
Stage newStage = new Stage();
newStage.setScene(newScene);
newStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
To that:
#FXML
public void editPerson() {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource(
"PersonEditor.fxml"));
Parent root = (Parent) loader.load();
PersonEditorCtrl ctrl = loader.getController();
ctrl.init(table.getSelectionModel().getSelectedItem());
Scene newScene = new Scene(root);
Stage newStage = new Stage();
newStage.setScene(newScene);
newStage.show();
} catch (Exception e) {
e.printStackTrace();
}
}
You first have to run loader.load() then you can get the Controller.
Patrick
Related
I'm writing some code where I interact (Change text) with FXML elements from the start method. However, I find that when I call the method from my controller class I get a NullPointerException. I've found that the issue has something to do with threads, but I have been able to get anything to work. I have included some sample code that generates the same problem.
Main class:
public class Main extends Application {
Controller C = new Controller();
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
Scene scene = new Scene(root, 300, 275);
stage.setTitle("FXML Welcome");
stage.setScene(scene);
stage.show();
C.handleSubmitButtonAction();//Error happens here.
}
public static void main(String[] args) {
launch(args);
}
}
Controller class:
public class Controller{
#FXML public Text actiontarget;
#FXML protected void handleSubmitButtonAction() {
actiontarget.setText("Sign in button pressed");
}
}
FXML code:
<GridPane fx:id="GridPane" fx:controller="sample.Controller" xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10">
<children>
<Text text="Welcome" GridPane.columnIndex="0" GridPane.rowIndex="0" GridPane.columnSpan="2"/>
<Label text="User Name:" GridPane.columnIndex="0" GridPane.rowIndex="1"/>
<TextField GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Label text="Password:" GridPane.columnIndex="0" GridPane.rowIndex="2"/>
<PasswordField fx:id="passwordField" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
<HBox spacing="10" alignment="bottom_right" GridPane.columnIndex="1" GridPane.rowIndex="4">
<Button text="Sign In" onAction="#handleSubmitButtonAction"/>
</HBox>
<Text fx:id="actiontarget" GridPane.columnIndex="1" GridPane.rowIndex="6"/>
</children>
</GridPane>
The FXMLLoader creates a instance of the controller itself, if you specify the controller class using the fx:controller attribute in the fxml.
To get access to that instance, you need to create a FXMLLoader instance and use getController() after loading the fxml. Otherwise the controller instance where the values are injected is different to the one you create yourself and store in the C field:
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"))
Parent root = loader.load();
C = loader.getController();
As you can see, my texts are constrained by labels. How do I make the label resize to exactly fit the text and also to resize the VBox and GridPane accordingly. I only want to resize vertically.
My FXML:
<VBox fx:id="body"
alignment="TOP_CENTER"
prefHeight="150"
GridPane.vgrow="SOMETIMES"
prefWidth="300"
GridPane.columnIndex="0"
GridPane.rowIndex="1" spacing="5">
<Label alignment="CENTER" textAlignment="JUSTIFY" fx:id="word" maxWidth="268"/>
<Pane prefHeight="10" VBox.vgrow="NEVER"/>
<Label alignment="CENTER" textAlignment="JUSTIFY" wrapText="true" fx:id="meaning" maxWidth="268" />
<Label alignment="CENTER" textAlignment="JUSTIFY" wrapText="true" fx:id="sentence" maxWidth="268" />
</VBox>
This VBox is inside the GridPane:
<GridPane fx:id="base"
alignment="CENTER"
prefHeight="210.0"
maxWidth="310.0"
stylesheets="#style.css"
vgap="0" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="sample.Controller">
...
Minimal, Complete, and Verifiable example as requested by #James_D
Main Class:
public class Main extends Application {
private Stage stage;
private StackPane stackPane;
#Override
public void start(Stage primaryStage) throws Exception{
stage = primaryStage;
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Parent root = (Parent) loader.load();
stackPane = new StackPane(root);
Scene scene = new Scene(stackPane);
scene.setFill(Color.WHITE);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Controller Class:
public class Controller implements Initializable{
#FXML private Label label1;
#FXML private Button changeLabel;
private StringProperty labelString = new SimpleStringProperty();
#Override
public void initialize(URL location, ResourceBundle resources) {
labelString.setValue("aasdasd sad asdasd asdasda");
label1.textProperty().bind(labelString);
}
#FXML
public void clicked(MouseEvent e){
labelString.setValue("asdsadasd asdasdasd sfdgsfwoef fgtrhfgbdrgdf dfgdfivbjkfd gdfgidfjvdf gdfgjldkvbdf gjdilgjdfv dfgojdflkgdf ");
}
}
sample.fxml:
<GridPane fx:controller="sample.Controller"
xmlns:fx="http://javafx.com/fxml" alignment="center" hgap="10" vgap="10" maxHeight="Infinity">
<children>
<VBox fx:id="body"
alignment="CENTER"
maxHeight="Infinity"
GridPane.vgrow="SOMETIMES"
prefWidth="300"
GridPane.columnIndex="0"
GridPane.rowIndex="1" spacing="5">
<Label alignment="CENTER" VBox.vgrow="ALWAYS" wrapText="true" textAlignment="CENTER" fx:id="label1" maxWidth="268"/>
<Button fx:id="changeLabel" text="Change" minWidth="50" onMouseClicked="#clicked" maxWidth="Infinity" />
</VBox>
</children>
Expectation:
When I press 'Change' button, Everything should resize to just give enough space for text to be shown.
Problem:
When I press 'Change' button, UI remains same not showing the full text.
Assuming you want the text to wrap, the labels will need to be able to grow vertically. Add the attribute
maxHeight="Infinity"
to each label. You are also constraining the overall height of the VBox with prefHeight="150"; remove that attribute and let the VBox figure out its own height. Similarly, you probably want to remove the prefHeight attribute from the GridPane.
I have a question.
I want to change the color of a pane from another controller class.
I am using this code:
FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/Menu.fxml"));
try {
Parent loaded = (Parent) loader.load();
} catch (IOException e) {
e.printStackTrace();
}
MenuController controller = (MenuController) loader.getController();
Platform.runLater(new Runnable() {
#Override
public void run() {
Pane pane = controller.getRedPane();
pane.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
}
});
The loaded, controller and pane aren't null.
But the pane's color doesn't change, can someone help me with this problem?
Thank you very much.
[EDIT]
public class MenuController implements Initializable
{
#FXML
private GridPane MenuRoot;
#FXML
private Pane redPane;
#Override
public void initialize(URL location, ResourceBundle resources)
{
}
#FXML
private void changeGridSize(ActionEvent event){
new ChangeSizes();
}
public GridPane getMenuRoot(){
return this.MenuRoot;
}
public Pane getRedPane(){
return this.redPane;
}
}
[EDIT]
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<GridPane fx:id="MenuRoot" gridLinesVisible="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="nl.voxworks.homeserver.client.MenuController">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="0.0" percentWidth="50.0" />
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="0.0" percentWidth="50.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="0.0" percentHeight="50.0" vgrow="ALWAYS" />
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="0.0" percentHeight="50.0" vgrow="ALWAYS" />
</rowConstraints>
<children>
<Pane fx:id="redPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: red;" GridPane.rowIndex="1" />
<Pane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: black;" GridPane.columnIndex="1" GridPane.rowIndex="1" />
</children>
</GridPane>
[EDIT] (different project all files included)
package javafxapplication16;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Insets;
import javafx.scene.layout.Background;
import javafx.scene.layout.BackgroundFill;
import javafx.scene.layout.CornerRadii;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
public class ChangeSize {
public ChangeSize(){
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
try {
loader.load();
} catch (IOException ex) {
Logger.getLogger(ChangeSize.class.getName()).log(Level.SEVERE, null, ex);
}
FXMLDocumentController controller = (FXMLDocumentController) loader.getController();
Platform.runLater(new Runnable() {
#Override
public void run() {
Pane pane = controller.getPane();
pane.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
}
});
}
}
FXMLDocumentController.
package javafxapplication16;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
public class FXMLDocumentController implements Initializable {
#FXML
private Pane redPane;
#FXML
private void changeGridSize(ActionEvent event){
new ChangeSize();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
}
public Pane getPane(){
return this.redPane;
}
}
JavaFXApplication16
package javafxapplication16;
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 JavaFXApplication16 extends Application {
#Override
public void start(Stage stage) throws Exception {
// Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
// FXMLLoader loader
Parent loaded=null;
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
try {
loaded = (Parent) loader.load();
} catch (IOException e) {
e.printStackTrace();
}
Scene scene = new Scene(loaded);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
FXML
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<GridPane fx:id="MenuRoot" gridLinesVisible="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication16.FXMLDocumentController">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="0.0" percentWidth="50.0" />
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="0.0" percentWidth="50.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="0.0" percentHeight="50.0" vgrow="ALWAYS" />
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="0.0" percentHeight="50.0" vgrow="ALWAYS" />
</rowConstraints>
<children>
<Pane fx:id="redPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: red;" GridPane.rowIndex="1" />
<Pane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: black;" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Button mnemonicParsing="false" onAction="#changeGridSize" text="Button" />
</children>
</GridPane>
This is my code: I hope helped you
FXMLDocumentController.class
public class FXMLDocumentController implements Initializable {
#FXML
private Pane redPane;
#FXML
private void changeGridSize(ActionEvent event){
// new ChangeSizes();
}
#Override
public void initialize(URL url, ResourceBundle rb) {
}
public Pane getPane(){
return this.redPane;
}
}
JavaFXMLApplication3.class
public class JavaFXMLApplication3 extends Application {
#Override
public void start(Stage stage) throws Exception {
// Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
// FXMLLoader loader
Parent loaded=null;
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
try {
loaded = (Parent) loader.load();
} catch (IOException e) {
e.printStackTrace();
}
Scene scene = new Scene(loaded);
stage.setScene(scene);
stage.show();
FXMLDocumentController controller = (FXMLDocumentController) loader.getController();
Platform.runLater(new Runnable() {
#Override
public void run() {
Pane pane = controller.getPane();
pane.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
}
});
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
FXMLDocument.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<GridPane fx:id="MenuRoot" gridLinesVisible="true" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxmlapplication3.FXMLDocumentController">
<columnConstraints>
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="0.0" percentWidth="50.0" />
<ColumnConstraints hgrow="ALWAYS" maxWidth="1.7976931348623157E308" minWidth="0.0" percentWidth="50.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="0.0" percentHeight="50.0" vgrow="ALWAYS" />
<RowConstraints maxHeight="1.7976931348623157E308" minHeight="0.0" percentHeight="50.0" vgrow="ALWAYS" />
</rowConstraints>
<children>
<Pane fx:id="redPane" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: red;" GridPane.rowIndex="1" />
<Pane maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="0.0" minWidth="0.0" prefHeight="200.0" prefWidth="200.0" style="-fx-background-color: black;" GridPane.columnIndex="1" GridPane.rowIndex="1" />
</children>
</GridPane>
I test your code and the problem is that you create another Pane redPane that isn't show:
when you call FXMLLoader you create a new loader that isn't show in stage.
I suggested you a possible solution : create a static Stage ... example code:
public class JavaFXMLApplication3 extends Application {
static Stage staticstage;
// Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
// FXMLLoader loader
#Override
public void start(Stage stage) throws Exception {
// Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
// FXMLLoader loader
staticstage=stage;
Parent loaded=null;
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
try {
loaded = (Parent) loader.load();
} catch (IOException e) {
e.printStackTrace();
}
Scene scene = new Scene(loaded);
stage.setScene(scene);
stage.show();
}
/**
* #param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
and change class ChangeSize
public class ChangeSize {
public ChangeSize() {
Parent loaded=null;
FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
try {
loaded = (Parent) loader.load();
} catch (IOException e) {
e.printStackTrace();
}
Scene scene = new Scene(loaded);
JavaFXMLApplication3.staticstage.setScene(scene);
JavaFXMLApplication3.staticstage.show();
FXMLDocumentController controller = (FXMLDocumentController) loader.getController();
Platform.runLater(new Runnable() {
#Override
public void run() {
Pane pane = controller.getPane();
pane.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
}
});
}
}
another solution is to pass FXMLDocumentController to class ChangeSize ... example code :
public class ChangeSize {
public ChangeSize(FXMLDocumentController controller) {
Platform.runLater(new Runnable() {
#Override
public void run() {
Pane pane = controller.getPane();
pane.setBackground(new Background(new BackgroundFill(Color.BLUE, CornerRadii.EMPTY, Insets.EMPTY)));
}
});
}
and in FXMLDocumentController class change the changeGridSize
#FXML
private void changeGridSize(ActionEvent event){
new ChangeSize(this);
}
I need to close my JDialog from JavaFx Button defined in my FXML file.
I post code of my class called by Main Application:
ExampleWindow.java
public class ExampleWindow extends JDialog
{
#FXML
Button closeButton;
public ExampleWindow()
{
}
public void initAndShowGUI()
{
final JFXPanel fxPanel = new JFXPanel();
add(fxPanel);
Platform.runLater(new Runnable()
{
#Override
public void run()
{
AnchorPane parent = null;
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setRoot(this);
try {
parent = fxmlLoader.load(getClass().getResource("WindowControlPanel.fxml"));
}
catch (IOException e) {
e.printStackTrace();
}
scene = new Scene(parent);
fxPanel.setScene(scene);
}
});
}
public void onAction(ActionEvent ac)
{
this.dispose();
}
}
Method onAction is called by JavaFx Button (on FXML file)
WindowControlPanel.fxml
<AnchorPane id="AnchorPane" fx:id="windowPanel" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="50.0" prefWidth="1024.0" style="-fx-border-color: white, grey; -fx-border-width: 2, 1; -fx-border-insets: 0, 0 1 1 0" xmlns:fx="http://javafx.com/fxml" fx:controller="ExampleWindow">
<children>
<FlowPane alignment="CENTER_RIGHT" columnHalignment="CENTER" prefHeight="50.0" prefWidth="1024.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<Button fx:id="closeButton" mnemonicParsing="false" onAction="#onAction" prefHeight="35.0" prefWidth="100.0" text="Close">
<FlowPane.margin>
<Insets bottom="5.0" left="20.0" right="20.0" top="5.0" />
</FlowPane.margin>
</Button>
</children>
</FlowPane>
</children>
</AnchorPane>
When I pressed closeButton, method onAction is correctly called, but my JDialog doesn't close. Any ideas? Where am I wrong?
I want to find a VBox node in a scene loaded with FXMLoader thanks to Node#lookup() but I get the following exception :
java.lang.ClassCastException: com.sun.javafx.scene.control.skin.SplitPaneSkin$Content cannot be cast to javafx.scene.layout.VBox
The code :
public class Main extends Application {
public static void main(String[] args) {
Application.launch(Main.class, (java.lang.String[]) null);
}
#Override
public void start(Stage stage) throws Exception {
AnchorPane page = (AnchorPane) FXMLLoader.load(Main.class.getResource("test.fxml"));
Scene scene = new Scene(page);
stage.setScene(scene);
stage.show();
VBox myvbox = (VBox) page.lookup("#myvbox");
myvbox.getChildren().add(new Button("Hello world !!!"));
}
}
The fxml file:
<AnchorPane id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml" >
<children>
<SplitPane dividerPositions="0.5" focusTraversable="true" prefHeight="400.0" prefWidth="600.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<items>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="160.0" prefWidth="100.0" />
<VBox fx:id="myvbox" prefHeight="398.0" prefWidth="421.0" />
</items>
</SplitPane>
</children>
</AnchorPane>
I would like to know :
1. Why lookup method return a SplitPaneSkin$Content and not a VBox ?
2. How I can get the VBox in another manner ?
Thanks in advance
The easiest way to get a reference to the VBox is by calling FXMLLoader#getNamespace(). For example:
VBox myvbox = (VBox)fxmlLoader.getNamespace().get("myvbox");
Note that you'll need to create an instance of FXMLLoader and call the non-static version of load() in order for this to work:
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("test.fxml"));
AnchorPane page = (AnchorPane) fxmlLoader.load();
SplitPane puts all items in separate stack panes (fancied as SplitPaneSkin$Content). For unknown reason FXMLLoader assign them the same id as root child. You can get VBox you need by next utility method:
public <T> T lookup(Node parent, String id, Class<T> clazz) {
for (Node node : parent.lookupAll(id)) {
if (node.getClass().isAssignableFrom(clazz)) {
return (T)node;
}
}
throw new IllegalArgumentException("Parent " + parent + " doesn't contain node with id " + id);
}
and use it next way:
VBox myvbox = lookup(page, "#myvbox", VBox.class);
myvbox.getChildren().add(new Button("Hello world !!!"));
you can use Controller and add autopopulated field:
#FXML
VBox myvbox;