JavaFX-绑定不同TableView中相应TableRows的属性

JavaFX-绑定不同TableView中相应TableRows的属性,javafx,Javafx,我在同一场景中有两个TableViews,它们密切相关。我想设置一个侦听器,当用户将某一行悬停在一个表中时,另一个表中具有相同索引的行也将被“悬停” 我试图用一个自定义的行工厂tableView.setRowFactory(…)来解决这个问题。在工厂调用(…)方法中,我可以在目标行上切换CSS伪类(.myclass:hover),如: row.hoverProperty().addListener((obs, o, n) -> { myOtherTable.[get row

我在同一场景中有两个
TableView
s,它们密切相关。我想设置一个侦听器,当用户将某一行悬停在一个表中时,另一个表中具有相同索引的行也将被“悬停”

我试图用一个自定义的行工厂
tableView.setRowFactory(…)
来解决这个问题。在工厂
调用(…)
方法中,我可以在目标行上切换CSS伪类(
.myclass:hover
),如:

row.hoverProperty().addListener((obs, o, n) -> {
        myOtherTable.[get row here].pseudoClassStateChanged(PseudoClass.getPseudoClass("hover"), true);
});
正如您在我的工厂方法中看到的,我有一个对第二个
TableView
对象的引用,
myOtherTable
。我想我必须抓住它的
TableRow
对象才能继续设置伪类,但我不知道如何设置

也许有更好的方法吗?

如果我没记错的话,您不能直接访问TableView的一行。获取行索引的唯一方法是在定义CellFactory时访问属性indexProperty


我建议您创建一个个性化的扩展TableRow或TableCell对象,您可以在其中存储一个id或类似的东西…

创建一个表示悬停行索引的属性和一个
伪类:

IntegerProperty hoveredRowIndex = new SimpleIntegerProperty(-1);
PseudoClass appearHovered = PseudoClass.getPseudoClass("appear-hovered");
现在创建一个行工厂,创建观察此值及其自身索引的表行:

Callback<TableView<T>, TableCell<T>> rowFactory = tv -> {
    TableRow<T> row = new TableRow<T>() {
        private BooleanBinding shouldAppearHovered = Bindings.createBooleanBinding(
                () -> getIndex() != -1 && getIndex() == hoveredRowIndex.get(), indexProperty(),
                hoveredRowIndex);

        {

            shouldAppearHovered.addListener(
                    (obs, wasHovered, isNowHovered) -> pseudoClassStateChanged(appearHovered, isNowHovered));

            hoverProperty().addListener((obs, wasHovered, isNowHovered) -> {
                if (isNowHovered) {
                    hoveredRowIndex.set(getIndex());
                } else {
                    hoveredRowIndex.set(-1);
                }
            });
        }
    };
    return row;
};
要设置应显示为悬停的行的样式,请使用

。表格行单元格:悬停显示。表格单元格{
/* ... */
}
设置该行中单个单元格的样式

这里有一个SSCCE:

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

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.BooleanBinding;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.css.PseudoClass;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class ConnectedHoverTables extends Application {

    private IntegerProperty hoveredRowIndex = new SimpleIntegerProperty(-1);
    private PseudoClass appearHovered = PseudoClass.getPseudoClass("appear-hovered");

    @Override
    public void start(Stage primaryStage) {
        HBox root = new HBox(10, createTable(), createTable());
        root.setPadding(new Insets(20));
        Scene scene = new Scene(root);
        scene.getStylesheets().add("style.css");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private TableView<Item> createTable() {
        TableView<Item> table = new TableView<>();

        table.setRowFactory(tv -> {
            TableRow<Item> row = new TableRow<Item>() {
                private BooleanBinding shouldAppearHovered = Bindings.createBooleanBinding(
                        () -> getIndex() != -1 && getIndex() == hoveredRowIndex.get(), indexProperty(),
                        hoveredRowIndex);

                {

                    shouldAppearHovered.addListener(
                            (obs, wasHovered, isNowHovered) -> pseudoClassStateChanged(appearHovered, isNowHovered));

                    hoverProperty().addListener((obs, wasHovered, isNowHovered) -> {
                        if (isNowHovered) {
                            hoveredRowIndex.set(getIndex());
                        } else {
                            hoveredRowIndex.set(-1);
                        }
                    });
                }
            };
            return row;
        });

        table.setOnMouseClicked(e -> System.gc());

        table.getColumns().add(column("Item", Item::nameProperty));
        table.getColumns().add(column("Value", Item::valueProperty));
        table.getItems().setAll(createData());
        return table;
    }

    private List<Item> createData() {
        Random rng = new Random();
        List<Item> items = new ArrayList<>();
        for (int i = 1; i <= 100; i++) {
            Item item = new Item("Item " + i, rng.nextInt(1000));
            items.add(item);
        }
        return items;
    }

    private <S, T> TableColumn<S, T> column(String title, Function<S, ObservableValue<T>> property) {
        TableColumn<S, T> col = new TableColumn<>(title);
        col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
        return col;
    }

    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) {
        launch(args);
    }
}
import java.util.ArrayList;
导入java.util.List;
导入java.util.Random;
导入java.util.function.function;
导入javafx.application.application;
导入javafx.beans.binding.Bindings;
导入javafx.beans.binding.BooleanBinding;
导入javafx.beans.property.IntegerProperty;
导入javafx.beans.property.SimpleIntegerProperty;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.beans.property.StringProperty;
导入javafx.beans.value.observeValue;
导入javafx.css.pseudo类;
导入javafx.geometry.Insets;
导入javafx.scene.scene;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableRow;
导入javafx.scene.control.TableView;
导入javafx.scene.layout.HBox;
导入javafx.stage.stage;
公共类ConnectedHoverTables扩展了应用程序{
私有IntegerProperty hoveredRowIndex=新的SimpleIntegerProperty(-1);
私有伪类appearhowered=PseudoClass.getPseudoClass(“显示悬停”);
@凌驾
公共无效开始(阶段primaryStage){
HBox root=新的HBox(10,createTable(),createTable());
根。设置填充(新插图(20));
场景=新场景(根);
scene.getStylesheets().add(“style.css”);
初级阶段。场景(场景);
primaryStage.show();
}
私有表视图createTable(){
TableView table=新TableView();
表.setRowFactory(电视->{
TableRow行=新建TableRow(){
私有BooleanBinding应显示为hovered=Bindings.createBooleanBinding(
()->getIndex()!=-1&&getIndex()==hoveredRowIndex.get(),indexProperty(),
悬停指数);
{
shouldAppearHovered.addListener(
(obs,wasHovered,isnowhered)->pseudoClassStateChanged(appearhered,isnowhered));
hoverProperty().addListener((obs、wasHovered、isNowHovered)->{
如果(现在悬停){
hoveredRowIndex.set(getIndex());
}否则{
hoveredRowIndex.set(-1);
}
});
}
};
返回行;
});
table.setOnMouseClicked(e->System.gc());
table.getColumns().add(列(“项”,项::nameProperty));
table.getColumns().add(column(“Value”,Item::valueProperty));
table.getItems().setAll(createData());
返回表;
}
私有列表createData(){
随机rng=新随机();
列表项=新建ArrayList();
for(int i=1;i property.apply(cellData.getValue());
返回列;
}
公共静态类项{
私有最终StringProperty名称=新SimpleStringProperty();
私有最终IntegerProperty值=新的SimpleIntegerProperty();
公共项(字符串名称、int值){
集合名(名称);
设置值(值);
}
公共最终字符串属性nameProperty(){
返回此.name;
}
公共最终字符串getName(){
返回此.nameProperty().get();
}
公共最终void集合名(最终字符串名){
this.nameProperty().set(name);
}
公共最终整数属性值属性(){
返回此.value;
}
公共最终整数getValue(){
返回此.valueProperty().get();
}
公共最终无效设置值(最终整数值){
this.valueProperty().set(值);
}
}
公共静态void main(字符串[]args){
发射(args);
}
}

谢谢,它几乎可以工作了!当我在表a中悬停一行时,表B中的相应行有时显示为悬停,有时不显示;当我首先悬停在表B上时,表A几乎从未悬停过。这是否与两个表同时设置
hoveredRowIndex
属性有关?这应该是您想要的。。。让我试着写一个SSCCE。是的,正在发生的是绑定正在被垃圾收集。解决方案是将其作为表行的一个属性:使用此更改更新答案。效果非常好。谢谢,我也更新了我的问题,以便更好地描述我们正在讨论的内容,并让您满意