我有一个JavaFX
应用程序,它使用Spring Framework
进行依赖注入。一切都很好。
唯一的问题是当我使用ApplicationEventPublisher
发布其他控制器要监听的事件时。
在添加新客户时,将捕获客户详细信息的模式发布者AddCustomerEvent
,其中CustomersController
侦听事件并获取新添加的客户并将其添加到可用的客户列表中。
EventListener
方法获取事件,从而获得新客户,但未添加到客户列表中。此外,当我硬编码'要添加到绑定到tableView的客户列表的新Customer
,Customer
不会显示在tableView中。
出版商:
以下是发布者控制器。它发布一个事件,其中包含要订阅的其他控制器的新Customer
。
@Component
@Scope("prototype")
public class AddUpdateCustomerController implements Initializable {
@FXML
private Button btnSave;
@FXML
private Button btnCancel;
@FXML
private TextField txtFirstName;
@FXML
private TextField txtSecondName;
@FXML
private TextField txtPhone;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@Override
public void initialize(URL url, ResourceBundle rb) {
btnSave.setOnAction(this::handleSaveCustomer);
}
private void handleSaveCustomer(ActionEvent event){
String firstName = txtFirstName.getText();
String secondName = txtSecondName.getText();
String phone = txtPhone.getText();
Customer c = new Customer(1, firstName, secondName, phone);
AddCustomerEvent addCustomerEvent = new AddCustomerEvent(c);
applicationEventPublisher.publishEvent(addCustomerEvent);
}
}
订户:
此bean会听取发布者(AddUpdateCustomerController
类)在方法addCustomerEventListener(AddCustomerEvent addCustomerEvent)
@Component
@Scope("prototype")
public class CustomersController implements Initializable {
@FXML
private TableView<Customer> tblCustomers;
@FXML
private TableColumn<Customer, String> clmFirstName;
@FXML
private TableColumn<Customer, String> clmSecondName;
@FXML
private TableColumn<Customer, String> clmPhone;
@FXML
private Button addCustomer;
private final ObservableList<Customer> customerList = FXCollections.observableArrayList();
private final ListProperty<Customer> customerListProperty = new SimpleListProperty<>();
@Autowired
protected AnnotationConfigApplicationContext applicationContext;
@Autowired
protected Stage primaryStage;
/**
* Initializes the controller class.
*/
@Override
public void initialize(URL url, ResourceBundle rb) {
clmFirstName.setCellValueFactory(new PropertyValueFactory("firstName"));
clmSecondName.setCellValueFactory(new PropertyValueFactory("secondName"));
clmPhone.setCellValueFactory(new PropertyValueFactory("phone"));
customerListProperty.set(customerList);
tblCustomers.itemsProperty().bind(customerListProperty);
addCustomer.setOnAction(this::addCustomerActionEvent);
customerList.add(new Customer(1, "Name 1", "Second 1", "001"));
customerList.add(new Customer(2, "Name 2", "Second 2", "002"));
customerList.add(new Customer(1, "Name 3", "Second 3", "003"));
customerList.add(new Customer(1, "Name 4", "Second 4", "004"));
}
private void addCustomerActionEvent(ActionEvent event){
try {
Parent loader
= SpringFXMLLoader.create()
.applicationContext(applicationContext)
.location(getClass().getResource("/fxml/addUpdateCustomer.fxml"))
.load();
Stage addUpdateCustomerModal = new Stage();
addUpdateCustomerModal.initOwner(primaryStage);
addUpdateCustomerModal.centerOnScreen();
addUpdateCustomerModal.setScene(new Scene(loader));
addUpdateCustomerModal.show();
} catch (IOException ex) {
Logger.getLogger(CustomersController.class.getName()).log(Level.SEVERE, null, ex);
}
}
@EventListener
public void addCustomerEventListener(AddCustomerEvent addCustomerEvent){
System.out.println("Heey");
customerList.add(addCustomerEvent.getCustomer());
customerList.add(new Customer(1, "Name 5", "Second 5", "005"));
}
}
我还创建了一个小型的javafx应用来重现this github repo
中描述的问题Add Customer
按钮。first name
,second name
和phone
。Save
按钮。您会注意到刚添加的成员不在表格视图中
答案 0 :(得分:1)
主要问题是我们使用控制器的不同实例,因为这是scope="prototype"
。我们需要两件不同的东西:
解决方案是创建一个正在侦听队列并存储客户列表的Singleton。然后通过@autowire在控制器中包含这个单例。
当然在这种情况下,总是不需要总线:你可以在AddCustomerController中添加这个单例,然后直接添加列表中的元素。
以下是单身人士的解决方案:
@Component
public class CustomersSingleton {
private final ObservableList<Customer> customerList = FXCollections.observableArrayList();
@EventListener
public void addCustomerEventListener(AddCustomerEvent addCustomerEvent){
System.out.println("Heey");
customerList.add(addCustomerEvent.getCustomer());
customerList.add(new Customer(1, "Name 5", "Second 5", "005"));
}
public ObservableList<Customer> getCustomerList() {
return customerList;
}
}
然后修改你的控制器
// remove attributes customerList and customerListProperty then modify method:
/**
* Initializes the controller class.
*/
@SuppressWarnings ({ "rawtypes", "unchecked" })
@Override
public void initialize(URL url, ResourceBundle rb) {
clmFirstName.setCellValueFactory(new PropertyValueFactory("firstName"));
clmSecondName.setCellValueFactory(new PropertyValueFactory("secondName"));
clmPhone.setCellValueFactory(new PropertyValueFactory("phone"));
ObservableList<Customer> customerList = customersSingleton.getCustomerList();
tblCustomers.setItems(customerList);
addCustomer.setOnAction(this::addCustomerActionEvent);
customerList.add(new Customer(1, "Name 1", "Second 1", "001"));
customerList.add(new Customer(2, "Name 2", "Second 2", "002"));
customerList.add(new Customer(1, "Name 3", "Second 3", "003"));
customerList.add(new Customer(1, "Name 4", "Second 4", "004"));
}
附注:使其工作的简单但真正令人沮丧的解决方案只是删除@Scope("prototype")
注释,但是你不能将单例作为控制器,因为屏幕有很多实例,每个屏幕都需要它的控制器
@Component
//@Scope("prototype")
public class CustomersController implements Initializable {
评论不要使用它!