JavaFXTableView:单击打开行之间的详细信息

JavaFXTableView:单击打开行之间的详细信息,javafx,tableview,Javafx,Tableview,我正在尝试在TableView中显示旅行连接。到目前为止,这就像一个魅力。现在,我在尝试获取要在表行之间显示的连接的详细信息时遇到了麻烦。这应该在选择表项时发生 问题是,详细信息的格式与我显示的连接不同。所以我需要在两个表行之间放置一个面板。这是可能的吗?正确的方法是为TableRow创建自定义外观,并在返回已安装自定义外观的TableRow的表上使用rowFactory。然而,由于皮肤类在编写注释时不是公共API,尽管它们将在Java9中,这意味着完全从头开始实现皮肤类,并布置表单元格等,这将

我正在尝试在TableView中显示旅行连接。到目前为止,这就像一个魅力。现在,我在尝试获取要在表行之间显示的连接的详细信息时遇到了麻烦。这应该在选择表项时发生


问题是,详细信息的格式与我显示的连接不同。所以我需要在两个表行之间放置一个面板。这是可能的吗?

正确的方法是为TableRow创建自定义外观,并在返回已安装自定义外观的TableRow的表上使用rowFactory。然而,由于皮肤类在编写注释时不是公共API,尽管它们将在Java9中,这意味着完全从头开始实现皮肤类,并布置表单元格等,这将是相当困难的

一种不太正式但更简单的方法是直接覆盖TableRow中的各种布局方法,并连接到超类实现中

这很有效,但感觉有点脆弱:

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

import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TableWithCustomRow extends Application {

    @Override
    public void start(Stage primaryStage) {
        TableView<Item> table = new TableView<>();

        table.setRowFactory(tv -> new TableRow<Item>() {
            Node detailsPane ;
            {
                selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
                    if (isNowSelected) {
                        getChildren().add(detailsPane);
                    } else {
                        getChildren().remove(detailsPane);
                    }
                    this.requestLayout();
                });
                detailsPane = createDetailsPane(itemProperty());
            }

            @Override
            protected double computePrefHeight(double width) {
                if (isSelected()) {
                    return super.computePrefHeight(width)+detailsPane.prefHeight(getWidth());
                } else {
                    return super.computePrefHeight(width);
                }
            }

            @Override
            protected void layoutChildren() {
                super.layoutChildren();
                if (isSelected()) {
                    double width = getWidth();
                    double paneHeight = detailsPane.prefHeight(width);
                    detailsPane.resizeRelocate(0, getHeight()-paneHeight, width, paneHeight);
                } 
            }
        });

        Random random = new Random();
        for (int i = 1 ; i <= 100 ; i++) {
            table.getItems().add(new Item("Item "+i, random.nextInt(100)));
        }
        table.getColumns().add(column("Item", Item::nameProperty));
        table.getColumns().add(column("Value", Item::valueProperty));

        Scene scene = new Scene(table, 800, 600);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    private Node createDetailsPane(ObjectProperty<Item> item) {
        BorderPane detailsPane = new BorderPane();
        Label detailsLabel = new Label();
        VBox labels = new VBox(5, new Label("These are the"), detailsLabel);
        labels.setAlignment(Pos.CENTER_LEFT);
        labels.setPadding(new Insets(2, 2, 2, 16));
        detailsPane.setCenter(labels);

        Label icon = new Label("Icon");
        icon.setStyle("-fx-background-color: aqua; -fx-text-fill: darkgreen; -fx-font-size:18;");
        BorderPane.setMargin(icon, new Insets(6));
        icon.setMinSize(40, 40);
        detailsPane.setLeft(icon);

        detailsPane.setStyle("-fx-background-color: -fx-background; -fx-background: skyblue;");

        item.addListener((obs, oldItem, newItem) -> {
            if (newItem == null) {
                detailsLabel.setText("");
            } else {
                detailsLabel.setText("details for "+newItem.getName());
            }
        });


        return detailsPane ;
    }

    private static <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()));
        col.setPrefWidth(150);
        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 java.lang.String getName() {
            return this.nameProperty().get();
        }


        public final void setName(final java.lang.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);
    }
}
这就产生了以下结果:


