Search code examples
javajavafxfxmlhbox

How to download fxml with custom cell in a ListView?


I want to make a custom cell in the ListView. Excuse my bad English! I want to display the picture, name and status in the ListView. For this I use a different Fxml that contains Hbox .

  public class Controller {    
   CollectionContactForListCollection contactForList = new   CollectionContactForListCollection();
@FXML
private ListView<Contact> listContact ;
@FXML
HBox hbox;
@FXML
ImageView avatar;
@FXML
Label labelName;
@FXML
Label lblStatus;
@FXML
Label lblSense;

@FXML
private void initialize(){ 
    contactForList.fieldData();
    // listContact.setItems((ObservableList)       contactForList.getContactList()); 
    listContact.setCellFactory(new Callback<ListView<Contact>, ListCell<Contact>>() {
        @Override
        public ListCell<Contact> call(ListView<Contact> param) {              
            ListCell<Contact> listCell = new ListCell<Contact>() {                    
                @Override
                protected void updateItem(Contact item, boolean empty) {
                    super.updateItem(item, empty);
                    if (empty || item == null) {
                        setText(null);
                        setGraphic(null);
                    } else {
                        //This method does not work download                          
                       FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/view/boxInContact.fxml"));
                       fxmlLoader.setController(this);                      
                        labelName.setText(item.getName());
                        lblSense.setText(item.getSense());
                        lblStatus.setText(item.getStatus());
                        avatar.setImage(item.getImage());                            
                    }
                }
            };
            return listCell;
        }
    });
    listContact.setItems((ObservableList) contactForList.getContactList());
}

Solution

  • As a general, rule, you should use a different controller class for each FXML file. With the code you have, all cells are using the same controller instance, so there is only one reference to each control, even though there are many labelNames, etc (one for each cell).

    So define a controller for the FXML defined for the list cell, and define the methods you need to update the controls:

    public class ContactCellController {
    
        @FXML
        private Label labelName ;
        @FXML
        private Label labelStatus ;
        @FXML
        private Label labelSense ;
        @FXML
        private ImageView avatar ;
    
        public void setName(String name) {
            labelName.setText(name);
        }
    
        public void setStatus(String status) {
            labelStatus.setText(status);
        }
    
        public void setSense(String sense) {
            labelSense.setText(sense);
        }
    
        public void setAvatarImage(Image image) {
            avatar.setImage(image);
        }
    }
    

    Update the FXML file to use a controller attribute with fx:controller="my.package.ContactCellController", and then your cell implementation can look like

    listContact.setCellFactory(lv -> new ListCell<Contact>() {
        private Node graphic ;
        private ContactCellController controller ;
    
        {
            try {
                FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/boxInContact.fxml"));
                graphic = loader.load();
                controller = loader.getController();
            } catch (IOException exc) {
                throw new RuntimeException(exc);
            }
        }
    
        @Override
        protected void updateItem(Contact contact, boolean empty) {
            super.updateItem(contact, empty);
            if (empty) {
                setGraphic(null);
            } else {
                controller.setName(contact.getName());
                controller.setStatus(contact.getStatus());
                controller.setSense(contact.getSense());
                controller.setAvatarImage(contact.getImage());
                setGraphic(graphic);
            }
        }
    });