JavaFX中ObservableList有新数据但ListView不更新的问题
JavaFX ListView 不更新问题
以下代码中,名为tourList的ListView无法更新,尽管tourNameList这个ObservableList已经包含新数据。程序启动时能正常显示数据库初始条目,但添加新条目后界面毫无变化,求解决。
public class TourListView implements TourListObserver { public TourListViewModel tourListViewModel = new TourListViewModel(); public TourFormViewModel tourFormViewModel = new TourFormViewModel(); public FormInputManager formInputManager = new FormInputManager(); Alert alert = new Alert(Alert.AlertType.ERROR); Alert successPrompt = new Alert(Alert.AlertType.INFORMATION); //Form Components @FXML public ScrollPane tourForm; @FXML public TextField formFrom; public ChoiceBox<String> formTransportType = new ChoiceBox<>(); public TextField formTo; @FXML public TextField formName; @FXML public TextField formDescription; @FXML public Button formSubmitButton; @FXML public ListView<String> tourList = new ListView<>(); public TextArea formRouteInformation; @Override public void onTourListUpdated() { Platform.runLater(this::updateTourList); //thread safe update } public void updateTourList() { //check if I am creating a second List System.out.println("UPDATE TOUR LIST: TourListView"); ObservableList<String> tourNameList = tourListViewModel.getTourNameList(); System.out.println("tourNameList: " + tourNameList.toString() ); //tourNameList has shows new Data this.tourList.setItems(tourNameList); //this doesn't show new data //this.tourList.getItems().setAll(tourNameList); //this.tourList.refresh(); } @FXML public void addTour(ActionEvent event) { System.out.println("Button clicked: addTour"); //validate Input FormTour formTour = new FormTour(formName.getText(), formDescription.getText(), formFrom.getText(), formTo.getText(), formTransportType.getValue(), formRouteInformation.getText()); String validationString = formInputManager.validateForm(formTour); if (Objects.equals(validationString, FormMessages.VALID_FORM.getMessage())) { //post them to DB System.out.print("VALID INPUT"); System.out.printf(validationString); tourFormViewModel.postTour(formTour); tourListViewModel.updateList(); successPrompt.setTitle("Tour has been added"); successPrompt.setContentText(FormMessages.FORM_ADDED.getMessage()); successPrompt.setHeaderText(""); successPrompt.showAndWait(); } else { //show error message alert.setTitle("INVALID INPUT"); alert.setContentText(validationString); alert.setHeaderText(""); alert.showAndWait(); System.out.printf(validationString); } } public void addTourFormShow(ActionEvent event) { //make TourList invisible if (tourList.isVisible()) { tourList.setVisible(false); tourForm.setVisible(true); } else { tourList.setVisible(true); tourForm.setVisible(false); } System.out.println("Button clicked: startForm"); } @javafx.fxml.FXML public void initialize() { tourListViewModel.registerObserver(this); //init List ObservableList<String> tourNameListList = FXCollections.observableArrayList(); tourNameListList = tourListViewModel.getTourNameList(); this.tourList.setItems(tourNameListList); //init ChoiceBox String[] choiceBoxChoices = {"public transit", "car", "bike", "foot"}; formTransportType.getItems().addAll(choiceBoxChoices); } }
我尝试过以下代码,但仍然无效:
this.tourList.getItems().setAll(tourNameList); this.tourList.refresh();
FXML文件:
<SplitPane dividerPositions="0.10738255033557047" orientation="VERTICAL" prefHeight="300.0" prefWidth="174.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0" fx:controller="at.fhtw.app.view.TourListView" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1"> <items> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="49.0" prefWidth="172.0" SplitPane.resizableWithParent="false"> <children> <Label layoutY="5.0" text="Tours"/> <Button fx:id="addButton" onAction="#addTourFormShow" layoutX="94.0" layoutY="1.0" mnemonicParsing="false" text="+" AnchorPane.rightAnchor="51.0" AnchorPane.topAnchor="0.0"/> <Button layoutX="121.0" layoutY="1.0" mnemonicParsing="false" text="-" AnchorPane.rightAnchor="27.0" AnchorPane.topAnchor="0.0"/> <Button layoutX="145.0" layoutY="1.0" mnemonicParsing="false" text="..." AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"/> </children> </AnchorPane> <AnchorPane minHeight="0.0" minWidth="0.0" prefHeight="100.0" prefWidth="160.0"> <children> <fx:include fx:id="tourForm" source="Tour-Form.fxml" visible="false"/> <ListView fx:id="tourList" prefHeight="262.0" prefWidth="172.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0"/> </children> </AnchorPane> </items> </SplitPane>
问题原因及解决步骤
1. 核心问题:FXML控件注入被覆盖
控制器中@FXML public ListView<String> tourList = new ListView<>();这行代码存在错误:手动实例化了一个ListView对象,覆盖了FXML加载时注入的界面控件。后续所有对tourList的操作都是针对这个内存中的新对象,而非界面上显示的ListView,因此界面不会更新。
修复方法:
将该行代码修改为:
@FXML public ListView<String> tourList;
去掉手动实例化的= new ListView<>(),让FXML正确注入界面上的ListView控件。
2. 优化列表更新逻辑(推荐)
如果TourListViewModel的updateList()方法每次都创建新的ObservableList实例,即使修复了注入问题,每次调用setItems()虽然能更新,但更优雅的方式是复用同一个列表实例,让ListView自动监听内容变化:
在TourListViewModel中维护单一的ObservableList:
private ObservableList<String> tourNameList = FXCollections.observableArrayList(); public ObservableList<String> getTourNameList() { return tourNameList; } public void updateList() { // 从数据库获取最新数据 List<String> newTourNames = /* 数据库查询逻辑 */; // 更新现有列表内容,而非创建新列表 tourNameList.clear(); tourNameList.addAll(newTourNames); // 通知观察者 notifyObservers(); }
这样ListView绑定后,列表内容变化时会自动触发界面更新,无需反复调用setItems()或refresh()。
内容的提问来源于stack exchange,提问作者Isi
相关产品推荐
相关产品推荐

