0

I'm trying to add background Colors in my Listview via ListCell.

My ListView is working, but I got a problem with the ListCell. It is somehow overwriting the Colors after every ListView item. My current outcome is, that only the last item of my ListView gets the background Color grey (since its Priority is "Neutral"). My suggestion is, that every ListCell overwrites the one before, so that the Colors set before are update to "null" because the priority of the current item is a different one. Does anyone have an idea please?

Edit: I tried Fabians suggestion. I m able to create Notes, but somehow the names of the notes are still the Notepad ID's (i.e. "Notepad@"HexCode""). Also, the Colors are not working. This is the complete methode I'm implementing:

    public void initialize() throws SQLException {
    //initializing listView
    notesListView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
    //initializing listView items depending on instance + depending on User
    if (this.objectType instanceof Student) {
        ObservableList<Notepad> list = FXCollections.observableArrayList();
        for(StudentNotepad s : db.getStudentNotepadDao()) {
            if(db.getLoggedInUser() == s.getNotepad().getUser()) {
                list.add(s.getNotepad());
            }
        }
        notesListView.setItems(list);
            notesListView.getItems().clear(); // this is not necessary, if the list is guaranteed to be empty
            db.getStudentNotepadDao().queryForAll().stream()
                    .map(StudentNotepad::getNotepad)
                    .filter(n -> n.getUser().equals(db.getLoggedInUser()))
                    .forEach(notesListView.getItems()::add);
            notesListView.setCellFactory(new Callback<ListView<Notepad>, ListCell<Notepad>>() {
                public ListCell<Notepad> call(ListView<Notepad> param) {
                    return new ListCell<Notepad>() {
                        @Override
                        protected void updateItem(Notepad item, boolean empty) {
                            super.updateItem(item, empty);

                            String style = "";
                            if (!empty && item != null) {
                                setText(item.getNotepadName());

                                // this switch could be rewritten using a Map<String, String>
                                switch (item.getNotepadPriority()) {
                                    case "Hoch":
                                        style = "-fx-background-color: red";
                                        break;
                                    case "Mittel":
                                        style = "-fx-background-color: yellow";
                                        break;
                                    case "Niedrig":
                                        style = "-fx-background-color: green";
                                        break;
                                    case "Neutral":
                                        style = "-fx-background-color: grey";
                                        break;
                                }
                            } else {
                                setText("");
                            }
                            setStyle(style);
                        }

                    };
                }
            });
        }

}

Coon
  • 87
  • 7

2 Answers2

0

There are quite a few problems with your code.

  1. You can declare studentNotes as an ObservableList and use it directly without the redundant temporary list (Unless you really want to use it an ArrayList for some reason, which I don't think you do).

  2. You should call notesListView.setItems and notesListView.setCellFactory after the loop, not inside it. Then inside your updateItem method you need to do a search to get the StudentNotepad object that corresponds with the item being passed to it.

  3. It would simplify things a lot more if you declared your notesListView as ListView<Notepad> (I assume that's the class you're using for your note pad objects) so that updateItem gives you the Notepad object directly, then you can use call setText and pass the property that you want to show. If you're unsure how to do it you can look at This SO thread

Gnas
  • 698
  • 1
  • 6
  • 14
0

The ListCells are all created by the same factory. Replacing the factory multiple times results in the last factory creating the cells, not in cells being created by the factory set during the iteration corresponding to the item.

n.getNotepad().getNotepadName().equals(item)

only yields true for a single item for this reason.

Use a ListView<Notepad> here (I'll assume StudentNotepad.getNotepad returns an object of type Nodepad).

The following code also assumes db.getStudentNotepadDao().queryForAll() returns a Collection. If it returns an array, use Stream.of with the array as parameter instead of using the stream() method.

notesListView.getItems().clear(); // this is not necessary, if the list is guaranteed to be empty
db.getStudentNotepadDao().queryForAll().stream()
                                       .map(StudentNotepad::getNotepad)
                                       .filter(n -> n.getUser().equals(db.getLoggedInUser()))
                                       .forEach(notesListView.getItems()::add);

notesListView.setCellFactory(new Callback<ListView<Notepad>, ListCell<Notepad>>() {
    public ListCell<Notepad> call(ListView<Notepad> param) {
        return new ListCell<Notepad>() {
            @Override
            protected void updateItem(Notepad item, boolean empty) {
                super.updateItem(item, empty);

                String style = "";
                if (!empty && item != null) {
                     setText(item.getNotepadName());

                     // this switch could be rewritten using a Map<String, String>
                     switch (item.getNotepadPriority()) {
                         case "Hoch":
                             style = "-fx-background-color: red";
                             break;
                         case "Mittel":
                             style = "-fx-background-color: yellow";
                             break;
                         case "Niedrig":
                             style = "-fx-background-color: green";
                             break;
                         case "Neutral":
                             style = "-fx-background-color: grey";
                             break;
                     }
                } else {
                    setText("");
                }
                setStyle(style);
            }

        };
    }
});
fabian
  • 80,457
  • 12
  • 86
  • 114
  • Hi Fabian, thank you so much for your response! The Problem with ListView is, that after doing so, the ListView is showing the Notepads address ID which looks something like "Notepad@"some hex address" " That's why I used a ListView i.e. the names of the Notepads. – Coon Dec 02 '18 at 14:09
  • @KaanErdogan The results of the approach in my answer should show the contents of the `studentNotes` list at the end of your loop: The `Stream` is mapped to `Stream` using `.map(StudentNotepad::getNotepad)`. The rest of the operations do not change the type. This results in the cells receiving objects that would be converted to string in your code using `getNotepadName()`, so doing the same to get the new value for the `ListCell.text` property (`setText(item.getNotepadName());`) should result in the same text being displayed. – fabian Dec 02 '18 at 14:27
  • Yeah I just realised that in your sample. Thank you so much, I wasted hours and hours in trying to figure out how to deal with that problem. – Coon Dec 02 '18 at 14:41
  • Hi Fabian, I just tried your suggestion but couldn't implement it I think. I edited my previous question, could you give me feedback please? – Coon Dec 02 '18 at 15:24
  • It's probably a bad idea to compare users using `==` instead of `equals()`. Furthermore I recommend adding the items only once. You should be able to remove the loop or the stream+clear calls, since they both effectively do the same. The important part would be adding the structure of the `Notepad` class though and checking, if the values are initialized the way you think they are, e.g. by using a debugger or adding some print statements. – fabian Dec 02 '18 at 16:08