我正在尝试将数据添加到具有与主应用程序不同的控制器的TableView
中。经过一番修补后,我花了一段时间使用静态TableView
和用于调用更新的静态方法。但是,我在代码的其他地方遇到了这种方法的问题,some other research使我相信FXMLLoader
可能会有所帮助。
但是应添加的数据未显示在表中。 System.out.println("adding info");
在控制台中的显示是预期的两倍,但是表保持空白。使用静态方法时已填充。我猜我的FXMLLoader
正在创建一个与程序启动时创建的实例不同的实例。下面的代码(主要在主类的showMainStage部分)中的问题是什么?
主类:
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);
}
}
信息对象:
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>
答案 0 :(得分:0)
好吧,DataTable与您先前初始化的MainStage没有关系。 FXML文件中包含的数据表与您之后创建的数据表不同。我建议您在Main.fxml中创建一个Node,然后在加载第二个文件时覆盖此节点。例如,我的代码库之一包含:
loadingWidget.start();
Task <Parent> task = new Task<Parent>() {
@Override
protected Parent call() throws Exception {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/translationCreator.fxml"));
return loader.load();
}
};
task.setOnFailed(new EventHandler<WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent event) {
loadingWidget.close();
task.getException().printStackTrace();
Notifications.create().title("Something went wrong!").text("Error while loading resource tableWindow.fxml").show();
}
});
task.setOnSucceeded(new EventHandler <WorkerStateEvent>() {
@Override
public void handle(WorkerStateEvent event) {
loadingWidget.close();
contentPane.getChildren().clear();
contentPane.getChildren().add(task.getValue());
}
});
new Thread(task).start();
因此,我刚刚将我的新节点添加到了我在FXML文件中定义的内容窗格中。之后,这应该很容易工作,您不必定义诸如Static Controllers之类的东西。如果您听不懂,我会尝试给您一个完整的例子:)
答案 1 :(得分:0)
如果使用FXMLLoader
加载fxml并通过控制器修改生成的场景,则这对通过另一个FXMLLoader.load
调用基于同一fxml创建的任何场景均无效。
您的代码假设是这种情况:
致电loader.load();
后,有:
InteractionTest
实例;其中只有一个用作控制器InfoTable.fxml
创建的<fx:include source="InfoTable.fxml" />
的1个版本以及用于场景一部分的InfoTableController
的一个实例。稍后,在showMainStage
方法中,您将使用InfoTableController
创建该场景的另一个版本以及另一个tableLoader.load()
实例。您永远不会显示此场景,但这是您为其初始化表的唯一场景。对于fxml的第一个版本,您永远不需要进行初始化。
您的监听器中有一个与表中所选项目类似的问题。
我不建议使用Application
类作为控制器。而是创建一个单独的控制器类,并使用它来将数据传递到嵌套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.MainController"
xmlns:fx="http://javafx.com/fxml">
<center>
<SplitPane dividerPositions="0.5" orientation="HORIZONTAL"
focusTraversable="true">
<items>
<fx:include fx:id="table" source="InfoTable.fxml" />
<fx:include fx:id="display" source="InfoDisplay.fxml" />
</items>
</SplitPane>
</center>
</BorderPane>
public class MainController {
// fields for injection of nested controllers
@FXML
private InfoDisplayController displayController;
@FXML
private InfoTableController tableController;
@FXML
private void initialize() {
// connect selected table item with displayed document
tableController.selectedItemProperty().addListener((o, oldValue, newValue) -> {
final String id = newValue.getId();
displayController.displayDocument(id);
});
}
public void updateTable(final List<Info> infoList) {
tableController.updateTable(infoList);
}
}
public class InfoTableController {
...
@FXML
public void initialize() {
...
// 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);
// });
...
}
public ObjectProperty<Info> selectedItemProperty() {
return table.getSelectionModel().selectedItemProperty();
}
}
private void showMainStage() throws IOException {
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 loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/fxml/Main.fxml"));
final Parent root = loader.load();
((MainController)loader.getController()).updateTable(infoList);
...
// final FXMLLoader tableLoader = new FXMLLoader(getClass().getResource("/fxml/InfoTable.fxml"));
...
}