I am attempting to add data to a TableView
that has a different controller than the main application. After some tinkering, I did this for some time with a static TableView
and a static method for calling the updates. However, I've run into problems with this approach elsewhere in the code and some other research led me to believe that the FXMLLoader
might help.
But the data that should be added does not show up in the table. The System.out.println("adding info");
shows up in the console twice as expected, but the table stays empty. It was populated when using the static approach. I am guessing my FXMLLoader
is creating a different instance than the one that was created at program start. What is the problem in the code below, mostly in the main class the showMainStage part?
Main class:
package test.controller;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
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;
public class InteractionTest extends Application {
private Stage mainStage;
/**
* Show the main window.
*
* @throws IOException
*/
private void showMainStage() throws IOException {
final FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/fxml/Main.fxml"));
final Parent root = loader.load();
final BorderPane bp = (BorderPane) root;
mainStage = new Stage();
mainStage.setScene(new Scene(bp));
mainStage.setTitle("Interaction test");
mainStage.setMaximized(false);
mainStage.show();
final Info i1 = new Info("1");
i1.setPosition(1);
i1.setTitle("Info 1");
final Info i2 = new Info("2");
i2.setPosition(2);
i2.setTitle("Info 2");
final List<Info> infoList = new ArrayList<>();
infoList.add(i1);
infoList.add(i2);
final FXMLLoader tableLoader = new FXMLLoader(getClass().getResource("/fxml/InfoTable.fxml"));
final Parent parent = tableLoader.load();
final InfoTableController itc = (InfoTableController) tableLoader.getController();
itc.updateTable(infoList);
}
@Override
public void start(final Stage initStage) throws Exception {
try {
showMainStage();
} catch (final IOException e) {
e.printStackTrace();
}
}
/**
* Main method.
*
* @param args
*/
public static void main(final String[] args) {
launch();
}
}
TableController:
package test.controller;
import java.io.IOException;
import java.util.List;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableColumn.SortType;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
/**
* Holds a {@link TableView} to display the infos for further interaction. Is
* the controller for InfoTable.fxml.
*
*/
public class InfoTableController {
/**
* A {@link ScrollPane} for the {@link Info} table.
*/
@FXML
private ScrollPane infoTablePane;
/**
* A {@link TableView} for the {@link Info}s.
*/
private final TableView<Info> table = new TableView<>();
/**
* Build the column headers during initialization.
*/
@FXML
public void initialize() {
final TableColumn<Info, String> positionColumn = new TableColumn<>("#");
positionColumn.setEditable(false);
positionColumn.setPrefWidth(15.0);
positionColumn.setMaxWidth(50.0);
positionColumn.setSortable(true);
positionColumn.setSortType(SortType.ASCENDING);
positionColumn.setCellValueFactory(new PropertyValueFactory<>("position"));
final TableColumn<Info, String> titleColumn = new TableColumn<>("Title");
titleColumn.setEditable(true);
titleColumn.setPrefWidth(200.0);
titleColumn.setMaxWidth(1000.0);
titleColumn.setCellValueFactory(new PropertyValueFactory<>("title"));
table.getColumns().addAll(positionColumn, titleColumn);
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.getSortOrder().add(positionColumn);
table.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
table.getSelectionModel().setCellSelectionEnabled(true);
table.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
final String id = newValue.getId();
final FXMLLoader loader = new FXMLLoader(getClass().getResource("/fxml/InfoDisplay.fxml"));
try {
final Parent parent = loader.load();
} catch (final IOException e1) {
e1.printStackTrace();
}
final InfoDisplayController idc = (InfoDisplayController) loader.getController();
idc.displayDocument(id);
});
infoTablePane.setContent(table);
infoTablePane.setFitToWidth(true);
infoTablePane.setFitToHeight(true);
}
/**
* Sorts the {@link #table}.
*/
public void sortTable() {
table.sort();
}
/**
* Adds table entries.
*
*/
public void updateTable(final List<Info> infoList) {
table.getItems().clear();
for (final Info info : infoList) {
System.out.println("adding info");
table.getItems().add(info);
}
}
}
DisplayController:
package test.controller;
import javafx.fxml.FXML;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.Tab;
import javafx.scene.control.TabPane;
import javafx.scene.control.TextArea;
/**
* Displays infos for reading. Controller for InfoDisplay.fxml.
*
*/
public class InfoDisplayController {
@FXML
private TabPane infoDisplayTabPane;
/**
* Constructor.
*/
public InfoDisplayController() {
}
@FXML
public void initialize() {
infoDisplayTabPane.getTabs().add(new Tab("test in class"));
}
/**
* Displays the selected document in tabs.
*
* @param id The selected document's id.
*/
public void displayDocument(final String id) {
// get the underlying Lucene document with the id; omitted for this example
System.out.println("attempting to display " + id);
infoDisplayTabPane.getTabs().clear();
final TextArea textArea = new TextArea("My info text.");
final ScrollPane scrollPane = new ScrollPane(textArea);
final Tab tab = new Tab("info", scrollPane);
infoDisplayTabPane.getTabs().add(tab);
}
}
Info object:
package test.controller;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
public class Info {
/**
* The id as pulled from the Lucene index.
*/
private final String id;
/**
* The position.
*/
private final SimpleIntegerProperty position = new SimpleIntegerProperty(0);
/**
* The title.
*/
private final SimpleStringProperty title = new SimpleStringProperty("Title");
/**
* Constructor.
*/
public Info(final String id) {
this.id = id;
}
public String getId() {
return id;
}
public int getPosition() {
return position.get();
}
public void setPosition(final int position) {
this.position.set(position);
}
public String getTitle() {
return title.get();
}
public void setTitle(final String title) {
this.title.set(title);
}
}
Main.fxml:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.Text?>
<BorderPane id="BorderPane"
fx:controller="test.controller.InteractionTest"
xmlns:fx="http://javafx.com/fxml">
<top>
</top>
<center>
<SplitPane dividerPositions="0.5" orientation="HORIZONTAL"
focusTraversable="true">
<items>
<fx:include source="InfoTable.fxml" />
<fx:include source="InfoDisplay.fxml" />
</items>
</SplitPane>
</center>
<bottom>
</bottom>
</BorderPane>
InfoTable.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.control.*?>
<ScrollPane xmlns:fx="http://javafx.com/fxml/1"
fx:controller="test.controller.InfoTableController"
fx:id="infoTablePane">
</ScrollPane>
InfoDisplay.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<BorderPane xmlns:fx="http://javafx.com/fxml/1"
prefHeight="500" prefWidth="500" minHeight="200" minWidth="200"
fx:controller="test.controller.InfoDisplayController">
<center>
<TabPane fx:id="infoDisplayTabPane"><Tab text="test"></Tab></TabPane>
</center>
</BorderPane>