Search code examples
listviewjavafx-2highlightingjavafx-8

How to programmatically user define colors for a list view based on a string value in JavaFX


I need to have the ability to highlight a row in a list box if the text in the row match the text that the user specified aka the user says highlight all lines that contains the word “warning” or so… I asked around and came across this where Alex showed me how to use style sheets.

I implemented the solution above. But now I want to enhance it so that the user have the option to choose what the fore and back ground color should be for multiple string values (first one specified taking highest priority) I have played around with the CSS and added one more style and based on whether the text is found or not I remove and add the CSS Style sheets to give the effect as below:

highlighter.css

/** Highlighting for list-view search result cells */

.list-cell.search-highlight {
-fx-background-color: tomato;
-fx-accent: firebrick;
}

.list-cell:filled:hover.search-highlight {
-fx-background-color: derive(tomato, -20%);
}

.list-cell.search-highlight2 {
-fx-background-color: yellow;
-fx-accent: firebrick;
}

.list-cell:filled:hover.search-highlight2 {
-fx-background-color: derive(yellow, -20%);
}

java code to remove/add the css SearchHighlightedTextCell.java

public class SearchHighlightedTextCell extends ListCell<String> {

private static final String HIGHLIGHT_CLASS = "search-highlight";
private static final String HIGHLIGHT_CLASS2 = "search-highlight2";
private StringProperty searchText = new SimpleStringProperty("");
private StringProperty searchText2 =  new SimpleStringProperty("");

SearchHighlightedTextCell(StringProperty searchText, StringProperty searchText2) {
    this.searchText = searchText;
    this.searchText2 = searchText2;
}

@Override
protected void updateItem(String text, boolean empty) {
    super.updateItem(text, empty);

    setText(text == null ? "" : text);

    updateStyleClass();
    searchText.addListener(new InvalidationListener() {
        @Override
        public void invalidated(Observable observable) {
            updateStyleClass();
        }
    });

    searchText2.addListener(new InvalidationListener() {
        @Override
        public void invalidated(Observable observable) {
            updateStyleClass();
        }
    });
}

private void updateStyleClass() {
    try {
        if (!isEmptyString(searchText.get()) && !isEmptyString(getText()) && getText().toUpperCase().contains(searchText.get().toUpperCase())) {           
            getStyleClass().remove(HIGHLIGHT_CLASS2);
            getStyleClass().add(HIGHLIGHT_CLASS);

        } else if (!isEmptyString(searchText2.get()) && !isEmptyString(getText()) && getText().toUpperCase().contains(searchText2.get().toUpperCase())) {
            getStyleClass().remove(HIGHLIGHT_CLASS);
            getStyleClass().add(HIGHLIGHT_CLASS2);            

        } else {
            getStyleClass().remove(HIGHLIGHT_CLASS2);
            getStyleClass().remove(HIGHLIGHT_CLASS);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }             
}

private boolean isEmptyString(String text) {
    return text == null || text.equals("");
}

This generates something like this

the word Lorem was used for red and sem for yellow

But the thing is I can’t possibly define all the combinations in the style sheet wrt foreground and background colors. Is there a way how I can manually add style sheets programmatically based on the users preference. Or is there another way to do it. Here is the screen I have designed for the user to indicate what should be highlighted

enter image description here


Solution

  • You can easely do it by using cellfactory on your listview

    listView.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
                @Override
                public ListCell<String> call(ListView<String> stringListView) {
                    return new ListCell<String>(){
                        @Override
                        protected void updateItem(String s, boolean b) {
                            super.updateItem(s, b);    //To change body of overridden methods use File | Settings | File Templates.
                            if (b) {
                                setText(null);
                                setGraphic(null);
                            }
                            if (s.contains("warning")){
                                setStyle(your style here);
                                        setGraphic(your graphics);
                                setText(your text);
                            }
                            if (s.contains("error")){
                                setStyle(your style here);
                                setGraphic(your graphics);
                                setText(your text);
                            }
                        }
                    };
                }
            });