Listing file names using FXML TableView - unable to populate data - java

I am trying to populate filesnames in a tabular format using FXML.
I am able to display the table but the rows are not getting displayed.
Directory name will be selected by user during runtime.
.
Main.java
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.AnchorPane;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
try {
AnchorPane root =(AnchorPane)FXMLLoader.load(getClass().getResource("Utility.fxml"));
Scene scene = new Scene(root,600,600);
scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
primaryStage.setScene(scene);
primaryStage.setTitle("testing");
primaryStage.show();
} catch(Exception e){
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
}
AppController.java
import java.io.File;
import java.util.Arrays;
import java.util.List;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.control.*;
import javafx.stage.DirectoryChooser;
public class AppController
{
#FXML private Label BrowseStatus;
#FXML private TextField TDpath;
#FXML private Button CreateH2H;
#FXML private TableView<String> FileListTable;
#FXML private TableColumn<FilesInDir,String> FileNameCol;
#FXML private ObservableList<String> fidlist;
#FXML
protected void handleBrowseWindowsExplorer(ActionEvent event){
DirectoryChooser TestDataDir = new DirectoryChooser();
TestDataDir.setTitle("Select path");
File selectedDir = TestDataDir.showDialog(null);
if(selectedDir == null){
BrowseStatus.setText("Nothing choosen");
TDpath.setText("");
} else {
TDpath.setText(selectedDir.getAbsolutePath());
FileListTable = new TableView<String>();
FileNameCol.setCellValueFactory(new PropertyValueFactory<FilesIndDir,String>("FileName"));
FileListTable.setPlaceholder(BrowseStatus);
BrowseStatus.setText("Folder has been selected");
File tFile = new File(TDpath.getText());
File[] listOfFiles = tFile.listFiles();
fidlist = FXCollections.observableArrayList();
List<String> fileNameList = null;
for (int i=0; i<listOfFiles.length; i++) {
fileNameList = Arrays.asList(listOfFiles[i].getName());
}
fidlist.addAll(fileNamesList);
FileListTable.setItems(fidlist);
}
}
}
Utility.fxml
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.collection.*?>
<?import javafx.collections.FXCollections?>
<?import javafx.geometry.*?>
<?import javafx.scene.chart.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.web.*?>
<?import javafx.scene.control.cell.PropertyValueFactory?>
<AnchorPane fx:controller="application.AppController" id="AnchorPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" xmlns:fx="http://javafx.com/fxml">
<children>
<GridPane>
<children>
<MenuBar maxWidth="-Infinity" prefWidth="800.0" GridPane.ColumnIndex="0" GridPane.RowIndex="0">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="Close" />
</items>
</Menu>
</menus>
</MenuBar>
<BorderPane GridPane.ColumnIndex="0" GridPane.RowIndex="1">
<top>
<TabPane PrefHeight="700.0" PrefWidth="900.0" tabClosingPolicy="UNAVAILABLE">
<Tab text="Files tab ">
<content>
<GridPane hgap="10" vgap="10">
<padding><Insets top="25" right="25" bottom="10" left="25" /></padding>
<children>
<Label text="Path :" GridPane.ColumnIndex="0" GridPane.RowIndex="1" />
<TextField fx:id="TDpath" GridPane.ColumnIndex="0" GridPane.RowIndex="1" />
<Button text="Browse" onAction="#handleBrowseWindowsExplorer" GridPane.ColumnIndex="3" GridPane.RowIndex="1" />
<VBox prefHeight="300.0" prefWidth="400.0" spacing="6.0" VBox.vgrow="ALWAYS" GridPane.ColumnIndex="0" GridPane.RowIndex="3" GridPane.columnSpan="4" >
<children>
<TableView fx:id="FileListTable" >
<placeholder><Label fx:id="BrowseStatus" text="No files in selected directory" /></placeholder>
<columns>
<TableColumn fx:id="FileNameCol" text="File Names" prefWidth="400">
<cellValueFactory>
<PropertyValueFactory property="FileName" />
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
</children>
</VBox>
</children>
</GridPane>
</content>
</Tab>
</TabPane>
</top>
</BorderPane>
</children>
</GridPane>
</children>
</AnchorPane>
FilesInDir.java
import javafx.beans.property.SimpleStringProperty;
public class FilesInDir {
private final SimpleStringProperty FileName = new SimpleStringProperty();
public FilesInDir(String fName) {
setFileName(fName);
}
public String FileNameProperty() {
return FileName.get();
}
public void setFileName(String fName) {
this.Filename.set(fName);
}
}

In this answer I'll just ignore all the typos, since there seems to be a compilable version of the code and point out the other errors:
FilesInDir
If I got your intention, this class should contain the info for a file that should be displayed. Besides ignoring the naming convention of starting identifiers of class members with a lowercase letter, the real issue here is the FileNameProperty. The property method with the suffix Property has to return the property itself and PropertyValueFactory relies on that fact. It should look like this:
public StringProperty fileNameProperty() {
return FileName;
}
Also you did not use the class as type parameter of your TableView:
#FXML
private TableView<FilesInDir> FileListTable;
AppController.handleBrowseWindowsExplorer
The main issue is in this method:
There's no need to need to make fidlist a field, let alone annotate it with #FXML. In fact there's no need to create a new ObservableList at all.
You recreate the TableView, that was created and injected by the FXMLLoader and do not insert it to the scene graph, but you work with the new TableView, which is not the one that is displayed on screen.
If no file is selected, the TextField is emptied, but the items in the TableView from a previously selected directory remain, leading to inconsistent behaviour.
fileNameList = Arrays.asList(listOfFiles[i].getName()); in the for loop replaces the list with a new List containing a single element every time it's executed.
File tFile = new File(TDpath.getText()); recreates the file from the String that was created by converting the selected file to a String. That's just unnecessary; you should simply use selectedDir
Changing the method like this should work, assuming you fixed the points mentioned for FilesInDir too:
#FXML
protected void handleBrowseWindowsExplorer(ActionEvent event) {
DirectoryChooser TestDataDir = new DirectoryChooser();
TestDataDir.setTitle("Select path");
File selectedDir = TestDataDir.showDialog(null);
if (selectedDir == null) {
BrowseStatus.setText("Nothing choosen");
FileListTable.getItems().clear();
TDpath.setText("");
} else {
TDpath.setText(selectedDir.getAbsolutePath());
BrowseStatus.setText("Folder has been selected");
File[] listOfFiles = selectedDir.listFiles();
ArrayList<FilesInDir> fidlist = new ArrayList<>(listOfFiles.length);
for (File listOfFile : listOfFiles) {
fidlist.add(new FilesInDir(listOfFile.getName()));
}
FileListTable.getItems().setAll(fidlist);
}
}

