简体   繁体   中英

Styling background of TornadoFX ListView

Is it possible to style a ListView component so that none of the elements have a shaded background?

Ie not like this:

显示默认行为的图像,我不想要

But instead have them all styled like the first, third, fifth item etc.

TIA

In the default stylesheet, modena.css the background color for ListCell s is governed by the following lines of code:

.list-cell,
.tree-cell {
    -fx-background: -fx-control-inner-background;
    -fx-background-color: -fx-background;
    -fx-text-fill: -fx-text-background-color;
}

/* ... */

.list-cell:odd {
    -fx-background: -fx-control-inner-background-alt;
}

So to remove the alternative color for the odd-numbered cells (note that counting is zero-indexed, so the odd-numbered cells are the 2nd, 4th, etc in the list view), you just need to include the following in your external CSS file, to revert the color for the odd-numbered cells to the same as the even-numbered cells:

.list-cell:odd {
    -fx-background: -fx-control-inner-background ;
}

If you need to apply this to one specific ListView , you can set an id on that ListView :

ListView myListView ;
// ...

myListView.setId("plain-list-view");

and then the CSS selector becomes

#plain-list-view .list-cell:odd {
    -fx-background: -fx-control-inner-background ;
}

You need to create a custom ListCell with a non-null Background. Once you do this, the automatic colour handling of the ListView for selected rows won't work properly any more. So you'll have to handle that yourself. The selection action will invert the colour of the text to white, but that's all. So you need to set the background colour of the cell based on the "Selected" property of the ListCell. In Java it would look like this:

    public class Sample1 extends Application {
    
        public static void main(String[] args) {
            launch(args);
        }
    
        @Override
        public void start(Stage primaryStage) {
            Scene scene = new Scene(new ListBackgroundWhite(), 300, 200);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    }
    
    public class ListBackgroundWhite extends ListView<String> {
    
        public ListBackgroundWhite() {
            super();
            setCellFactory(listView -> new WhiteListCell());
            setItems(FXCollections.observableArrayList("first line", "second line", "third line", "fourth line"));
        }
    
        static class WhiteListCell extends ListCell<String> {
    
        WhiteListCell() {
            Background unselectedBackground =
                    new Background(new BackgroundFill(Color.WHITESMOKE, CornerRadii.EMPTY, Insets.EMPTY));
            Background selectedBackground = new Background(new BackgroundFill(Color.BROWN, CornerRadii.EMPTY,
                    Insets.EMPTY));
            backgroundProperty().bind(Bindings.createObjectBinding(() -> isSelected() ? selectedBackground :
                    unselectedBackground, selectedProperty()));
        }
    
            @Override
            public void updateItem(String item, boolean isEmpty) {
                super.updateItem(item, isEmpty);
                if (!isEmpty) {
                    setText(item);
                } else {
                    setText(null);
                }
            }
        }
    }

Once you do this, the cell background is no longer transparent, and the stripe pattern of the ListView itself won't show through.

EDIT:

As pointed out, this IS heavy-handed, except that in most cases a ListView isn't going to be a simple Label with a string in it. It's going to have some sort of layout in the ListCell that is going to require that you create a custom ListCell in any event.

However, messing with the Background directly via a binding to the "Selected" property is clumsy. You can create a new StyleClass, and then just define the modified PseudoClasses in the css. Then add this new StyleClass to the custom ListCell, and then it will handle it automatically as it applies the "EVEN" and "ODD" pseudoclasses.

One thing I found was that since the new "odd" definition gets applied after all of the other definitions in the default Modena css, that the "SELECTED" pseudoclass for ODD lines is suppressed. This means that the odd and even lines look different when they are selected, so a duplicate "SELECTED" definition needed to be added to the new css after the "ODD" definition. Then everything works properly. So the new code looks like this:

The CSS:

.custom-list-cell:odd {
    -fx-background: -fx-control-inner-background;
}

.custom-list-cell:selected {
    -fx-background: -fx-selection-bar;
    -fx-table-cell-border-color: derive(-fx-selection-bar, 20%);
}

The main, now loads the new stylesheet into the Scene:

public class Sample1 extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        Scene scene = new Scene(new ListBackgroundWhite(), 300, 200);
        scene.getStylesheets().add(getClass().getResource("/css/samples.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

And then the only customization to the ListCell is to add the new StyleClass:

public class ListBackgroundWhite extends ListView<String> {

    public ListBackgroundWhite() {
        super();
        setCellFactory(listView -> new WhiteListCell());
        setItems(FXCollections.observableArrayList("first line", "second line", "third line", "fourth line"));
    }

    static class WhiteListCell extends ListCell<String> {

        WhiteListCell() {
            getStyleClass().add("custom-list-cell");
        }

        @Override
        public void updateItem(String item, boolean isEmpty) {
            super.updateItem(item, isEmpty);
            if (!isEmpty) {
                setText(item);
            } else {
                setText(null);
            }
        }
    }
}

But if you really are just wanting to have a ListView with just simple labels in it, you can just have the cell factory add the StyleClass on to the standard TextFieldListCell:

public ListBackgroundWhite() {
    super();
    setCellFactory(listView -> {
        ListCell<String> cell = new TextFieldListCell<>();
        cell.getStyleClass().add("custom-list-cell");
        return cell;
    });
    setItems(FXCollections.observableArrayList("first line", "second line", "third line", "fourth line"));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM