我有两个窗口和两个控制器。
在第一个窗口中是一个按钮,用于打开第二个窗口和TableView。第二个窗口是一种形式,我可以在其中插入类的属性。插入后,我单击“保存”,然后将新创建的对象添加到静态列表中。这应该显示在TableView中。当我仅使用一个窗口和一个控制器时,一切工作正常,但如两个窗口中所述拆分功能,则不会刷新TableView。
这是我的最小示例:
主控制器
public class Controller {
@FXML
public TableView tableView;
@FXML
private Button openWindow;
// called by the FXML loader after the labels declared above are injected:
public void initialize() {
TableColumn mailColumn = new TableColumn("E-Mail");
tableView.getColumns().addAll(mailColumn);
mailColumn.setCellValueFactory(new PropertyValueFactory<Person,String>("mail"));
openWindow.setOnAction((event) -> {
new PersonInputForm(event);
});
}
// ###### Receiver TableView Action Handling #######
public void updateReceiverList(){
final ObservableList<Person> data = FXCollections.observableArrayList(Memory.receiverList);
tableView.getItems().clear();
tableView.getItems().addAll(data);
}
}
辅助控制器
public class PersonInputFormController {
@FXML
private TextField mail;
@FXML
private AnchorPane personInputFormAnchorPane;
private Controller mainController ;
Stage stage;
public void setStage() {
stage = (Stage) personInputFormAnchorPane.getScene().getWindow();
}
public void setMainController(Controller mainController){
this.mainController = mainController;
}
public void save(){
Memory.saveReceiver(mail);
mainController.updateReceiverList();
stage.close();
}
}
主窗口
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception{
FXMLLoader loader = new FXMLLoader(getClass().getResource("sample.fxml"));
Parent root = loader.load();
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
次要窗口
public class PersonInputForm {
public PersonInputForm(ActionEvent event) {
Stage stage = new Stage();
FXMLLoader mainFxmlLoader = new FXMLLoader(getClass().getResource("../sample.fxml"));
try {
mainFxmlLoader.load();
} catch (IOException e) {
e.printStackTrace();
}
Controller mainController = mainFxmlLoader.getController();
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("PersonInputForm.fxml"));
Parent root = null;
try {
root = (Parent)fxmlLoader.load();
} catch (IOException e) {
e.printStackTrace();
}
stage.setScene(new Scene(root));
stage.initOwner(
((Node) (event.getSource())).getScene().getWindow() );
PersonInputFormController controller = fxmlLoader.<PersonInputFormController>getController();
controller.setStage();
controller.setMainController(mainController);
stage.show();
}
}
记忆力
public class Memory {
public static sample.Person sender = new sample.Person();
public static ArrayList<sample.Person> receiverList = new ArrayList();
static public void saveReceiver(TextField mail){
Person receiver = new Person();
receiver.setMail(mail.getText());
receiverList.add(receiver);
}
}
对象
public class Person {
private SimpleStringProperty mail = new SimpleStringProperty();
public String getMail() {
return mail.get();
}
public SimpleStringProperty mailProperty() {
return mail;
}
public void setMail(String mail) {
this.mail.set(mail);
}
}
我发现了以下类似的主题:
How to set items of a TableView in a different controller class in JavaFX?
Javafx Update a tableview from another FXML
但是,我仍然不知道如何解决我的问题。
谢谢!
答案 0 :(得分:0)
在您的PersonInputForm
类的构造函数中,创建一个FXMLLoader
来加载sample.fxml
。然后,将此负载(一个Controller
实例)所产生的控制器提供给以后生成的PersonInputFormController
实例。与此有关的问题是,调用Controller
的{{1}}实例与您赋予new PersonInputForm(event)
的不是同一实例。请记住,每次调用PersonInputFormController
时,都会创建一个连接到 new 控制器实例的 new 场景图。
当您从FXMLLoader.load
的一个实例中调用new PersonInputForm(event)
时,您需要在Controller
的这个实例上调用Controller
,最简单的解决方法是通过也从updateReceiverList()
到this
。然后删除负责加载PersonInputForm
的代码。
sample.fxml
注意:在构造函数中具有所有这些行为是错误的。
尽管以上所述可以解决您的问题(我相信),但必须清除并替换public PersonInputForm(ActionEvent event, Controller mainController) {
// code...
controller.setMainController(mainController);
}
的项目并不是理想的方法。看看TableView
:
updateReceiverList()
该代码将一个收藏复制到另一个收藏两次。当您具有大量元素时,这可能会变得非常昂贵。如果您有一个不同的控制器可以观察并做出反应的可观察模型,那就更好了。
例如,您正在使用public void updateReceiverList(){
// Copies Memory.receiverList into new ObservableList
final ObservableList<Person> data = FXCollections.observableArrayList(Memory.receiverList);
tableView.getItems().clear();
// Copies data into the TableView's items list
tableView.getItems().addAll(data);
}
存储/共享ArrayList
,而您可能会使用Person
。然后,您可以使用ObservableList
,tableView.setItems(Memory.receiverList)
会自动看到PersonInputFormController
对receiverList
所做的任何更新。由于您似乎没有使用多线程,因此此设置不会造成任何问题。当或开始使用后台线程时,请记住,绝对不要从后台线程直接或间接更新UI。
但是,使用全局状态(即公共静态变量)也不理想。我建议阅读不同的应用程序体系结构,例如:Model-View-Controller(MVC),Model-View-Presenter(MVP),Model-View-ViewModel(MVVP)等。然后尝试将其中一种应用于您的应用程序作为适当的。
一些链接:
我想指出关于您的代码的另一件事。您正在使用很多原始类型。 Don't use raw types。例如,您应该具有:
TableView
并且:
@FXML private TableView<Person> tableView;
并且:
TableColumn<Person, String> mailColumn = new TableColumn<>("E-Mail");
// which lets you use the diamond operator here
mailColumn.setCellValueFactory(new PropertyValueFactory<>("mail"));