Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access UI components from SceneBuilder in JavaFX

Tags:

javafx

(DUPLICATE & SOLVED - see answer below)

I'm doing my first steps in JavaFX and it seems quite hard to use the "SceneBuilder". I'm used to Android and the QtCreator. It looks to me that there is accessing the UI components much easier.

Something like findViewById(R.id.btnPushMe); <- Android Code

Actually I got an solution but it is quite uncomfortable to use. This looks as this:

FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("../fmxl/main.fxml"));

AnchorPane pane = loader.load();
System.out.println("panechilds:" + pane.getChildren().size());

BorderPane border = (BorderPane) pane.getChildren().get(0);
System.out.println("borderchilds:" + border.getChildren().size());

the xml..

<AnchorPane fx:id="mAnchor" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0"
            xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.progui.MainController">
    <children>
        <BorderPane layoutX="-1.0" prefHeight="600.0" prefWidth="800.0">
            <top>

               ...

Thanks in advance Martin

Edit:

This is a duplicate question (but I will not delete it, because I took some time to find the answer - maybe because JavaFX wasn't asked as much as Android questions were..)

AnchorPane anchor = (AnchorPane) scene.lookup("#mAnchor");

found here: How to find an element with an ID in JavaFX?

like image 591
Martin Pfeffer Avatar asked Apr 05 '15 23:04

Martin Pfeffer


2 Answers

You should use a controller class and access the UI elements there.

Basically you do:

<AnchorPane fx:id="mAnchor" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="800.0"
            xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="app.progui.MainController">
    <children>
        <BorderPane fx:id="border" layoutX="-1.0" prefHeight="600.0" prefWidth="800.0">
            <top>

               ...

And then you can access the fx:id-attributed elements in the controller with

package app.progui ;

// ...

public class MainController {

    @FXML
    private BorderPane border ;


    public void initialize() {
        border.setStyle("-fx-background-color: antiquewhite;");
        // ...
    }

    // ...
}

The field names in the controller class must match the fx:id values in the FXML file.

It is possible to access the fx:id-attributed elements in the class that invoked the FXMLLoader, but if you need to do this it is usually a sign that your overall design is wrong. You can do:

FXMLLoader loader = new FXMLLoader(MainApp.class.getResource("../fmxl/main.fxml"));

AnchorPane pane = loader.load();
Map<String, Object> fxmlNamespace = loader.getNamespace();
BorderPane border = (BorderPane) fxmlNamespace.get("border");

assuming the fx:id defined in the FXML snipped above.

like image 166
James_D Avatar answered Sep 21 '22 12:09

James_D


When you design for FXML, you typically design three things: the application logic, the GUI controller logic, and the FXML.

References to the UI controls you wish to access are injected by the FXML loader into your controller class during its loading and initialization so that you do not need to use a FindById() method.

A controller class looks similar to this:

class DCServRecEditor extends DialogController {


@FXML // ResourceBundle that was given to the FXMLLoader
private ResourceBundle resources;

@FXML // URL location of the FXML file that was given to the FXMLLoader
private URL location;

@FXML // fx:id="ancMatchSelector"
private AnchorPane ancMatchSelector; // Value injected by FXMLLoader

@FXML // fx:id="ancServEditor"
private AnchorPane ancServEditor; // Value injected by FXMLLoader

@FXML // fx:id="ancServRecEditor"
private AnchorPane ancServRecEditor; // Value injected by FXMLLoader
:
:

The FXML loading facility automatically injects references into instance fields that are annotated with the @FXML tag. To manipulate a UI control, just access its methods using the appropriate reference.

Separating the UI control logic from your application logic is highly desirable, and effects a "separation of concerns". When you get used to designing FXML UI's this way, you'll enjoy it.

like image 23
scottb Avatar answered Sep 20 '22 12:09

scottb