正确的方法是为TableRow创建自定义外观,并在返回安装了自定义外观的TableRow的表上使用rowFactory。然而,由于皮肤类在编写注释时不是公共API,尽管它们将在Java9中,这意味着完全从头开始实现皮肤类,并布置表单元格等,这将是相当困难的

一种不太正式但更简单的方法是直接覆盖TableRow中的各种布局方法,并连接到超类实现中

这很有效,但感觉有点脆弱:

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

import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class TableWithCustomRow extends Application {

    @Override
    public void start(Stage primaryStage) {
        TableView<Item> table = new TableView<>();

        table.setRowFactory(tv -> new TableRow<Item>() {
            Node detailsPane ;
            {
                selectedProperty().addListener((obs, wasSelected, isNowSelected) -> {
                    if (isNowSelected) {
                        getChildren().add(detailsPane);
                    } else {
                        getChildren().remove(detailsPane);
                    }
                    this.requestLayout();
                });
                detailsPane = createDetailsPane(itemProperty());
            }

            @Override
            protected double computePrefHeight(double width) {
                if (isSelected()) {
                    return super.computePrefHeight(width)+detailsPane.prefHeight(getWidth());
                } else {
                    return super.computePrefHeight(width);
                }
            }

            @Override
            protected void layoutChildren() {
                super.layoutChildren();
                if (isSelected()) {
                    double width = getWidth();
                    double paneHeight = detailsPane.prefHeight(width);
                    detailsPane.resizeRelocate(0, getHeight()-paneHeight, width, paneHeight);
                } 
            }
        });

        Random random = new Random();
        for (int i = 1 ; i <= 100 ; i++) {
            table.getItems().add(new Item("Item "+i, random.nextInt(100)));
        }
        table.getColumns().add(column("Item", Item::nameProperty));
        table.getColumns().add(column("Value", Item::valueProperty));

        Scene scene = new Scene(table, 800, 600);
        primaryStage.setScene(scene);
        primaryStage.show();

    }

    private Node createDetailsPane(ObjectProperty<Item> item) {
        BorderPane detailsPane = new BorderPane();
        Label detailsLabel = new Label();
        VBox labels = new VBox(5, new Label("These are the"), detailsLabel);
        labels.setAlignment(Pos.CENTER_LEFT);
        labels.setPadding(new Insets(2, 2, 2, 16));
        detailsPane.setCenter(labels);

        Label icon = new Label("Icon");
        icon.setStyle("-fx-background-color: aqua; -fx-text-fill: darkgreen; -fx-font-size:18;");
        BorderPane.setMargin(icon, new Insets(6));
        icon.setMinSize(40, 40);
        detailsPane.setLeft(icon);

        detailsPane.setStyle("-fx-background-color: -fx-background; -fx-background: skyblue;");

        item.addListener((obs, oldItem, newItem) -> {
            if (newItem == null) {
                detailsLabel.setText("");
            } else {
                detailsLabel.setText("details for "+newItem.getName());
            }
        });


        return detailsPane ;
    }

    private static <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()));
        col.setPrefWidth(150);
        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 java.lang.String getName() {
            return this.nameProperty().get();
        }


        public final void setName(final java.lang.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);
    }
}
这就产生了以下结果:


也许你应该考虑使用A。但我想您需要TableView提供的列。不过,树状视图中的节点可以修改为类似于表的形式。a有一个树状视图结构,其中包含表提供的列,如果您需要的话。但细节与我所显示的连接不同,说明这不是你所需要的。也许你应该考虑使用A。但我想您需要TableView提供的列。不过,树状视图中的节点可以修改为类似于表的形式。a有一个树状视图结构,其中包含表提供的列,如果您需要的话。但细节的格式与我显示的连接不同,这并不是你所需要的。这非常有效。你介意我在博客上发布这个解决方案吗?这不是一个直接的拷贝,而是一个广义的版本;请参考这篇文章。顺便说一句,我只测试了它非常短暂的多重选择启用;如果你还没有测试过的话,你也可能想在那里测试一下。这非常有效。你介意我在博客上发布这个解决方案吗?这不是一个直接的拷贝,而是一个广义的版本;请参考这篇文章。顺便说一句,我只测试了它非常短暂的多重选择启用;如果还没有,你可能也想在那里测试一下。