Javafx:如何在setRowFactory中引用行内的特定单元格?

Javafx:如何在setRowFactory中引用行内的特定单元格?,java,javafx,Java,Javafx,我有一个tableView,其中每个表行表示一个对象,每个列表示该对象的属性。在tableView中,我定义了一个setRowFactory 在setRowFactory中,我希望能够访问行中的特定单元格,并通过执行以下操作突出显示它:ThisCellofThisRow.pseudoClassStateChanged(…) 问题是:我不知道如何引用此ThisCellofThisRow 不确定要做什么,但可以更改行的伪类状态,然后使用CSS选择特定列。这样,行工厂根本不必访问单元格 例如: hig

我有一个tableView,其中每个表行表示一个对象,每个列表示该对象的属性。在tableView中,我定义了一个
setRowFactory

setRowFactory
中,我希望能够访问行中的特定单元格,并通过执行以下操作突出显示它:
ThisCellofThisRow.pseudoClassStateChanged(…)


问题是:我不知道如何引用此
ThisCellofThisRow

不确定要做什么,但可以更改行的伪类状态,然后使用CSS选择特定列。这样,行工厂根本不必访问单元格

例如:

highlight-cell-in-row.css:

/*
** Gives a yellow background to a table cell with style class "value-cell"
** that is inside a row with the "high" psuedoclass set 
*/

.table-row-cell:high .value-cell {
    -fx-background-color: transparent, yellow ;
}
TableViewHighlightItem.java:

import java.util.Random;
import java.util.function.Function;

