1

私が念頭に置いていた設計は次のようなものです。実装が次のようになるラッパークラスがありますTreeView<E>E

public class E {
    private int key;
    private String value;

    public E(int key, String value) {
        this.key = key;
        this.value = value;
    }

    public int getKey(){
        return key; 
    }

    public String getValue() {
        return value;
    }

    public String toString(){
        return value;
    }
}

したがって、多数のインスタンスTreeView<E>が含まれます。TreeItem<E>そして、toString()メソッドはE値を表示します。

そして、ツリー項目のいずれかを押すと、 のキー値に接続されている DB からのすべての行を含むTableView<ObservableList<String>>、選択したものの下に が表示されるようにします。TreeItem<E>TreeItem<E>

これは可能ですか?適切なオプションであることはわかっTreeTableViewていますが、ツリー項目のいずれかを押さない限り、列を表示したくありません。そして、それぞれTreeItem<E>に独自のテーブルが必要です。ただし、レコードの場合、すべてのテーブルに同じ列があり、行数が異なるだけです。

更新: @Uluk Biy の助けを借りて、解決策を実装することができましたが、1 つのバグが含まれています。

問題は、TreeView で TreeItem を押すと、選択されるノードが、TreeItem を押したときにスクロール ペインに表示されない最初のノードの 2 ステップ下のノードになることです (TreeView には自動的にスクロール ペインが含まれます)。 )。したがって、非表示のツリー項目が 3 つ未満になるようにウィンドウを拡大すると、何も表示されません。TableView が間違った場所に表示されるわけではありません。問題は、正しいツリー項目が選択されていないことです (キー値を出力したので、これはわかっています。

これは、このバグを示す SSCCE です。表でラッパー 1 を選択すると、ラッパー 6 が選択されます。TreeView のサイズを変更して非表示にする TreeItem を 3 つ未満にすると、何も選択されなくなります。

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;

public class SSCCE extends Application {

    private Stage primaryStage;
    private AnchorPane rootLayout;
    private TreeView<Wrapper> overview; 

    public void start(Stage primaryStage) {
        this.primaryStage = primaryStage;
        this.primaryStage.setTitle("SSCCE");

        initRootLayout();
        showTreeView();
    }

    public void initRootLayout() {
        rootLayout = new AnchorPane();
        rootLayout.setPrefSize(300, 200);

        Scene scene = new Scene(rootLayout);
        primaryStage.setScene(scene);

        primaryStage.show();
    }       

    ObservableList<String> columns = FXCollections.observableArrayList();
    ObservableList<ObservableList<String>> data = FXCollections.observableArrayList();
    ObservableList<Wrapper> items = FXCollections.observableArrayList();

    private void showTreeView() {

        // Dummy values
        columns.addAll("key", "text");              
        data.add(FXCollections.observableArrayList("1", "test"));
        data.add(FXCollections.observableArrayList("1", "test2"));
        data.add(FXCollections.observableArrayList("2", "test3"));
        data.add(FXCollections.observableArrayList("2", "test4"));
        data.add(FXCollections.observableArrayList("3", "test5"));
        data.add(FXCollections.observableArrayList("3", "test6"));
        data.add(FXCollections.observableArrayList("4", "test7"));
        data.add(FXCollections.observableArrayList("4", "test8"));
        data.add(FXCollections.observableArrayList("5", "test9"));
        data.add(FXCollections.observableArrayList("5", "test10"));
        data.add(FXCollections.observableArrayList("6", "test11"));
        data.add(FXCollections.observableArrayList("6", "test12"));
        items.addAll(new Wrapper(1, "wrapper 1"), new Wrapper(2, "wrapper 2"), new Wrapper(3, "wrapper 3"), new Wrapper(4, "wrapper 4"), new Wrapper(5, "wrapper 5"), new Wrapper(6, "wrapper 6"));

        TreeItem<Wrapper> root = new TreeItem<Wrapper>();
        overview = new TreeView<Wrapper>(root);
        overview.setPrefHeight(75);

        overview.setCellFactory(new Callback<TreeView<Wrapper>, TreeCell<Wrapper>>() {
            @Override
            public TreeCell<Wrapper> call(TreeView<Wrapper> stringTreeView) {
                TreeCell<Wrapper> treeCell = new TreeCell<Wrapper>() {
                    @Override
                    protected void updateItem(Wrapper item, boolean empty) {
                        super.updateItem(item, empty);
                        if (empty || item == null) {
                            setText(null);
                            setGraphic(null);
                        } else {
                            if (getTreeItem().isLeaf() && isSelected()) {
                                setText(null);

                                // A debug text that proves that the wrong item is being selected.
                                System.out.println("Selected wrapper: " + item);

                                TableView<ObservableList<String>> table = new TableView<ObservableList<String>>();
                                for (int i = 0; i < columns.size(); i++) {
                                    final int j = i;

                                    TableColumn<ObservableList<String>, String> column = new TableColumn<ObservableList<String>, String>(
                                            columns.get(i));

                                    column.setCellValueFactory((
                                            TableColumn.CellDataFeatures<ObservableList<String>, String> param) -> new SimpleStringProperty(
                                            param.getValue().get(j)
                                                    .toString()));

                                    table.getColumns()
                                            .add(column);
                                }

                                ObservableList<ObservableList<String>> selected_data = FXCollections
                                        .observableArrayList();

                                for(int i = 0; i < data.size(); i++) {

                                    if(Integer.parseInt(data.get(i).get(0)) == item.getKey()) {
                                        selected_data.add(data.get(i));
                                    }
                                }
                                table.setItems(selected_data);

                                VBox vbox = new VBox(new Label(item
                                        .getValue()), table);
                                setGraphic(vbox);
                            } else {
                                setText(item.getValue());
                                setGraphic(null);
                            }
                        }
                    }
                };
                return treeCell;
            }
        });

        for (int i = 0; i < items.size(); i++) {
            TreeItem<Wrapper> target = new TreeItem<Wrapper>(items.get(i));
            root.getChildren().add(target);
        }

        overview.setShowRoot(false);
        rootLayout.getChildren().add(overview);

    }

    public static void main(String[] args) {
        launch(args);
    }
}

class Wrapper {
    private int key;
    private String value;

    Wrapper(int key, String value) {
        this.key = key;
        this.value = value;
    }

    int getKey() {
        return key;
    }

    String getValue() {
        return value;
    }

    public String toString() {
        return "Wrapper " + key;
    }
}
4

1 に答える 1

1

カスタム セル ファクトリを設定することは、ここで行う方法ではありません。セルは複数のアイテムをレンダリングするために再利用されるため、最初にすべてのセルがツリービューのビューポート内に表示されている場合、アイテムのデフォルトの選択だけではセルの再利用がトリガーされず、updateItem() が呼び出されません。一方、ビューポートの外に他のアイテムがあり、ユーザーがそれらのアイテムまでスクロールすると、上部の非表示アイテムのセルが再利用され、ビューポートに新しく入力されたアイテムの下にレンダリングされます。このimoは、以下のコメントで説明されている動作の説明です。要するに、カスタムを定義することTreeCellは正しいアプローチではありません。代わりに、項目選択の変更を観察し、そこにグラフィックを設定できます。

treeView.getSelectionModel().selectedItemProperty().addListener( ( ObservableValue<? extends TreeItem<Wrapper>> observable,
        TreeItem<Wrapper> oldValue, TreeItem<Wrapper> newValue ) ->
        {
            System.out.println( "Selected newValue: " + newValue );

            if ( oldValue != null )
            {
                // hide graphic of previous selected item
                oldValue.setGraphic( null );
            }

            if ( newValue != null )
            {
                TableView<ObservableList<String>> table = new TableView<>();
                for ( int i = 0; i < columns.size(); i++ )
                {
                    final int j = i;

                    TableColumn<ObservableList<String>, String> column = new TableColumn<>(
                            columns.get( i ) );

                    column.setCellValueFactory( (
                                    TableColumn.CellDataFeatures<ObservableList<String>, String> param ) -> 
                            new SimpleStringProperty( param.getValue().get( j ) ) );

                    table.getColumns().add( column );
                }

                ObservableList<ObservableList<String>> selected_data = FXCollections
                .observableArrayList();

                for ( int i = 0; i < data.size(); i++ )
                {
                    if ( Integer.parseInt( data.get( i ).get( 0 ) ) == newValue.getValue().getKey() )
                    {
                        selected_data.add( data.get( i ) );
                    }
                }
                table.setItems( selected_data );
                VBox vbox = new VBox( new Label( newValue.getValue().getValue() ), table );
                newValue.setGraphic( vbox );
            }
        } );

設定しないtreeView.setCellFactory(...)でください。問題は、アイテムのテキストを非表示にする方法です。

于 2015-06-01T09:02:41.177 に答える