TornadoFX ListView 的样式背景

问题描述

是否可以设置 ListView 组件的样式,使所有元素都没有阴影背景?

我不是这样的:

Image showing the default behaviour,that I do not want

而是让它们都像第一项、第三项、第五项等一样。

TIA

解决方法

在默认样式表中,ListCellmodena.css 背景颜色由以下代码行控制:

.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;
}

因此要删除奇数单元格的替代颜色(请注意,计数是零索引的,因此奇数单元格是列表视图中的第 2 个、第 4 个等),您只需要包含以下内容在您的外部 CSS 文件中,将奇数单元格的颜色恢复为与偶数单元格相同的颜色:

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

如果您需要将其应用于一个特定的 ListView,您可以在该 ListView 上设置一个 ID:

ListView myListView ;
// ...

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

然后CSS选择器变成

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

您需要创建一个具有非空背景的自定义 ListCell。执行此操作后,所选行的 ListView 的自动颜色处理将不再正常工作。所以你必须自己处理。选择操作会将文本颜色反转为白色,仅此而已。所以需要根据ListCell的“Selected”属性来设置单元格的背景色。在 Java 中,它看起来像这样:

    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,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);
                }
            }
        }
    }

一旦你这样做,单元格背景不再透明,ListView本身的条纹图案也不会显示出来。

编辑:

正如所指出的,这是严厉的,除了在大多数情况下 ListView 不会是一个简单的带有字符串的标签。它将在 ListCell 中具有某种布局,这将要求您在任何情况下创建自定义 ListCell。

然而,通过绑定到“Selected”属性直接弄乱背景是笨拙的。可以新建一个StyleClass,然后在css中定义修改后的PseudoClasses即可。然后将这个新的 StyleClass 添加到自定义 ListCell 中,然后它会在应用“EVEN”和“ODD”伪类时自动处理它。

我发现的一件事是,由于在默认 Modena css 中的所有其他定义之后应用了新的“奇数”定义,因此抑制了奇数行的“SELECTED”伪类。这意味着奇数行和偶数行在选择时看起来不同,因此需要在“ODD”定义之后将重复的“SELECTED”定义添加到新css中。然后一切正常。所以新代码看起来像这样:

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%);
}

主要,现在将新样式表加载到场景中:

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(),200);
        scene.getStylesheets().add(getClass().getResource("/css/samples.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

然后对 ListCell 的唯一自定义是添加新的 StyleClass:

public class ListBackgroundWhite extends ListView<String> {

    public ListBackgroundWhite() {
        super();
        setCellFactory(listView -> new WhiteListCell());
        setItems(FXCollections.observableArrayList("first 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);
            }
        }
    }
}

但如果你真的只想拥有一个只有简单标签的 ListView,你可以让单元工厂将 StyleClass 添加到标准 TextFieldListCell 上:

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