1

In my app which uses javafx I have a tableview with a few rows. I want to change CSS style in one row which meets my own requirements. I tried :

personTable.setRowFactory(new Callback<TableView<Person>, TableRow<Person>>() {
            @Override
            public TableRow<Person> call(TableView<Person> personTableView) {
                return new TableRow<Person>() {
                    @Override
                    protected void updateItem(Person person, boolean b) {
                        super.updateItem(person, b);
                        if(.../*my requirements*/) {                     
                            getStyleClass().add("priorityLow");
                        }
                    }
                };
            }
        });

but it does not work. Can anyone help me ? :)

Prasanth S
  • 3,725
  • 9
  • 43
  • 75
karoluch
  • 653
  • 3
  • 9
  • 21
  • Can you show your css? You should see some changes, but you need a bit more logic: only add the style if it's not already there, and remove it if your condition is false. – James_D Apr 18 '14 at 11:41
  • That's not work because whene I scroll my tableview rows are mixed, and rows which don't meet requirements gets 'priorityLow; style... – karoluch Apr 18 '14 at 11:44
  • Possible duplicate of http://stackoverflow.com/questions/20350099/programmatically-change-the-tableview-row-appearance/ – James_D Apr 18 '14 at 11:45

2 Answers2

4

See Programmatically change the TableView row appearance for a fuller discussion of this topic.

Since cells are reused, you need to make sure you only add the style class once to each cell. (In your current code, if the item changes from one for which your condition is true to another for which your condition is true, the list of style classes will contain a duplicate "priorityLow" entry. Eventually, you could potentially run out of memory by replicating this enough.)

Additionally, you need to remove any occurrences of "priorityLow" if your condition is false. (In your current code, if the item changes from one for which your condition is true to one for which your condition is false, the "priorityLow" class will remain incorrectly attached.)

Something like this:

personTable.setRowFactory(new Callback<TableView<Person>, TableRow<Person>>() {
            @Override
            public TableRow<Person> call(TableView<Person> personTableView) {
                return new TableRow<Person>() {
                    @Override
                    protected void updateItem(Person person, boolean b) {
                        super.updateItem(person, b);
                        if(.../*my requirements*/) { 
                            ObservableList<String> styles = getStyleClass();
                            if (! styles.contains("priorityLow")) {                    
                                getStyleClass().add("priorityLow");
                            }
                        } else {
                            // Remove all occurrences of "priorityLow":
                            styles.removeAll(Collections.singleton("priorityLow"));
                        }
                    }
                };
            }
        });

If you are using JavaFX 8, a solution using PseudoClasses will be cleaner and more efficient:

Update PseudoClass version (Java 8 only):

final PseudoClass lowPriorityPseudoClass = PseudoClass.getPseudoClass("priority-low");
personTable.setRowFactory(new Callback<TableView<Person>, TableRow<Person>>() {
            @Override
            public TableRow<Person> call(TableView<Person> personTableView) {
                return new TableRow<Person>() {
                    @Override
                    protected void updateItem(Person person, boolean b) {
                        super.updateItem(person, b);
                        boolean lowPriority = /* my requirements */ ;
                        pseudoClassStateChanged(lowPriorityPseudoClass, lowPriority);
                    }
                };
            }
        });

and the css will look like:

.table-row-cell:priority-low {
 /* styles specific for low priority row */
}
Community
  • 1
  • 1
James_D
  • 201,275
  • 16
  • 291
  • 322
  • The part where you are explaining the PseudoClass is very helpful for me, thanks for that! When I implement it, I get a Nullpointer Exception on `boolean lowPriority = (person.getAmount() < 0)`. Any thoughts on why? Note: I have placed this code in the initialize of the screen where the Tableview is showed. – bashoogzaad Oct 29 '14 at 15:51
  • All cell factories (of which row factories are an example) will receive `null` items if the cell is empty (and possibly at other times), so you must always write code to handle that: `boolean lowPriority = person != null && person.getAmount() < 0;` – James_D Oct 29 '14 at 15:55
  • Ah should have known that! Still learning java and javafx, so thanks for your patience and help! It works like a charm now! – bashoogzaad Oct 29 '14 at 16:17
0

Don't run the validation if the item (person) is NULL.

This should work for you.

personTable.setRowFactory(new Callback<TableView<Person>, TableRow<Person>>() 
{
    @Override public TableRow<Person> call(TableView<Person> personTableView) 
    {
        return new TableRow<Person>() 
        {
            @Override protected void updateItem(Person person, boolean b) 
            {
                super.updateItem(person, b);

                if (person == null)
                    return;

                if(Priority.LOW.equals(person.getPriority())) // Example requirement
                {                     
                    getStyleClass().add("priorityLow");
                }
            }
        };
    }
});
Georgian
  • 8,795
  • 8
  • 46
  • 87