This discussion is archived
6 Replies Latest reply: Dec 13, 2012 11:38 AM by 979037 RSS

Force TreeView cell refresh

979037 Newbie
Currently Being Moderated
I have a TreeView filled with an `ObservableList` of Local objects. When one of the Locals is selected in the TreeView, a TextField allow the user to edit the name of the Local. When the name attribute is changed I want to refresh the TreeView with the new value but I can't find out how!
I already read some solutions to bind a String from an Object to a Label/TextField (through `SimpleStringProperty`), but my problem is more complex, I want to bind an attribute from an object contained on a list to an element/cell of a TreeView.

I give you my source code so you can see my problem.


Local.java
    public class Local {
                
        private int         id;
        private String      name;
            
        public Local() {
            this.id             = -1;
            this.name           = "";
        }
                
        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id= id;
        }

        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
LocalController.java
    ...

    @FXML TreeView locals_tree_view;
    @FXML TextField name;

    ...

    // POPULATE TREE VIEW
    List<Local>           locals           = Database.getLocals();
    TreeItem<Family> rootNode     = new TreeItem<>(new Local());
    buildFamilyTree(rootNode, locals);
    tree_families.setRoot(rootNode);
    local_tree_view.setCellFactory(new Callback() {
            @Override
            public Object call(Object p) {
                return new LocalTreeCell ();
            }
        });
    ...

    // HANDLE NAME CHANGE
    name.textProperty().addListener(new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> ov, String t, String newText) {
            TreeItem<Local> selectedItem = (TreeItem) local_tree_view.getSelectionModel().getSelectedItem();

            Local selectedLocal = selectedItem.getValue();
            selectedLocal .setName(newText);

            // ******** UPDATE TREE CELL SOMEHOW ********
        }
    });
...
LocalTreeCell
        private final class LocalTreeCell extends TreeCell<Local> {
    
            @Override
            protected void updateItem(Local local, boolean empty) {
                super.updateItem(local, empty);
    
                if(empty) {
                    setGraphic(null);
                    setText(null);
                    return;
                }
                setText(local.getName());
            }
        }
 
Edited by: 976034 on 11/Dez/2012 5:59
FIxed error in my code, TreeView doesn't define a setItems method.
  • 1. Re: Force TreeView cell refresh
    James_D Guru
    Currently Being Moderated
    I'm a bit confused by your data model; unless I'm missing something TreeView<T> doesn't define a setItems(ObservableList<T>) method. Your model should consist of a hierarchy of TreeItem<Local> objects.

    Assuming that works, though, I would do
        name.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> ov, String t, String newText) {
               TreeItem<Local> selectedItem = (TreeItem) local_tree_view.getSelectionModel().getSelectedItem();
               Local selectedLocal = selectedItem.getValue();
               Local updatedLocal = new Local();
               updatedLocal.setId(selectedLocal.getId());
               updatedLocal.setName(newText);
               selectedItem.setValue(updatedLocal);
               // now replace selectedLocal with updatedLocal in your data structure
            }
        });
    If you have control over the Local class, another option might be to define the properties of it as FXProperties instead of standard JavaBean properties. You could make your TreeView a simple TreeView<String> and bidirectionally bind the valueProperty of the TreeItem to the name property of the corresponding Local object. Then in your ChangeListener simply update the value of the selected TreeItem.
  • 2. Re: Force TreeView cell refresh
    979037 Newbie
    Currently Being Moderated
    You're right, sorry about the confusion, I already fix the error.
    Your tip works, but I don't know if its the best approach because I have to remove the previous item and then add the updated one. I'm doing that as follows:
    ...
    int     selectedIndex = local_tree_view.getRow(selectedItem);
    boolean result        = local_tree_view.getRoot().getChildren().remove(selectedItem);
    tree_families.getRoot().getChildren().add(selectedIndex, selectedItem);
    ...
    What about update the value that I want and then simply colapse and expand the item? It work too but I don't think thats an "engineering approach"... :)
    ...
    boolean expanded = selectedItem.expandedProperty().get();
    selectedItem.expandedProperty().set(!expanded);
    selectedItem.expandedProperty().set(expanded);
    ...
    Thanks!
  • 3. Re: Force TreeView cell refresh
    James_D Guru
    Currently Being Moderated
    976034 wrote:
    You're right, sorry about the confusion, I already fix the error.
    Your tip works, but I don't know if its the best approach because I have to remove the previous item and then add the updated one. I'm doing that as follows:
    ...
    int     selectedIndex = local_tree_view.getRow(selectedItem);
    boolean result        = local_tree_view.getRoot().getChildren().remove(selectedItem);
    tree_families.getRoot().getChildren().add(selectedIndex, selectedItem);
    ...
    What about update the value that I want and then simply colapse and expand the item? It work too but I don't think thats an "engineering approach"... :)
    ...
    boolean expanded = selectedItem.expandedProperty().get();
    selectedItem.expandedProperty().set(!expanded);
    selectedItem.expandedProperty().set(expanded);
    ...
    You don't need either of those.
    The TreeView observes its items for changes in their values, so
    selectedItem.setValue(updatedLocal);
    updates the tree.

    I was just concerned that you may need to update your external data structure (the one you retrieved from the database). In that case you need something like
    int index = locals.indexOf(selectedLocal);
    locals.set(index, updatedLocal);
    But you may not need this, depending on your application logic.
  • 4. Re: Force TreeView cell refresh
    979037 Newbie
    Currently Being Moderated
    Hi,
    your sugestion don't work, or i'm doing something wrong. As you said, setValue should trigger an update:
    selectedItem.setValue(updatedLocal);
    But in the tree the value stay the same. You can see my code that does not work
    TreeItem<Local> selectedItem = (TreeItem) local_tree_view.getSelectionModel().getSelectedItem();
    Local selectedLocal = selectedItem.getValue();
    selectedLocal.setName(newName);
    selectedItem.setValue(selectedFamily);
    I'm I doing something wrong? I know that the object is the same, but following what you say should be enough.

    Thanks
  • 5. Re: Force TreeView cell refresh
    James_D Guru
    Currently Being Moderated
    That won't work. I think this will:
    TreeItem<Local> selectedItem = (TreeItem) local_tree_view.getSelectionModel().getSelectedItem();
    Local selectedLocal = selectedItem.getValue();
    Local updatedLocal = new Local();
    updatedLocal.setId(selectedLocal.getId());
    updatedLocal.setName(newName);
    selectedItem.setValue(updatedLocal);
    Calling setValue(...) on the tree item is only going to have an effect if you pass in something that is different to the value it currently has. The TreeItem cannot detect changes in the state of the object it holds in its 'value' property, so when you call selectedLocal.setName(...) the TreeItem has no idea anything changes. When you call selectedItem.setValue(...) you're passing in an identical reference to the one it already holds, so it's not going to know that you've changed anything.
  • 6. Re: Force TreeView cell refresh
    979037 Newbie
    Currently Being Moderated
    Ok, problem solved. thank you

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points