Related

JavaFX Setting an Image to ImageView after selecting it

I want to select a picture on the HDD with the help of JFileChooser and display it in the GUI. The problem is that I can't set the selected image to the ImageView. I think I'm doing something completely wrong but I also tried various other ways to display it for example with BufferedImage but nothing worked for me. I don't get behind this, please help me.
Controller:
package application;
import java.io.File;
import java.net.MalformedURLException;
import javax.swing.JFileChooser;
import javax.swing.filechooser.FileSystemView;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;
public class WindowController {
#FXML private Button btn_load;
#FXML private TextField text_path;
#FXML private ImageView img_frame;
public Main main;
public void setMain(Main main) {
this.main = main;
}
#FXML
public void handle_load() throws MalformedURLException{
JFileChooser chooser = new JFileChooser(FileSystemView.getFileSystemView().getHomeDirectory());
int returnValue = chooser.showOpenDialog(null);
if (returnValue == JFileChooser.APPROVE_OPTION) {
text_path.setText(chooser.getSelectedFile().getAbsolutePath());
File file = new File(chooser.getSelectedFile().getAbsolutePath());
String localURL = file.toURI().toURL().toString();
img_frame.setImage(localURL);
}
}
}
And the fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="700.0" prefWidth="900.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.WindowController">
<children>
<ImageView fx:id="img_frame" fitHeight="516.0" fitWidth="627.0" layoutX="142.0" layoutY="114.0" pickOnBounds="true" preserveRatio="true" AnchorPane.bottomAnchor="97.0" AnchorPane.leftAnchor="142.0" AnchorPane.rightAnchor="142.0" AnchorPane.topAnchor="114.0" />
<HBox layoutX="14.0" layoutY="14.0" prefHeight="25.0" prefWidth="885.0" AnchorPane.leftAnchor="14.0" AnchorPane.rightAnchor="12.0">
<children>
<Button fx:id="btn_load" mnemonicParsing="false" onAction="#handle_load" text="Load Image" HBox.hgrow="NEVER" />
<TextField fx:id="text_path" prefHeight="25.0" prefWidth="0.0" HBox.hgrow="SOMETIMES" />
</children>
</HBox>
</children>
</AnchorPane>
instead of adding it to a url, just add
img_view.setImage(new Image(url));
It will fix your problem

I need to access and clear a Pane from another controller class (javafx and SceneBuilder)

