You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 14:44:59