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

时间:2017-05-17 11:21:18

标签: javafx

我在同一个场景中有两个TableView s密切相关。我想设置一个监听器,当用户在一个表中悬停某一行时,另一个表中具有相同索引的行是" hovered"同样。

我尝试使用自定义行工厂tableView.setRowFactory(...)解决此问题。在工厂call(...)方法内部,我可以在目标行上切换CSS伪类(.myclass:hover),如:

row.hoverProperty().addListener((obs, o, n) -> {
        myOtherTable.[get row here].pseudoClassStateChanged(PseudoClass.getPseudoClass("hover"), true);
});

正如您在我的工厂方法中所看到的,我引用了第二个TableView对象myOtherTable。我想我必须抓住它的TableRow对象继续设置伪类,但我无法弄清楚如何。
也许还有更好的方法吗?

2 个答案:

答案 0 :(得分:2)

创建一个表示悬停行的索引的属性,以及PseudoClass

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

(将T替换为表的实际类型。)

现在使用两个表的行工厂。您可以使用CSS选择器

.table-row-cell:appear-hovered {
    /* ... */
}

设置应该显示为悬停的行的样式,或使用

.table-row-cell:appear-hovered .table-cell {
    /* ... */
}

为该行中的单个单元格设置样式。

这是一个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);
    }
}

答案 1 :(得分:0)

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

我建议您创建一个个性化的扩展TableRow或TableCell对象,您可以在其中存储ID或类似内容......