I'm trying to build a simple GUI with JavaFX using SceneBuilder, where I'm using a MenuItem (in Main.fxml
) to select a root folder. The folder's contents are then listed in a TextArea that again is wrapped in a TabPane (FileListTab.fxml
, nested FXML that is included in Main.fxml
).
I used this post as a starting point to get used to MVC. Unfortunately I don't know how to make my nested FXML listen or be bound to the outer one since I'm not explicitly calling it. Right now I'm stuck just to display my chosen folder in a label.
My minimal working code right now looks like this:
Main.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="MainController">
<top>
<MenuBar BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" onAction="#browseInputFolder" text="Open folder" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
<center>
<TabPane prefHeight="200.0" prefWidth="200.0" tabClosingPolicy="UNAVAILABLE" BorderPane.alignment="CENTER">
<tabs>
<Tab text="File listing">
<content>
<fx:include fx:id="analysisTab" source="FileListTab.fxml" />
</content>
</Tab>
</tabs>
</TabPane>
</center>
</BorderPane>
FileListTab.fxml
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" spacing="15.0" xmlns="http://javafx.com/javafx/8.0.40" xmlns:fx="http://javafx.com/fxml/1" fx:controller="FileListController">
<children>
<HBox spacing="10.0">
<children>
<Label minWidth="100.0" text="Root folder:" />
<Label fx:id="label_rootFolder" />
</children>
</HBox>
<TextArea prefHeight="200.0" prefWidth="200.0" />
<HBox spacing="10.0">
<children>
<Label minWidth="100.0" text="Found files:" />
<Label fx:id="label_filesFound" />
</children>
</HBox>
</children>
<padding>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
</VBox>
Model.java (the supposed to be shared model between controllers)
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Model {
private StringProperty rootFolder;
public String getRootFolder() {
return rootFolderProperty().get();
}
public StringProperty rootFolderProperty() {
if (rootFolder == null)
rootFolder = new SimpleStringProperty();
return rootFolder;
}
public void setRootFolder(String rootFolder) {
this.rootFolderProperty().set(rootFolder);
}
}
NestedGUI.java (Main class)
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import java.io.IOException;
public class NestedGUI extends Application {
Model model = new Model();
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
Parent root = null;
try {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getClassLoader().getResource("Main.fxml"));
root = (BorderPane) fxmlLoader.load();
MainController controller = fxmlLoader.getController();
controller.setModel(model);
// This openes another window with the tab's content that is actually displaying the selected root folder
/* FXMLLoader fxmlLoader2 = new FXMLLoader();
fxmlLoader2.setLocation(getClass().getClassLoader().getResource("FileListTab.fxml"));
VBox vBox = (VBox) fxmlLoader2.load();
FileListController listController = fxmlLoader2.getController();
listController.setModel(model);
Scene scene = new Scene(vBox);
Stage stage = new Stage();
stage.setScene(scene);
stage.show();*/
} catch (IOException e) {
e.printStackTrace();
}
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
MainController.java
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import java.io.File;
public class MainController {
Model model;
public void setModel(Model model) {
this.model = model;
}
public void browseInputFolder() {
DirectoryChooser chooser = new DirectoryChooser();
chooser.setTitle("Select folder");
File folder = chooser.showDialog(new Stage());
if (folder == null)
return;
String inputFolderPath = folder.getAbsolutePath() + File.separator;
model.setRootFolder(inputFolderPath);
System.out.print(inputFolderPath);
}
}
FileListController.java
import javafx.fxml.FXML;
import javafx.scene.control.Label;
public class FileListController {
Model model;
@FXML
Label label_rootFolder;
public void setModel(Model model) {
label_rootFolder.textProperty().unbind();
this.model = model;
label_rootFolder.textProperty().bind(model.rootFolderProperty());
}
}
I looked through various posts here on SO, but either I didn't understand the answers or others had different problems. Can somebody give me some pointers? (hints to solve this, code snippets, links...) It looks like a pretty basic FXML-problem, but I just don't get it.
See Question&Answers more detail:os