【发布时间】:2015-08-19 15:26:12
【问题描述】:
我有一个应用程序(就这个问题而言)有 3 个组件。
- 包含 TableView 的主视图(带有控制器)
- 此视图的表项 (TableMessage) 的模型
- 线程侦听器侦听要添加到表中的消息
当项目添加到连接的 ObservableList 时,我遇到了 TableView 不更新的问题。如果我在控制器的 initialize 方法中添加示例数据,则数据显示正常。但是,当我从程序的其他地方(本例中的侦听器)调用相同的方法来添加时,TableView 不会更新。在调试时,我可以看到数据被添加到连接列表中(并且样本数据在那里,所以我知道它是正确的对象)。
控制器:
@FXML
private TableView<TableMessage> messageTable;
@FXML
private TableColumn<TableMessage, String> messageIDColumn;
@FXML
private TableColumn<TableMessage, String> timestampColumn;
@FXML
private TableColumn<TableMessage, String> reportTypeColumn;
@FXML
private TableColumn<TableMessage, String> tNumberColumn;
private ObservableList<TableMessage> tableContent = FXCollections.observableArrayList();
@FXML
public void initialize() {
linkColumns();
// this works
addRow(new TableMessage("001", "today", "1", "10"));
}
private void linkColumns() {
messageIDColumn.setCellValueFactory(new PropertyValueFactory<TableMessage, String>("messageID"));
timestampColumn.setCellValueFactory(new PropertyValueFactory<TableMessage, String>("timestamp"));
reportTypeColumn.setCellValueFactory(new PropertyValueFactory<TableMessage, String>("reportType"));
tNumberColumn.setCellValueFactory(new PropertyValueFactory<TableMessage, String>("tNumber"));
messageTable.setItems(tableContent);
}
public void addRow(TableMessage row) {
tableContent.add(row);
}
型号:
public class TableMessage{
private SimpleStringProperty messageID = new SimpleStringProperty ("");
private SimpleStringProperty timestamp = new SimpleStringProperty ("");
private SimpleStringProperty reportType = new SimpleStringProperty ("");
private SimpleStringProperty tNumber = new SimpleStringProperty ("");
// all my constructors, getters, setters below
...
}
听众:
// same sample code as before, doesn't work here (reference to myController is set separately)
myController.addRow(new TableMessage("001", "today", "1", "10"));
我不明白为什么 TableView 在初始化后停止观看。如前所述,我确认正在更新正确的 tableContent 引用。
谢谢
编辑 1:
根据下面的问题,我上面的视图的父级(我们称之为 MainController)通过以下方式获取对上述控制器的引用:
FXMLLoader loader = new FXMLLoader(getClass().getResource("MessageView.fxml"));
loader.load();
messageViewController= (MessageViewController) loader.getController();
然后将SpringContext(用于侦听器)向下传递到messageViewController,这会从SpringContext 创建侦听器。
然后给听众参考我的messageViewController我打电话
myListener.setReferenceToController(this);
看起来像这样
public void setReferenceToController(MessageController ref) {
this.messageController = ref;
}
作为一个侧面的想法,如果在对控制器的错误引用中出现错误,为什么我在跟踪时会在可观察列表中看到示例数据(回想一下它是在 initialize 中调用的)听者的来电?
【问题讨论】:
-
1.你能展示你是如何将控制器的引用放入 Listener 类的吗?您确定它与加载 FXML 时为您创建的控制器实例相同吗? 2.你在FX应用线程上调用
addRow(...)吗? -
幽默我。 (您发布的代码没有任何问题,因此错误在其他地方。获得正确的引用是最明显的候选者。)将
System.out.println("In initialize: "+this);放入控制器的initialize()方法中,将System.out.println("In Listener: "+myController);放入@ 987654338@(就在您显示的代码行之前);验证变量的输出是否相同。 -
以上更新。此外,幽默被授予。
Initialize在应用程序启动时被调用两次(因此创建了两个控制器)。侦听器引用的控制器是创建的第二个控制器。我愿意打赌这就是我的问题所在。我在调试时看到 ArrayList 中的示例数据的原因是它仍然被初始化调用,但它不是活动视图。 -
在您的编辑中,您调用
loader.load(),但您放弃了结果。其结果是包含TableView的 UI 节点。由于您使用的控制器连接到未显示的TableView,因此当您修改TableView时看不到任何结果也就不足为奇了。相反,由于您清楚地看到了TableView,因此您必须在其他地方使用相同的 FXML 调用load(...)并显示结果。您需要对由 that 调用创建的控制器的引用load()(而不是对它的其他任意调用)。 -
默认情况下,它总是生成一个新的控制器。有一些可能的解决方法:我真的没有足够的信息来知道哪种方法适合您的情况。最好的选择可能是您可以将
fx:included FXML 文件的控制器注入到“包含”FXML 文件的控制器中。将fx:id添加到fx:include,然后在注入时将"Controller"附加到该ID。见here。