import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
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 TableViewHighlightItem extends Application {

    @Override
    public void start(Stage primaryStage) {

        // create table and columns:
        TableView<Item> table = new TableView<>();
        TableColumn<Item, String> nameCol = column("Name", Item::nameProperty);
        TableColumn<Item, Number> valueCol = column("Value", Item::valueProperty);
        table.getColumns().add(nameCol);
        table.getColumns().add(valueCol);

        // basic default cell, but with "value-cell" always added as a CSS class:
        valueCol.setCellFactory(col -> {
            TableCell<Item, Number> cell = new TableCell<Item, Number>(){
                @Override
                public void updateItem(Number value, boolean empty) {
                    super.updateItem(value, empty);
                    if (empty) {
                        setText(null);
                    } else {
                        setText(value.toString());
                    }
                }
            };
            cell.getStyleClass().add("value-cell");
            return cell ;
        });

        PseudoClass high = PseudoClass.getPseudoClass("high");

        // Table row toggles "high" pseudoclass according to state of current item in row:
        table.setRowFactory(tv -> {
            TableRow<Item> row = new TableRow<>();

            ChangeListener<Boolean> highListener = (obs, wasHigh, isNowHigh) -> 
                row.pseudoClassStateChanged(high, isNowHigh);

            row.itemProperty().addListener((obs, oldItem, newItem) -> {
                if (oldItem != null) {
                    oldItem.highProperty().removeListener(highListener);
                }
                if (newItem == null) {
                    row.pseudoClassStateChanged(high, false);
                } else {
                    row.pseudoClassStateChanged(high, newItem.isHigh());
                    newItem.highProperty().addListener(highListener);
                }
            });

            return row ;
        });

        Random rng = new Random();

        // Button to test changing data to random values:
        Button changeButton = new Button("Change Data");
        changeButton.setOnAction(e -> 
                table.getItems().forEach(item -> item.setValue(rng.nextInt(20))));

        // add data to table:
        for (int i = 1 ; i <= 40 ; i++) {
            table.getItems().add(new Item("Item "+i, rng.nextInt(20)));
        }

        // layout:
        BorderPane root = new BorderPane(table, null, null, changeButton, null);
        BorderPane.setAlignment(changeButton, Pos.CENTER);
        BorderPane.setMargin(changeButton, new Insets(10));
        Scene scene = new Scene(root, 600, 600);
        scene.getStylesheets().add("highlight-cell-in-row.css");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    // utility method for creating columns:
    private static <S,T> TableColumn<S,T> column(String title, Function<S, ObservableValue<T>> property) {
        TableColumn<S,T> column = new TableColumn<>(title);
        column.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
        return column ;
    }

    // model class:
    public static class Item {
        private final StringProperty name = new SimpleStringProperty();
        private final IntegerProperty value = new SimpleIntegerProperty();
        private final ReadOnlyBooleanWrapper high = new ReadOnlyBooleanWrapper();

        public Item(String name, int value) {
            setName(name);
            setValue(value);
            high.bind(this.value.greaterThanOrEqualTo(10));
        }

        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 final ReadOnlyBooleanProperty highProperty() {
            return this.high.getReadOnlyProperty();
        }

        public final boolean isHigh() {
            return this.highProperty().get();
        }


    }

    public static void main(String[] args) {
        launch(args);
    }
}
import java.util.Random;
导入java.util.function.function;
导入javafx.application.application;
导入javafx.beans.property.IntegerProperty;
导入javafx.beans.property.ReadOnlyBooleanProperty;
导入javafx.beans.property.ReadOnlyBooleanWrapper;
导入javafx.beans.property.SimpleIntegerProperty;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.beans.property.StringProperty;
导入javafx.beans.value.ChangeListener;
导入javafx.beans.value.observeValue;
导入javafx.css.pseudo类;
导入javafx.geometry.Insets;
导入javafx.geometry.Pos;
导入javafx.scene.scene;
导入javafx.scene.control.Button;
导入javafx.scene.control.TableCell;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableRow;
导入javafx.scene.control.TableView;
导入javafx.scene.layout.BorderPane;
导入javafx.stage.stage;
公共类TableViewHighlightItem扩展了应用程序{
@凌驾
公共无效开始(阶段primaryStage){
//创建表和列:
TableView table=新TableView();
TableColumn nameCol=列(“名称”,项::nameProperty);
TableColumn valueCol=列(“值”,项::valueProperty);
table.getColumns().add(nameCol);
table.getColumns().add(valueCol);
//基本默认单元格,但“值单元格”始终作为CSS类添加:
值列设置单元工厂(列->{
TableCell单元格=新的TableCell(){
@凌驾
public void updateItem(数值,布尔空){
super.updateItem(值,空);
if(空){
setText(空);
}否则{
setText(value.toString());
}
}
};
cell.getStyleClass().add(“值单元格”);
返回单元;
});
PseudoClass高=PseudoClass.getPseudoClass(“高”);
//表行根据行中当前项的状态切换“高”伪类:
表.setRowFactory(电视->{
TableRow行=新TableRow();
ChangeListener highListener=(obs、wasHigh、isNowHigh)->
row.pseudoClassStateChanged(高,isNowHigh);
row.itemProperty().addListener((obs、oldItem、newItem)->{
if(oldItem!=null){
oldItem.highProperty().RemovelListener(highListener);
}
if(newItem==null){
行.pseudoClassStateChanged(高,假);
}否则{
row.pseudoClassStateChanged(高,newItem.isHigh());
newItem.highProperty().addListener(highListener);
}
});
返回行;
});
随机rng=新随机();
//用于测试将数据更改为随机值的按钮:
按钮更改按钮=新按钮(“更改数据”);
更改按钮。设置操作(e->
table.getItems().forEach(item->item.setValue(rng.nextInt(20));
//向表中添加数据:
for(int i=1;i property.apply(cellData.getValue());
返回列;
}
//模型类:
公共静态类项{
私有最终StringProperty名称=新SimpleStringProperty();
私有最终IntegerProperty值=新的SimpleIntegerProperty();
private final ReadOnlyBooleanWrapper high=新的ReadOnlyBooleanWrapper();
公共项(字符串名称、int值){
集合名(名称);
设置值(值);
high.bind(该值大于或等于(10));
}
公共最终字符串属性nameProperty(){
返回此.name;
}
公共最终字符串getName(){
返回此.nameProperty().get();
}
公共最终void集合名(最终字符串名){
this.nameProperty().set(name);
}
公共最终整数属性值属性(){
返回此.value;
}
公共最终整数getValue(){
返回此.valueProperty().get();
}
公共最终无效设置值(最终整数值){
this.valueProperty().set(值);
}
公共最终ReadOnlyBooleanProperty highProperty(){
返回此.high.getReadOnlyProperty();
}
公共最终布尔值isHigh(){
返回此.highProperty().get();
}
}
公共静态void main(字符串[]args){
发射(args);
}
}

谁更改列的伪类状态?也许您可以向该组件询问您所在行的状态?您指的是谁?我只想知道如何调用/引用行中的特定单元格框,并突出显示该单元格。呼叫/参考部分是我未能实现的部分。嗨@James_D,真的很感谢你的回答,你的代码使手机闪烁还是行闪烁?我的最终目标是制作一个手机闪光灯,而不是整排的闪光灯。你为什么不运行一下看看呢?它只突出显示单元格,因为CSS应用了t