Search code examples
javalistviewjavafx

Javafx: when deleting an item from a ListView almost all items disappear from the list, but reappear when refreshing the screen


If there's anything hard to understand I apologize, english is not my native language.

I'm trying to do a screen using JavaFX where there's a ListView, and in the list cell there's a button to delete the correspondent item, but when I delete the item all items but one disappears from the ListView, but only visually, they still continue in the list (if I refresh the list by changing the screen all items that should be in the list reappear).

This is the code for the delete button:

    @FXML
    public void deletePlan(ActionEvent event) {
        ButtonType all = new ButtonType("All revisions");
        ButtonType rev = new ButtonType("Revision 0" + model.getSelectedPlant()[0]);
        ButtonType cancel = new ButtonType("Back", ButtonBar.ButtonData.CANCEL_CLOSE);
        
        Alert confirm = new Alert(Alert.AlertType.CONFIRMATION, "Delete all plans from " + plan.getPlanName() + " or just Revision 0" + model.getSelectedPlant()[0] + "?",all, rev, cancel);
            
        confirm.setTitle("Delete plan");
        confirm.setHeaderText(null);
        
        Optional<ButtonType> result = confirm.showAndWait();
        
        if(!result.isPresent() || result.get() == ButtonType.CLOSE) {
            Alert inf = new Alert(Alert.AlertType.INFORMATION);
            
            inf.setTitle("Warning");
            inf.setHeaderText(null);
            inf.setContentText("Operation cancelled.");
            inf.show();
        } else if(result.get() == all) {
            project.deletePlan(plan.getPlanNumber());
        } else if(result.get() == rev) {
            plan.deleteRevision(model.getSelectedPlant()[0]);
        }
    }

It happens only when I use the "all" option, which executes "project.deletePlan(plan.getPlanNumber());". The option "rev" is working as it should. plan.getPlanNumber() just returns a int that I use to identify the document I want to remove from the list so I think is not necessary to put the code here.

Below is the list screenshot (the one marked with red), the first cell is how it looks when the cell is selected. Screenshot 01

The "Revisão 01" button is working normally, it executes the "rev" option from the Alert I've mentioned earlier, but when I press the button "Todos" which executes the "all" option is when the problem occurs. Screenshot 02

I've deleted the first item of the list, but all items except the second disappeared. But, when I close the "Plantas" pane and then reopen it the ListView shows all the items correctly. Screenshot 03 Screenshot 04

I've tried using list.refresh() after the delete, I've tried clearing the ListView and then repopulate it but nothing worked. I've used a print function to print all items of the list before and after the delete and everything was correct, this happens only visually.

Can someone help me with this? I don't know why this happens.

Edit: As requested by jewelsea I made a minimal reproducible example, but I thought there was too much archives so I put all it needed in a git repository i'll be linking below.

Repository


Solution

  • I found out what I was doing wrong, so I'm answering my own question.

    Like jewelsea said, I did a wrong implementation of the updateItem method in the cell factory.

    This is the wrong code:

    @Override
    public void updateItem(PlanInfo plan, boolean empty) {
        super.updateItem(plan, empty);
        
        if(empty || plan == null) {
            setText(null);
            setGraphic(null);
        } else {
            if(loader == null) {
                loader = new FXMLLoader(getClass().getResource("planListCell.fxml"));
                loader.setController(this);
                
                try {
                    loader.load();
                } catch(IOException io) {
                    Logger.getLogger(PlanListCell.class.getName()).log(Level.SEVERE, null, io);
                }
    
                this.plan = plan;
                
                planName.setText(plan.getPlanName());
                planNumber.setText("0" + String.valueOf(plan.getPlanNumber()));
                
                setText(null);
                setGraphic(planPane);
            }
        }
    }
    

    And this is the right code:

    @Override
    public void updateItem(PlanInfo plan, boolean empty) {
        super.updateItem(plan, empty);
        
        if(empty || plan == null) {
            setText(null);
            setGraphic(null);
        } else {
            if(loader == null) {
                loader = new FXMLLoader(getClass().getResource("planListCell.fxml"));
                loader.setController(this);
                
                try {
                    loader.load();
                } catch(IOException io) {
                    Logger.getLogger(PlanListCell.class.getName()).log(Level.SEVERE, null, io);
                }
            }
            
     /*-->*/this.plan = plan;
                
            planName.setText(plan.getPlanName());
            planNumber.setText("0" + String.valueOf(plan.getPlanNumber()));
                
            setText(null);
            setGraphic(planPane);/*<--*/
        }
    }
    

    That block of code that I pointed to with the arrows, I placed it incorrectly inside the if(loader==null){} block, which was causing the ListCell rendering to behave strangely.

    Thanks to everyone who tried to help me here.