-2

ListView doesn't update JavaFx

In the Code below, the ListView called tourList doesn't get updated eventhough the Observable List tourNameList has the updated data. When I start the program, the initial list is shown with the DB-entries, but when I add a new entry, no update is made. Can someone help...

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);
    }
}

I tried

this.tourList.getItems().setAll(tourNameList);
this.tourList.refresh();

but it also didn't work

As requested the FXML file:

<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>
Isi
  • 1
  • 3
  • 1
    Don't set `@FXML` fields to a new values. I did have a duplicate answer on that, but the question got deleted by StackOverflow bot and that removed the answer too :-(. Maybe there is another duplicate somewhere with more detail (I just don't know). – jewelsea May 30 '23 at 19:17
  • 2
    Post a [mre] (at the very least include the associated FXML file). – James_D May 30 '23 at 19:53
  • Nothing is wrong in the FXML (that I can see). Create and post a [mre] that demonstrates the issue. – James_D May 31 '23 at 12:53

2 Answers2

3

This is wrong:

@FXML
public ListView<String> tourList = new ListView<>();

You should never set an @FXML injected field to a new value.

The fxml loader will already have created an instance of the @FXML field and linked that into the object tree returned by the loader.

If you assign the field to a new value, the new value will not be in the loaded object tree added to the scene graph, so it will never be seen. Only the empty ListView created by the loader will be seen.

jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • Note, however, that this cannot be the only error. (If it were, `tourList` would *first* be set to the `ListView` instance constructed in code, and *then subsequently* would be set to the instance created when the FXML was parsed, and it would work, despite being incorrect.) So removing the explicit instantiation will cause a null pointer exception, the actual cause of which needs to be fixed. – James_D May 30 '23 at 19:52
  • (To be clear; everything stated in this answer is true. It's just not the whole story, and there's not enough information in the question to know the whole story.) – James_D May 30 '23 at 20:02
  • 3
    Yeah, it is usually the case with these kinds of questions that the errors are multiple. I just picked the first and most obvious issue that I saw and provided an answer to address that because the prior answer I could refer to no longer exists. – jewelsea May 30 '23 at 22:28
  • I am thankful for your engagement, because I am new to JavaFX and appreciate any help I can get. However, as James_D already mentioned, removing the instatiation, does not resolve my actual problem and causes a nullpointer exception... – Isi May 31 '23 at 08:20
  • 1
    as @James_D also mentioned: [mcve] required .. make sure to read that help pageeand act accordingly – kleopatra May 31 '23 at 08:28
  • anyway, manually setting an injected field is __wrong__ always! remove those and find the exact reason for them not being properly injected - that's where the [mcve] you will be writing will help you to nail the error – kleopatra May 31 '23 at 08:35
  • 1
    basically, this question as-is is not answerable - the exact reason for the null field is not in the snippets shown - so IMO we should not even try to .. it might well have the same fate as as the previous duplicate target https://stackoverflow.com/a/70716514/1155209 and eventually be deleted (if not by direct voting then later by bot ;) - then we'll again loose a useful answer .. – kleopatra May 31 '23 at 08:50
  • @kleopatra thank you for your passionate engagement. The solution was fairly simple, I used 1 controller for 2 fxml elements, so the problem is answerable. – Isi Jun 03 '23 at 11:45
  • @Isi actually, in re-reading your question and your answer, I agree with kleopatra that the question is not answerable, at least I can't understand your answer nor why it is correct. Perhaps understanding the answer requires some context that I am missing (e.g. the requested [mcve]). But you seem to have solved your problem, which is good. I don't think the question and solution will be useful to others, so I'll vote to close it. – jewelsea Jun 03 '23 at 19:00
-2

I solved the issue: I used one View for two fxml components(ListView for tourForm and tourList, meaning that I had 2 different ListViews.

Isi
  • 1
  • 3
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jun 03 '23 at 01:38