Guis erstellen mit FXML und javaFX gemischt

venator

Mitglied
Hallo,

beschäftige mich zurzeit viel mit JavaFx und FXML. Dabei tritt bei mir die Frage auf ob sich beiden Möglichkeiten ein GUI zu erstellen ergänzen können (1. FXML 2. Direkt in JavaFX). Entgültiges Ziel ist es z.B den rechten Teil einer horizontalen splitpane dynamisch zur Laufzeit in Java zu erstellen, während der rechte Teil statisch in einer FXML Datei definiert wird.

Habe viel ausprobiert, scheitere aber irgendwie ständig. Eigentlich versuche ich nur der im FXML definierten mainPane ein neues Label in der Javaklasse hinzuzufügen.

Am Besten zeige ich euch mal im Quellcode an einem stark vereinfachten Beispiel was ich meine.

sample.fxml
Java:
<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.collections.*?>

<Pane fx:controller="testapplication.Sample"
    xmlns:fx="http://javafx.com/fxml" 
    fx:id="mainPane">
</Pane>

TestApplication.java
Java:
public class TestApplication extends Application {
    @FXML private Pane mainPane;
    
    public static void main(String[] args) {
        Application.launch(TestApplication.class, args);
    }
    
    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("Sample.fxml"));
        
        stage.setScene(new Scene(root));
        stage.show();

        Label label = new Label();
        label.setText("Hello");
        
        mainPane.getChildren().add(label);
    }
}

Im Controller passiert noch nichts.

Wenn ich das jetzt versuche zu starten, bekomme ich eine java.lang.NullPointerException in der Zeile [JAVA=18]mainPane.getChildren().add(label);[/code] geworfen.

Kann ich die beiden Möglichkeiten eine GUI zu erstellen nicht mischen.
Was mache ich falsch? ???:L

Danke im Voraus
 
Die NullPointerException bekommst du, weil du das Label der
Code:
mainPane
hinzufügen möchtest, aber du initialisierst ja nur deine Parent
Code:
root
.

Edit: Bei mir funktioniert das übrigens dann auch mit einer AnchorPane, die ich über FXML erstelle, mit dem FXMLLoader lade und zu der ich anschließend noch einen Button im Java-Code hinzufüge.

Würde dir zum Testen, mal NetBeans empfehlen, weil es da direkt ein funktionierendes Beispiel gibt.
 
Zuletzt bearbeitet:
Hallo Paddelpirat danke für deine schnelle Antwort,

eigentlich sollte die mainPane durch die sample.fxml bereits initialisiert werden.
Durch
Code:
@FXML private Pane mainPane;
sollte die mainPane in Testapplication.java bekannt sein. (dachte ich)

Benutze auch Netbeans, da mir e(fx)clipse zu umständlich war. Habe auch schon einige Tutorials und Beispiele durchgearbeitet. Jedoch hat mir noch keines bei meinem Problem geholfen.

kannst Du mir noch zeigen, wie Du die mainPane oder AnchorPane initialisiert hast?
 
Hmm vielleicht musst du noch das
Code:
Initializable
implementieren. Ansonsten schätze ich mal, dass das in dem Beispiel funktioniert, weil es zu dem Sample.fxml eine gleichnamige Sample.java gibt.
Aber wie du im Hauptprogramm unten siehst, habe ich die AnchorPane, wie du, mit dem FXMLLoader geladen und anschließend noch einen zusätzlichen Button darauf im Java-Code hinzugefügt.

Ich poste einfach mal wie das bei mir im Beispielprogramm aussieht:

Sample.fxml
Java:
<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml" fx:controller="javafxml.Sample">
    <children>
        <Button id="button" layoutX="126" layoutY="90" text="Click Me!" onAction="#handleButtonAction" fx:id="button" />
        <Label id="label" layoutX="126" layoutY="120" minHeight="16" minWidth="69" prefHeight="16" prefWidth="69" fx:id="label" />
    </children>
</AnchorPane>

Sample.java
Java:
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;

public class Sample implements Initializable {
    
    @FXML
    private Label label;
    
    @FXML
    private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
        label.setText("Hello World!");
    }
    
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    
}

und das aufrufende Programm: JavaFXML.java
Java:
public class JavaFXML extends Application {
    
    public static void main(String[] args) {
        Application.launch(JavaFXML.class, args);
    }
    
    @Override
    public void start(Stage stage) throws Exception {
        AnchorPane root = (AnchorPane)FXMLLoader.load(getClass().getResource("Sample.fxml"));
        root.getChildren().add(new Button("Test Me"));
        
        stage.setScene(new Scene(root));
        stage.show();
    }
}

Edit: Was du evtl. noch ausprobieren könntest ist bei dir
Code:
fx:controller="testapplication.Sample"
auf
Code:
fx:controller="testapplication.TestApplication"
zu ändern. Schaue mir das aber auch gerade zum ersten Mal an ;-)
 
Zuletzt bearbeitet:
Du hast recht. Danke nochmal für das Beispiel.

Desweiteren ist es wahrscheinlich auch kein guter Stil den Button in der
Code:
start
Methode hinzuzufügen.

Dafür ist wahrscheinlich die
Code:
Initializable
da. Hier funktioniert das hinzufügen der Elemente auch besser.

In der
Code:
start
methode ist die Refenenz
Code:
@FXML private Label label;
noch nicht gefüllt.
Somit die NullPointerException.
 

Zurück
Oben