I know that there are a lot of questions already answered for this, but I just cant get my head around it. It is a possible duplicate of:
accessing a Pane from another class in javafx
JavaFX change Pane color from a different class
In my app I want to clear the changablePane (StackPane) in the MainWindowController from a mouseEvent in the NotesScreenController so that only the marked as done notes will be displayed.
MainWindowController.java
package gui;
import gui.mainWindow.issues.NotesScreenController;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.control.*;
import javafx.scene.control.Button;
import javafx.scene.control.MenuBar;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.Stack;
public class MainWindowController implements Initializable {
private Stage stage = null;
private StackPane paneNotes = null;
private NotesScreenController secondPane;
#FXML
private AnchorPane mainContainer;
#FXML
private VBox vBoxContainer;
#FXML
private MenuBar menuBarTop;
#FXML
private HBox hBoxContainer;
#FXML
private StackPane navigationSection;
#FXML
private TreeView<Button> treeView;
#FXML
private StackPane changablePane;
public static Button issuesNotes;
//TAB SO FILTRI
#Override
public void initialize(URL location, ResourceBundle resources) {
createTreeView();
}
private void createTreeView() {
Button treeViewHeader = new Button("Zdravo");
TreeItem<Button> treeViewHeaderItem = new TreeItem<>(treeViewHeader);
treeViewHeader.getStylesheets().add("styles/Notes/TreeViewStyles/TreeButton.css");
treeViewHeaderItem.setExpanded(true);
//ROOT FOR ISSUES TRACKING
Button rootForIssues = new Button("Issues Tracker");
Button issuesTable = new Button("Issues Table");
issuesNotes = new Button("Request Notes");
TreeItem<Button> rootForIssuesItem = new TreeItem<>(rootForIssues);
TreeItem<Button> issuesTableItem = new TreeItem<>(issuesTable);
TreeItem<Button> issuesNotesItem = new TreeItem<>(issuesNotes);
rootForIssues.getStylesheets().add("styles/Notes/TreeViewStyles/TreeButton.css");
issuesTable.getStylesheets().add("styles/Notes/TreeViewStyles/TreeButton.css");
issuesNotes.getStylesheets().add("styles/Notes/TreeViewStyles/TreeButton.css");
rootForIssuesItem.setExpanded(true);
rootForIssuesItem.getChildren().addAll(issuesTableItem, issuesNotesItem);
//ROOT ZA NEKOE DRUGO - PROBNO
Button buttonA = new Button("Proba");
Button buttonB = new Button("Proba");
Button buttonC = new Button("Proba");
TreeItem<Button> nodeA = new TreeItem<>(buttonA);
TreeItem<Button> nodeB = new TreeItem<>(buttonB);
TreeItem<Button> nodeC = new TreeItem<>(buttonC);
buttonA.getStylesheets().add("styles/Notes/TreeViewStyles/TreeButton.css");
buttonB.getStylesheets().add("styles/Notes/TreeViewStyles/TreeButton.css");
buttonC.getStylesheets().add("styles/Notes/TreeViewStyles/TreeButton.css");
nodeA.setExpanded(true);
nodeA.getChildren().addAll(nodeB, nodeC);
//ADDING ALL ROOTs OF THE TREEVIEW
treeViewHeaderItem.getChildren().addAll(rootForIssuesItem, nodeA);
issuesNotes.setOnAction(event ->{
clearPane();
URL paneOneUrl = getClass().getClassLoader().getResource("gui/mainWindow/issues/NotesScreen.fxml");
FXMLLoader loader = new FXMLLoader();
NotesScreenController nsc = new NotesScreenController();
loader.setController(nsc);
try {
paneNotes = loader.load(paneOneUrl);
changablePane.getChildren().add(paneNotes);
} catch (IOException e) {
e.printStackTrace();
}
});
issuesTable.setOnAction(event -> {
clearPane();
});
//TREE VIEW
treeView.setId("tree-view-issues");
treeView.getStylesheets().addAll("styles/Notes/TreeViewStyles/TreeView.css");
treeView.setRoot(treeViewHeaderItem);
}
public void clearPane() {
changablePane.getChildren().clear();
}
public void getMainScreenController() {
}
public static Button getIssuesNotes() {
return issuesNotes;
}
public void setStage(Stage stage) {
this.stage = stage;
stage.setResizable(true);
stage.setTitle("SoloStats - Welcome");
}
public void closeStage() {
if (this.stage != null) {
this.stage.close();
}
}
}
MainWindow.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Menu?>
<?import javafx.scene.control.MenuBar?>
<?import javafx.scene.control.MenuItem?>
<?import javafx.scene.control.TreeView?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.VBox?>
<AnchorPane fx:id="mainContainer" maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="1200.0" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.MainWindowController">
<children>
<VBox fx:id="vBoxContainer" layoutX="530.0" layoutY="230.0" prefHeight="25.0" prefWidth="1200.0" AnchorPane.bottomAnchor="572.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<MenuBar fx:id="menuBarTop" prefHeight="25.0">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="Close" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" text="Delete" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</children>
</VBox>
<HBox fx:id="hBoxContainer" layoutX="384.0" layoutY="238.0" prefHeight="600.0" prefWidth="1200.0" style="-fx-background-color: rgb(247, 247, 247);" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="25.0">
<children>
<StackPane fx:id="navigationSection" prefHeight="150.0" prefWidth="300.0" style="-fx-background-color: #222;">
<children>
<TreeView fx:id="treeView" fixedCellSize="24.0" prefHeight="200.0" prefWidth="200.0">
<StackPane.margin>
<Insets left="-25.0" />
</StackPane.margin>
</TreeView>
</children>
</StackPane>
<StackPane fx:id="changablePane" prefHeight="575.0" prefWidth="950.0" stylesheets="#../styles/MainWindow/StackPaneChangable.css" HBox.hgrow="ALWAYS" />
</children>
</HBox>
</children>
</AnchorPane>
NotesScreenController.java
package gui.mainWindow.issues;
import gui.MainWindowController;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ScrollPane;
import javafx.scene.layout.*;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
public class NotesScreenController extends AnchorPane implements Initializable {
private NotesDirectory notesDirectory = new NotesDirectory();
private MainWindowController mainController;
#FXML
private StackPane mainContainer;
#FXML
private VBox vBoxContainer;
#FXML
private HBox hBoxFilterContainer;
#FXML
private ScrollPane scrollPane;
#FXML
private TilePane tilePaneNotesScreen;
#FXML
private ComboBox<String> generalSortBox;
#FXML
private ComboBox<String> sortByNameBox;
#Override
public void initialize(URL location, ResourceBundle resources) {
loadScreen();
}
public void loadScreen() {
try {
notesDirectory.insertNotesToTilePane(tilePaneNotesScreen, notesDirectory.deserializedNotesList(notesDirectory.getFileName(new File("src/notesDirectory")), "src/notesDirectory/"));
} catch (IOException e) {
e.printStackTrace();
}
generalSortBox.setItems(FXCollections.observableArrayList("Flagged", "Date added", "Done Notes"));
sortByNameBox.setItems(FXCollections.observableArrayList("Priority", "Priority", "Priority", "Priority",
"Priority", "Priority", "Priority", "Priority", "Priority", "Priority", "Priority", "Priority",
"Priority", "Priority"));
generalSortBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> selected, String oldValue, String newValue) {
if (newValue != null) {
switch (newValue) {
case "Done Notes": try {
//THE ACTION NEED TO TAKE PLACE HERE
notesDirectory.insertNotesToTilePane(tilePaneNotesScreen, notesDirectory.deserializedNotesList(notesDirectory.getFileName(new File("src/notesRecycleBin")), "src/notesRecycleBin/"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
});
}
public void setMainController(MainWindowController controller) {
this.mainController = controller;
}
}
NotesScreen
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.ScrollPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.layout.TilePane?>
<?import javafx.scene.layout.VBox?>
<StackPane fx:id="mainContainer" prefHeight="575.0" prefWidth="950.0" stylesheets="#../../../styles/MainWindow/StackPaneChangable.css" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="gui.mainWindow.issues.NotesScreenController">
<children>
<VBox fx:id="vBoxContainer" prefHeight="575.0" prefWidth="950.0">
<children>
<HBox fx:id="hBoxFilterContainer" stylesheets="#../../../styles/MainWindow/ChoiceBox/HBoxFilters.css">
<children>
<ComboBox fx:id="generalSortBox" prefHeight="25.0" prefWidth="220.0" promptText="Sort by..." stylesheets="#../../../styles/MainWindow/ChoiceBox/ComboBox.css" />
<ComboBox fx:id="sortByNameBox" prefHeight="25.0" prefWidth="220.0" promptText="Choose name" stylesheets="#../../../styles/MainWindow/ChoiceBox/ComboBox.css" />
</children>
</HBox>
<ScrollPane fx:id="scrollPane" fitToHeight="true" fitToWidth="true" hbarPolicy="NEVER" prefHeight="575.0" prefWidth="950.0" stylesheets="#../../../styles/MainWindow/StackPaneChangable.css" VBox.vgrow="ALWAYS">
<content>
<TilePane fx:id="tilePaneNotesScreen" hgap="25.0" prefColumns="4" prefHeight="575.0" prefTileWidth="228.0" prefWidth="950.0" stylesheets="#../../../styles/MainWindow/StackPaneChangable.css" vgap="25.0">
<padding>
<Insets bottom="25.0" left="25.0" right="25.0" top="35.0" />
</padding>
</TilePane>
</content>
</ScrollPane>
</children>
</VBox>
</children>
</StackPane>
Basically all you are missing is setting the main screen controller in the NotesScreenController instance:
FXMLLoader loader = new FXMLLoader();
NotesScreenController nsc = new NotesScreenController();
loader.setController(nsc);
nsc.setMainController(this);
And then from the NotesScreenController you can clear the pane simply by calling
mainController.clearPane();
i.e. you can do:
generalSortBox.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<String>() {
#Override
public void changed(ObservableValue<? extends String> selected, String oldValue, String newValue) {
if (newValue != null) {
switch (newValue) {
case "Done Notes": try {
//THE ACTION NEED TO TAKE PLACE HERE
mainController.clearPane();
notesDirectory.insertNotesToTilePane(tilePaneNotesScreen, notesDirectory.deserializedNotesList(notesDirectory.getFileName(new File("src/notesRecycleBin")), "src/notesRecycleBin/"));
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
});
Note you have one subtle bug: when you call
paneNotes = loader.load(paneOneUrl);
you are calling the static FXMLLoader.load(URL) method. Since it's a static method, it's not invoked on the FXMLLoader instance you created, and so the previous call to setController(...) is effectively ignored. You need to set the location of the FXMLLoader instance, and then call the no-arg load() method. So you should have:
issuesNotes.setOnAction(event ->{
clearPane();
URL paneOneUrl = getClass().getClassLoader().getResource("gui/mainWindow/issues/NotesScreen.fxml");
FXMLLoader loader = new FXMLLoader();
NotesScreenController nsc = new NotesScreenController();
nsc.setMainController(this);
loader.setController(nsc);
loader.setLocation(paneOneUrl);
try {
// note call to no-arg load() method:
paneNotes = loader.load();
changablePane.getChildren().add(paneNotes);
} catch (IOException e) {
e.printStackTrace();
}
});
Finally, since you are setting the controller from the Java code, you need to remove the fx:controller attribute from the NotesScreen.fxml root element:
<StackPane fx:id="mainContainer" prefHeight="575.0" prefWidth="950.0" stylesheets="#../../../styles/MainWindow/StackPaneChangable.css" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1">
<!-- ... -->
</StackPane>

Java Fx, Edit the textarea of a specific tab

Well, my question is simple.
I am building an application with Java Fx, and I have a TabPane.
When I open a new Tab, that Tab gets it's content by a fxml file.
tab.setContent((Node)FXMLLoader.load(this.getClass().getResource("/main/textEditor.fxml")))
Fine, that works well, it always loads the same file on all Tabs, so, all textarea on all tabs have the same id.
The problem is, with java, I can only get the information of the textarea of the first Tab.
How can i edit specifically the textarea of one tab in particular?
An example of what i want to do :
Main
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Rectangle2D;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Screen;
import javafx.stage.Stage;
public class Main extends Application{
public static void main(String[] args) {
Application.launch(Main.class, args);
}
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/tabPane/test.fxml"));
Screen screen = Screen.getPrimary();
Rectangle2D bounds = screen.getVisualBounds();
stage.setScene(new Scene(root));
stage.show();
}
}
test.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import java.lang.*?>
<?import java.net.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.layout.AnchorPane?>
<VBox prefHeight="400.0" prefWidth="640.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="tabPane.controller">
<children>
<MenuBar VBox.vgrow="NEVER">
<menus>
<Menu mnemonicParsing="false" onAction="#test" text="File">
<items>
<MenuItem fx:id="insert" mnemonicParsing="false" onAction="#test" text="Insert" />
</items>
</Menu>
</menus>
</MenuBar>
<AnchorPane maxHeight="-1.0" maxWidth="-1.0" prefHeight="-1.0" prefWidth="-1.0" VBox.vgrow="ALWAYS">
<children>
<Label alignment="CENTER" layoutX="155.0" layoutY="177.0" style="
" text="Drag components from Library here…" textAlignment="CENTER" textFill="#9f9f9f" wrapText="false">
<font>
<Font size="18.0" />
</font>
</Label>
<TabPane fx:id="tabPane" prefHeight="375.0" prefWidth="640.0" tabClosingPolicy="UNAVAILABLE">
<tabs>
<Tab text="Untitled Tab 1">
<content>
<TextArea fx:id="textarea" prefHeight="200.0" prefWidth="200.0" text="a" />
</content>
</Tab>
<Tab text="Untitled Tab 2">
<content>
<TextArea fx:id="textarea1" prefHeight="200.0" prefWidth="200.0" text="a" />
</content>
</Tab>
</tabs>
</TabPane>
</children>
</AnchorPane>
</children>
<stylesheets>
<URL value="#../../../../BasicApplicatio11n_css/BasicApplication.css" />
controller.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.TextArea;
public class controller implements Initializable{
#FXML
private TextArea textarea;
#Override
public void initialize(URL arg0, ResourceBundle arg1) {
}
public void test(ActionEvent event){
textarea.appendText("Text");
}
}
There are two tabs on this example, when the button is pressed, I want to add the text on the current selected tab.
There are a few different ways to do this. One way is to let the controller for the tab content expose the textProperty from the text area. Then in your "main controller", create a StringProperty field. When you create a new tab, just observe its selected property and update the string property field to point to the one from the current controller. Then you can easily load text into the "current" pane.
Here's a simple example of this:
EditorController:
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.scene.control.TextArea;
public class EditorController {
#FXML
private TextArea textArea ;
public StringProperty textProperty() {
return textArea.textProperty() ;
}
}
with textEditor.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.control.TextArea?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="EditorController">
<center>
<TextArea fx:id="textArea"/>
</center>
</BorderPane>
And then the MainController could look like:
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import javafx.beans.property.StringProperty;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.stage.FileChooser;
public class MainController {
#FXML
private TabPane tabPane ;
private StringProperty currentText ;
public void initialize() throws IOException {
// load an initial tab:
newTab();
}
#FXML
private void newTab() throws IOException {
Tab tab = new Tab("Untitled text");
FXMLLoader loader = new FXMLLoader(getClass().getResource("textEditor.fxml"));
tab.setContent(loader.load());
EditorController controller = loader.getController() ;
tab.selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
if (isNowSelected) {
currentText = controller.textProperty();
}
});
tabPane.getTabs().add(tab);
tabPane.getSelectionModel().select(tab);
}
#FXML
private void load() {
FileChooser chooser = new FileChooser();
File file = chooser.showOpenDialog(tabPane.getScene().getWindow());
if (file != null) {
Path path = file.toPath();
try {
currentText.set(String.join("\n", Files.readAllLines(path)));
} catch (IOException e) {
Alert alert = new Alert(AlertType.ERROR);
alert.setContentText("Unable to load file "+path);
alert.setTitle("Load error");
alert.showAndWait();
}
tabPane.getSelectionModel().getSelectedItem().setText(path.getFileName().toString());
}
}
}
with main.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.BorderPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="MainController">
<center>
<TabPane fx:id="tabPane"/>
</center>
<bottom>
<HBox alignment="CENTER" spacing="5">
<padding>
<Insets top="5" right="5" left="5" bottom="5" />
</padding>
<Button text="Load..." onAction="#load" />
<Button text="New" onAction="#newTab"/>
</HBox>
</bottom>
</BorderPane>
For completeness, a simple application class:
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 Main extends Application {
#Override
public void start(Stage primaryStage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("main.fxml"));
Scene scene = new Scene(root, 800, 800);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
There are other approaches, e.g. you could just change the button's onAction property when the tab selection changes, etc.

JavaFX 8 - Layout swapping or similar/equivalent functionality to Qt's StackedWidget?

I've been asked to write a conversion program in JavaFX, but i need to allow the user to set different options depending on the conversion direction.
In reaction to swapping the conversion direction, I need to show two different (unique) sets of controls for options relating to the current direction only.
In one direction I need to display two TextFields, in the other direction, a pair of RadioButtons. I could show both at the same time and just enable/disable when needed, but I'm trying for a less cluttered approach first.
I'm looking for a solution that has similar layout-switching functionality to Qt's StackedWidget that I've used in C++, so i can swap out the TextFields for the RadioButtons and vice versa depending on the conversion direction.
It's important to note that this window has many other options that are common to both directions, so it's only a small part that needs to change according to the conversion direction. Thus I'd prefer it if I could easily access the swapped controls from within the same controller.
I don't want tabs or page numbers as the user controls the direction elsewhere, so TabPane and Pagination are out, unless those undesirable pieces of functionality can be disabled.
I've heard that there's something called a CardLayout in another Java framework (it's in awt if i heard right) which would do the job I want, what's the JavaFX 8 equivalent? Or is there another solution that i should be using instead?
I'm using SceneBuilder so ideally something i can implement in that, but I can use pure code if need be.
You can use any Pane subclass (e.g. a StackPane) and call pane.getChildren().setAll(textFieldDisplay); or pane.getChildren().setAll(radioButtonDisplay); as needed. The different displays can be any kind of Node, but since they hold other controls they would typically also be some subclass of Pane. In the example below I use a GridPane for one and a VBox for the other. In a real application, you might define each one in its own FXML file and load them independently, etc.
Complete example (using FXML):
Main.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainController"
alignment="CENTER">
<padding>
<Insets top="20" left="20" right="20" bottom="20" />
</padding>
<CheckBox text="Show Text Fields" fx:id="showTextFields" VBox.vgrow="NEVER">
<VBox.margin>
<Insets top="10" left="10" right="10" bottom="10"/>
</VBox.margin>
</CheckBox>
<StackPane fx:id="display" VBox.vgrow="ALWAYS" />
<Button text="OK" onAction="#submit" VBox.vgrow="NEVER" />
</VBox>
MainController.java:
package application;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.layout.StackPane;
public class MainController {
#FXML
private CheckBox showTextFields ;
#FXML
private StackPane display ;
private Node radioDisplay ;
private Node textFieldDisplay ;
private RadioButtonController radioButtonController ;
private TextFieldController textFieldController ;
public void initialize() throws Exception {
FXMLLoader radioDisplayLoader = new FXMLLoader(getClass().getResource("RadioDisplay.fxml"));
radioDisplay = radioDisplayLoader.load();
radioButtonController = radioDisplayLoader.getController();
FXMLLoader textFieldDisplayLoader = new FXMLLoader(getClass().getResource("TextFieldDisplay.fxml"));
textFieldDisplay = textFieldDisplayLoader.load();
textFieldController = textFieldDisplayLoader.getController();
showTextFields.selectedProperty().addListener((obs, wasSelected, isSelected) -> {
if (isSelected) {
display.getChildren().setAll(textFieldDisplay);
} else {
display.getChildren().setAll(radioDisplay);
}
});
display.getChildren().add(radioDisplay);
}
#FXML
private void submit() {
if (showTextFields.isSelected()) {
System.out.println("Value 1 is "+ textFieldController.getText1());
System.out.println("Value 2 is "+ textFieldController.getText2());
} else {
System.out.println("Chosen value is "+radioButtonController.getSelectedItem());
}
}
}
RadioDisplay.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.RadioButton?>
<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.RadioButtonController"
alignment="TOP_CENTER" spacing="10">
<padding>
<Insets top="10" left="10" right="10" bottom="10"/>
</padding>
<RadioButton text="Choice 1" selected="true" fx:id="choice1"/>
<RadioButton text="Choice 2" fx:id="choice2"/>
</VBox>
RadioButtonController.java:
package application;
import javafx.fxml.FXML;
import javafx.scene.control.RadioButton;
import javafx.scene.control.ToggleGroup;
public class RadioButtonController {
#FXML
private RadioButton choice1 ;
#FXML
private RadioButton choice2 ;
public void initialize() {
ToggleGroup toggleGroup = new ToggleGroup();
choice1.setToggleGroup(toggleGroup);
choice2.setToggleGroup(toggleGroup);
}
public String getSelectedItem() {
if (choice1.isSelected()) {
return "Choice 1";
} else if (choice2.isSelected()) {
return "Choice 2";
} else return "" ;
}
}
TextFieldDisplay.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<GridPane xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.TextFieldController"
hgap="10" vgap="10">
<columnConstraints>
<ColumnConstraints hgrow="NEVER" halignment="RIGHT"/>
<ColumnConstraints hgrow="SOMETIMES" />
</columnConstraints>
<Label text="Value 1:" GridPane.columnIndex="0" GridPane.rowIndex="0"/>
<Label text="Value 2:" GridPane.columnIndex="0" GridPane.rowIndex="1"/>
<TextField fx:id="textField1" GridPane.columnIndex="1" GridPane.rowIndex="0"/>
<TextField fx:id="textField2" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
</GridPane>
TextFieldController.java:
package application;
import javafx.fxml.FXML;
import javafx.scene.control.TextField;
public class TextFieldController {
#FXML
private TextField textField1 ;
#FXML
private TextField textField2 ;
public String getText1() {
return textField1.getText() ;
}
public String getText2() {
return textField2.getText();
}
}
Main.java:
package application;
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.VBox;
import javafx.fxml.FXMLLoader;
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
VBox root = (VBox)FXMLLoader.load(getClass().getResource("Main.fxml"));
Scene scene = new Scene(root,400,400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
All the FXML files are in the same package (application) as the .java files.
Update
If you prefer not to "modularize" it to this extent, you can put everything in a single FXML with a single controller. In that case, Main.fxml looks like
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.layout.StackPane?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.RadioButton?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextField?>
<VBox xmlns:fx="http://javafx.com/fxml/1" fx:controller="application.MainController"
alignment="CENTER">
<padding>
<Insets top="20" left="20" right="20" bottom="20" />
</padding>
<CheckBox text="Show Text Fields" fx:id="showTextFields" VBox.vgrow="NEVER">
<VBox.margin>
<Insets top="10" left="10" right="10" bottom="10"/>
</VBox.margin>
</CheckBox>
<StackPane fx:id="display" VBox.vgrow="ALWAYS">
<VBox fx:id="radioDisplay" alignment="TOP_CENTER" spacing="10">
<padding>
<Insets top="10" left="10" right="10" bottom="10" />
</padding>
<RadioButton text="Choice 1" selected="true" fx:id="choice1" />
<RadioButton text="Choice 2" fx:id="choice2" />
</VBox>
<fx:define>
<GridPane fx:id="textFieldDisplay" hgap="10" vgap="10">
<columnConstraints>
<ColumnConstraints hgrow="NEVER" halignment="RIGHT" />
<ColumnConstraints hgrow="SOMETIMES" />
</columnConstraints>
<Label text="Value 1:" GridPane.columnIndex="0"
GridPane.rowIndex="0" />
<Label text="Value 2:" GridPane.columnIndex="0"
GridPane.rowIndex="1" />
<TextField fx:id="textField1" GridPane.columnIndex="1"
GridPane.rowIndex="0" />
<TextField fx:id="textField2" GridPane.columnIndex="1"
GridPane.rowIndex="1" />
</GridPane>
</fx:define>
</StackPane>
<Button text="OK" onAction="#submit" VBox.vgrow="NEVER" />
</VBox>
and the corresponding controller is
package application;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.CheckBox;
import javafx.scene.control.RadioButton;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleGroup;
import javafx.scene.layout.StackPane;
public class MainController {
#FXML
private CheckBox showTextFields ;
#FXML
private StackPane display ;
#FXML
private Node radioDisplay ;
#FXML
private Node textFieldDisplay ;
#FXML
private TextField textField1 ;
#FXML
private TextField textField2 ;
#FXML
private RadioButton choice1 ;
#FXML
private RadioButton choice2 ;
public void initialize() throws Exception {
showTextFields.selectedProperty().addListener((obs, wasSelected, isSelected) -> {
if (isSelected) {
display.getChildren().setAll(textFieldDisplay);
} else {
display.getChildren().setAll(radioDisplay);
}
});
ToggleGroup toggleGroup = new ToggleGroup();
choice1.setToggleGroup(toggleGroup);
choice2.setToggleGroup(toggleGroup);
}
#FXML
private void submit() {
if (showTextFields.isSelected()) {
System.out.println("Value 1 is "+ textField1.getText());
System.out.println("Value 2 is "+ textField2.getText());
} else {
String chosenValue ;
if (choice1.isSelected()) {
chosenValue = "Choice 1";
} else if (choice2.isSelected()) {
chosenValue = "Choice 2";
} else {
chosenValue
= "None";
}
System.out.println("Chosen value is "+chosenValue);
}
}
}
(and in this case, remove the other two FXML files and their controllers).

JavaFX TreeView is null why?

I want to load the TreeView defined in my FXML file into a TreeView variable in my java code.
But always when I try it the TreeView is NULL.
I looked everywhere, Google, so many questions and answers here but nothing worked out.
I need the TreeView to add dynamicly TreeItems to it.
Here my IconOverview.FXML file located in src/rn.IconTool.view:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.image.*?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import rn.IconTool.model.*?>
<?import javafx.scene.control.TreeView?>
<AnchorPane prefHeight="584.0" prefWidth="966.0" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="rn.IconTool.model.IconOverviewControllerClass">
<children>
<SplitPane dividerPositions="0.229253112033195" layoutX="2.0" layoutY="34.0" prefHeight="547.0" prefWidth="966.0">
<items>
<AnchorPane fx:id="splitPaneMenu" minHeight="0.0" minWidth="0.0" prefHeight="545.0" prefWidth="353.0">
<children>
<TreeView fx:id="treeview" layoutX="-5.0" onMouseClicked="#ShowContextMenu" prefHeight="545.0" prefWidth="218.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" />
</children>
</AnchorPane>
<AnchorPane prefHeight="533.0" prefWidth="675.0">
<children>
<AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="545.0" prefWidth="702.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
<children>
<ImageView fitHeight="95.0" fitWidth="104.0" layoutX="22.0" layoutY="14.0" pickOnBounds="true" preserveRatio="true" />
</children>
</AnchorPane>
</children>
</AnchorPane>
</items>
</SplitPane>
<ToolBar layoutY="-1.0" prefHeight="30.0" prefWidth="968.0" />
</children>
</AnchorPane>
my RootLayout.fxml, located in .view too
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>
<?import rn.IconTool.model.*?>
<BorderPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="rn.IconTool.model.NewCategoryClass">
<top>
<MenuBar BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="Close" />
<MenuItem mnemonicParsing="false" onAction="#NewtCategory" text="New Category" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" text="Delete" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
</BorderPane>
the CreateNewCategoryScreen.fxml in .view too
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.BorderPane?>
<?import rn.IconTool.model.*?>
<BorderPane prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8"
xmlns:fx="http://javafx.com/fxml/1" fx:controller="rn.IconTool.model.NewCategoryClass">
<top>
<MenuBar BorderPane.alignment="CENTER">
<menus>
<Menu mnemonicParsing="false" text="File">
<items>
<MenuItem mnemonicParsing="false" text="Close" />
<MenuItem mnemonicParsing="false" onAction="#NewtCategory" text="New Category" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Edit">
<items>
<MenuItem mnemonicParsing="false" text="Delete" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="About" />
</items>
</Menu>
</menus>
</MenuBar>
</top>
</BorderPane>
And my ContextMenuPane.fxml although located in .view:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane prefHeight="254.0" prefWidth="166.0" xmlns:fx="http://javafx.com/fxml/1"
xmlns="http://javafx.com/javafx/8">
<!-- TODO Add Nodes -->
</AnchorPane>
And here for the Controller Class where I try to get the TreeView src/rn.IconTool.model IconOverviewControllerClass:
package rn.IconTool.model;
import java.io.IOException;
import rn.IconTool.MainApp;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.TreeView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
public class IconOverviewControllerClass {
#FXML TreeView treeview;
#FXML private AnchorPane splitPaneMenu;
public IconOverviewControllerClass(){
}
#FXML
public void ShowContextMenu(MouseEvent r){
GetInTouchWithContextMenu git = new GetInTouchWithContextMenu();
// treeview = (TreeView<String>) getScene().lookup("#treeview");
if(r.getButton() == r.getButton().SECONDARY){
System.out.println("Rechtsklick");
ContextMenu contextM = git.getTheContextMenu();
System.out.println(contextM.toString());
// treeview.setContextMenu(contextM);
//
// contextM.show(treeview, r.getX(), r.getY());
// System.out.println(contextM.isShowing());
System.out.println("X: " + r.getX() + " Y: " + r.getY());
}
}
public TreeView<?> getTreeView() throws IOException{
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/IconOverview.fxml"));
AnchorPane iconOverview = (AnchorPane) loader.load();
treeview = (TreeView<?>) iconOverview.lookup("#treeview");
System.out.println("TreeIconOver: " + treeview + " iconOverView: " + iconOverview);
return treeview;
}
}
And my class for creating a Contextmenu what isn´t working but no so worse. src/rn.IconTool.model
GetInTouchWithContextMenu:
package rn.IconTool.model;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.stage.WindowEvent;
public class GetInTouchWithContextMenu {
private ContextMenu contextM = null;
public GetInTouchWithContextMenu(){
getContextMenu();
}
private void getContextMenu(){
contextM = new ContextMenu();
contextM.setOnShowing(new EventHandler<WindowEvent>() {
public void handle(WindowEvent e) {
System.out.println("showing");
}
});
contextM.setOnShown(new EventHandler<WindowEvent>() {
public void handle(WindowEvent e) {
System.out.println("shown");
}
});
MenuItem item1 = new MenuItem("About");
item1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent e) {
System.out.println("About");
}
});
contextM.getItems().addAll(item1);
}
public ContextMenu getTheContextMenu(){
return contextM;
}
}
And here is my screen to create new TreeItems for my TreeView src/rn.IconTool.model NewCategoryClass
package rn.IconTool.model;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
import rn.IconTool.MainApp;
public class NewCategoryClass {
private AnchorPane categoryPane;
private Stage stage;
private Scene scene;
private Node rootIcon;
#FXML private javafx.scene.control.Button closeButton;
#FXML private javafx.scene.control.TextField categoryName;
#FXML private javafx.scene.control.TextField categoryIconName;
#FXML private javafx.scene.control.TreeView<String> treeview;
public NewCategoryClass(){
//System.out.println("Neue Kategorie erstellen.");
}
#FXML
private void NewtCategory() throws IOException{
System.out.println("Neue Kategorie angelegt.");
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/CreateNewCategoryScreen.fxml"));
categoryPane = (AnchorPane) loader.load();
scene = new Scene(categoryPane);
closeButton = (Button) scene.lookup("#closeButton");
stage = new Stage();
stage.setTitle("Set New Category");
stage.setScene(scene);
stage.show();
}
#FXML
private void FinishButtonlistener() throws IOException{
// get a handle to the stage
Stage stage = (Stage) closeButton.getScene().getWindow();
// do what you have to do
System.out.println("Textfeld: " + categoryName.getText());
// leeres Textfeld = leerer String
TreeItem<String> rootItem;
if(categoryName.getText().equals("")){
}else{
if(categoryIconName.getText().equals("")){
rootItem = new TreeItem<String> (categoryName.getText());
}else{
setRootIcon(categoryIconName.getText());
rootItem = new TreeItem<String> (categoryName.getText(), getRootIcon());
}
IconOverviewControllerClass iocc = new IconOverviewControllerClass();
iocc.getTreeView();
// treeview.setRoot(rootItem);
//System.out.println("AnchorPane: " + splitPaneMenu);
System.out.println("Treeview: " + treeview);
System.out.println("TreeItem: " + rootItem);
stage.close();
}
}
private void setRootIcon(String iconName){
rootIcon = new ImageView( new Image(this.getClass().getResourceAsStream(iconName)));
}
public Node getRootIcon(){
return rootIcon;
}
public Stage getStage(){
return stage;
}
public Scene getScene(){
return scene;
}
}
My main located in src/rn.IconTool
package rn.IconTool;
import java.io.IOException;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
public class MainApp extends Application {
private Stage primaryStage;
private BorderPane rootLayout;
private AnchorPane iconOverview;
private Scene scene;
#Override
public void start(Stage primaryStage) {
this.primaryStage = primaryStage;
this.primaryStage.setTitle("Icon Place");
initRootLayout();
showIconOverview();
}
/**
* Initializes the root layout.
*/
public void initRootLayout() {
try {
// Load root layout from fxml file.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/RootLayout.fxml"));
rootLayout = (BorderPane) loader.load();
// Show the scene containing the root layout.
scene = new Scene(rootLayout);
primaryStage.setScene(scene);
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public void showIconOverview() {
try {
FXMLLoader loader = new FXMLLoader();
loader.setLocation(MainApp.class.getResource("view/IconOverview.fxml"));
iconOverview = (AnchorPane) loader.load();
rootLayout.setCenter(iconOverview);
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Returns the main stage.
* #return
*/
public Stage getPrimaryStage() {
return primaryStage;
}
public static void main(String[] args) {
launch(args);
}
public Scene getScene(){
return scene;
}
}
I hope someone of you can help me
If you need the other classes to build the complete program then ask but I hope you have some ideas that the TreeView is not null ;)
You don't have to lookup the treeview with :
treeview = (TreeView) iconOverview.lookup("#treeview");
You automatically retrieve the treeView with the fx:id defined in the fxml file and the annotation #FXML in the controller.
I know why my TreeView was NULL. I forgot to implements javafx.fxml.Initializable and add the unimplemented method.
Here is my new IconOverviewControllerClass and dont worry about the static TreeView is only for test purpose ;)
package rn.IconTool.model;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.fxml.FXML;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.TreeView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
public class IconOverviewControllerClass implements javafx.fxml.Initializable{
#FXML public TreeView<String> treeview;
#FXML private AnchorPane splitPaneMenu;
private static TreeView<String> statictreeView;
public IconOverviewControllerClass(){
}
#FXML
public void initMyComponents(MouseEvent r) throws IOException{
if(getTreeView() == null){
System.out.println(treeview);
statictreeView = treeview;
System.out.println("static init: " + statictreeView);
}
ShowContextMenu(r);
}
public void ShowContextMenu(MouseEvent r){
if(r.getButton() == r.getButton().SECONDARY){
System.out.println("Rechtsklick");
GetInTouchWithContextMenu git = new GetInTouchWithContextMenu();
ContextMenu contextM = git.getTheContextMenu();
System.out.println(contextM.toString());
treeview.setContextMenu(contextM);
contextM.show(treeview, r.getX(), r.getY());
System.out.println(contextM.isShowing());
System.out.println("X: " + r.getX() + " Y: " + r.getY());
}
}
public TreeView<String> getTreeView() throws IOException{
return statictreeView;
}
#Override
public void initialize(URL location, ResourceBundle resources) {
//System.out.println(treeview);
statictreeView = treeview;
}
}

Categories

Resources