如何设置与选定行相邻的 TableView 行的样式?

How can I style a TableView row adjacent to a selected row?

如何设置与当前所选行相邻的 TableView 行的样式?

我想这样做的原因是在选中行时更改行周围边框的颜色,包括顶部和底部。

我目前设置单元格边框(即 table 的网格)样式的方式是在单元格底部设置背景色并插入 1px。本质上,每个单元格绘制自己的底部边框。

这意味着如果我想更改选定行的“顶部”和底部边框,我还需要能够为当前选定单元格上方的单元格设置样式。

您可以向 table 行的索引和 table 的选定索引添加侦听器,这会更新 table 行上的自定义 CSS 伪类:

TableView<MyTableType> table = ... ;
PseudoClass beforeSelected = PseudoClass.getPseudoClass("before-selected");

table.setRowFactory(tv -> {
    TableRow<MyTableType> row = new TableRow<>();
    ChangeListener<Number> listener = (obs, oldValue, newValue) -> {
        if (row.isEmpty()) {
            row.pseudoClassStateChanged(beforeSelected, false);
        } else {
            row.pseudoClassStateChanged(beforeSelected, 
                row.getIndex() == table.getSelectionModel().getSelectedIndex() - 1);
        }
    };
    row.indexProperty().addListener(listener);
    table.getSelectionModel().selectedIndexProperty().addListener(listener);
    return row ;
});

然后在您的 CSS 文件中,您可以使用选择器

为所选行之前的 table 行设置样式
.table-row-cell:before-selected {
    /* styles here... */
}

这是一个完整的工作示例:

import java.util.function.Function;

import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.css.PseudoClass;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class StyleTest extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        TableView<Item> table = new TableView<>();
        PseudoClass beforeSelected = PseudoClass.getPseudoClass("before-selected");
        table.setRowFactory(tv -> {
            TableRow<Item> row = new TableRow<>();
            ChangeListener<Number> listener = (obs, oldValue, newValue) -> {
                if (row.isEmpty()) {
                    row.pseudoClassStateChanged(beforeSelected, false);
                } else {
                    row.pseudoClassStateChanged(beforeSelected, 
                            row.getIndex() == table.getSelectionModel().getSelectedIndex() - 1);
                }
            };
            row.indexProperty().addListener(listener);
            table.getSelectionModel().selectedIndexProperty().addListener(listener);
            return row ;
        });
        
        table.getColumns().add(column("Item", Item::nameProperty));
        table.getColumns().add(column("Value", Item::valueProperty));
                
        for (int i=1 ; i <= 100 ; i++) {
            table.getItems().add(new Item("Item "+i, i));
        }
        
        Scene scene = new Scene(new BorderPane(table));
        scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
        stage.setScene(scene);
                
        stage.show();
        
        
    }
    
    private static <S,T> TableColumn<S,T> column(String title, Function<S, Property<T>> prop) {
        TableColumn<S,T> column = new TableColumn<>(title);
        column.setCellValueFactory(cellData -> prop.apply(cellData.getValue()));
        return column ;
    }

    
    public static class Item {
        private final StringProperty name = new SimpleStringProperty();
        private final IntegerProperty value = new SimpleIntegerProperty();
        
        public Item(String name, int value) {
            setName(name);
            setValue(value);
        }

        public final StringProperty nameProperty() {
            return this.name;
        }
        

        public final String getName() {
            return this.nameProperty().get();
        }
        

        public final void setName(final String name) {
            this.nameProperty().set(name);
        }
        

        public final IntegerProperty valueProperty() {
            return this.value;
        }
        

        public final int getValue() {
            return this.valueProperty().get();
        }
        

        public final void setValue(final int value) {
            this.valueProperty().set(value);
        }
        
        
        
    }
    
    public static void main(String[] args) {
        Application.launch(args);
    }

}

和一个示例 style.css(只是将前一行涂成绿色...):

.table-row-cell:before-selected {
  -fx-background: #00b140 ;
}