JavaFX – Verschachtelte Controller

Veröffentlicht von

Hier mal ein kleines Beispiel, wie man mit JavaFX, in der FXML, Controller verschachtelt und worauf man achten muss.

Wenn man in einer FXML-Datei weitere FXML-Dateien verschachteln will, nutzt man den folgenden Tag. Im SceneBuilder findet man das unter File > Include > FXML…

<fx:include source="PersonEditor.fxml" fx:id="personEditor"/>Code-Sprache: HTML, XML (xml)

Um an den Controller und Container der „PersonEditor.fxml“ zu kommen, fügt man folgenden Code ein. ACHTUNG der Variablen-Name vom Container muss der selbe Name der fx:include ID sein, bei der Controller-Klasse gilt das selbe, aber da muss noch dein „Controller“ angefügt werden, wenn diese Konvention nicht eingehalten wird, sind die Variablen Null.

@FXML private GridPane personEditor;
@FXML private PersonEditorController personEditorController; Code-Sprache: CSS (css)

Hier nochmal den kompletten Code

MainController.java

package app.example.NestedController;

import javafx.beans.binding.Bindings;
import javafx.fxml.FXML;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.util.Callback;

public class MainController {
	// ACHTUNG - der Name von der Controller-Variable muss die ID vom <fx:include /> sein, mit "Controller" hinten dran
	// wenn der Name nicht stimmt, ist die Controller-Klasse null
	@FXML private PersonEditorController personEditorController; 
	
	// ACHTUNG - der Name vom Container muss der Name von der <fx:include /> ID sein, andernfalls ist die Variable null
	@FXML private GridPane personEditor;

	@FXML private ListView<Person> personList ;
	
	public void initialize() {
		personList.getItems().addAll(
			new Person("Hugo", "Lloris"),
			new Person("Kyle", "Walker"),
			new Person("Jan", "Verthongen"),
			new Person("Younes", "Kaboul"),
			new Person("Danny","Rose"),
			new Person("Nacir", "Chadli"),
			new Person("Etienne", "Capoue"),
			new Person("Paulinho", "Maciel"),
			new Person("Andros", "Townsend"),
			new Person("Erik", "Lamela"),
			new Person("Roberto", "Soldado")
		);
		personList.setCellFactory(new Callback<ListView<Person>, ListCell<Person>>() {

			@Override
			public ListCell<Person> call(ListView<Person> listView) {
				return new ListCell<Person>() {
					@Override
					public void updateItem(Person person, boolean empty) {
						super.updateItem(person, empty);
						textProperty().unbind();
						if (person != null) {
							textProperty().bind(Bindings.format("%s %s", person.firstNameProperty(), person.lastNameProperty()));
						}
					}
				};
			}
			
		});
		
		personEditorController.personProperty().bind(personList.getSelectionModel().selectedItemProperty());
	}
}Code-Sprache: PHP (php)

PersonViewer.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.SplitPane?>
<?import javafx.scene.control.ListView?>
<?import javafx.scene.layout.Pane?>

<BorderPane xmlns:fx="http://javafx.com/fxml" fx:controller="app.example.NestedController.MainController">
	<center>
		<SplitPane>
			<ListView fx:id="personList"/>
			<Pane>
				<fx:include source="PersonEditor.fxml" fx:id="personEditor"/>
			</Pane>
		</SplitPane>
	</center>
</BorderPane>Code-Sprache: HTML, XML (xml)

PersonEditorController.java

package app.example.NestedController;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;

public class PersonEditorController {
	private final ObjectProperty<Person> person ;
	@FXML
	private TextField firstName ;
	@FXML
	private TextField lastName ;
	
	public PersonEditorController() {
		this.person = new SimpleObjectProperty<>(this, "person", null);
	}
	
	public void initialize() {
		this.person.addListener(new ChangeListener<Person>() {
			@Override
			public void changed(ObservableValue<? extends Person> observable,
					Person oldPerson, Person newPerson) {
				if (oldPerson != null) {
					firstName.textProperty().unbindBidirectional(oldPerson.firstNameProperty());
					lastName.textProperty().unbindBidirectional(oldPerson.lastNameProperty());
				}
				if (newPerson != null) {
					firstName.textProperty().bindBidirectional(newPerson.firstNameProperty());
					lastName.textProperty().bindBidirectional(newPerson.lastNameProperty());
				}
			}
		});
	}
	
	public final ObjectProperty<Person> personProperty() {
		return person ;
	}
	
	public final Person getPerson() {
		return person.get() ;
	}
	
	public final void setPerson(Person person) {
		this.person.set(person);
	}
}
Code-Sprache: PHP (php)

PersonViewer.java

package app.example.NestedController;

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 PersonViewer extends Application {

	@Override
	public void start(Stage primaryStage) throws IOException {
		Scene scene = new Scene(FXMLLoader.<Parent>load(getClass().getResource("PersonViewer.fxml")), 600, 400);
		primaryStage.setScene(scene);
		primaryStage.show();
	}

	public static void main(String[] args) {
		launch(args);
	}
}Code-Sprache: JavaScript (javascript)

PersonEditor.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>

<GridPane xmlns:fx="http://javafx.com/fxml" fx:controller="app.example.NestedController.PersonEditorController">
	<Label text="First Name:">
		<GridPane.columnIndex>0</GridPane.columnIndex>
		<GridPane.rowIndex>0</GridPane.rowIndex>
	</Label>
	<Label text="Last Name:">
		<GridPane.columnIndex>0</GridPane.columnIndex>
		<GridPane.rowIndex>1</GridPane.rowIndex>
	</Label>
	<TextField fx:id="firstName">
		<GridPane.columnIndex>1</GridPane.columnIndex>
		<GridPane.rowIndex>0</GridPane.rowIndex>
	</TextField>
	<TextField fx:id="lastName">
		<GridPane.columnIndex>1</GridPane.columnIndex>
		<GridPane.rowIndex>1</GridPane.rowIndex>
	</TextField>
</GridPane>Code-Sprache: HTML, XML (xml)

Person.java

package app.example.NestedController;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;

public class Person {
	private final StringProperty firstName ;
	private final StringProperty lastName ;
	
	public Person(String firstName, String lastName) {
		this.firstName = new SimpleStringProperty(this, "firstName", firstName);
		this.lastName = new SimpleStringProperty(this, "lastName", lastName);
	}
	
	public final StringProperty firstNameProperty() {
		return firstName ;
	}
	
	public final String getFirstName() {
		return firstName.get() ;
	}
	
	public final void setFirstName(String firstName) {
		this.firstName.set(firstName);
	}
	
	public final StringProperty lastNameProperty() {
		return lastName ;
	}
	
	public final String getLastName() {
		return lastName.get();
	}
	
	public final void setLastName(String lastName) {
		this.lastName.set(lastName);
	}
	
	@Override
	public String toString() {
		return getFirstName() + " " + getLastName() ;
	}
}Code-Sprache: PHP (php)