web-dev-qa-db-ja.com

チェックボックス付きのJavaFX 8、ListView

シンプルなリストビューを作成したいのですが。 setCellFactory()メソッドを使用できることはわかっていますが、正しく使用する方法がわかりません。これまでのところ:

myListView.setCellFactory(CheckBoxListCell.forListView(property));

「プロパティ」はコールバックと呼ばれるものです-コールバックは双方向の境界と関係があると思います。だから私は

property = new CallBack<String, ObservableValue<Boolean>>();

新しいコールバックを作成する場合、コンパイラーから通知されます。メソッド呼び出しを上書きする必要があります。

そしてここで私は行き詰まっています。そのメソッド呼び出しで何をしますか?実装することはできますが、何を返すか、何に使用すればよいですか? listItemのチェックボックスをクリックして、コンソールに「こんにちは」と表示させたいのですが。

11
jan

ListView<String>がある場合、ListViewの各項目はStringであり、 CheckBoxListCell.forListView(...) メソッドはCallback<String, ObservableValue<Boolean>>を予期します。

Java 8より前の考え方では、 Callback<String, ObservableValue<Boolean>> は単一のメソッドを定義するインターフェースであり、

public ObservableValue<Boolean> call(String s) ;

したがって、そのインターフェースを実装するものが必要であり、そのタイプのオブジェクトを渡します。

documentation は、そのコールバックの使用方法も示しています。

タイプTのオブジェクト(ListView.itemsリストから取得した値)を指定すると、指定したアイテムが選択されているかどうかを表すObservableValueを返すコールバック。このObservableValueは双方向にバインドされます(つまり、セルのCheckBoxがユーザーの操作に基づいてこのプロパティを設定または設定解除し、外部で変更された場合、CheckBoxはObservableValueの状態を反映します)。

ListView<String>があるため、ここではTStringです。)したがって、リストビューの各要素(各要素はString)に対して、コールバックを使用してチェックボックスの状態に双方向でバインドされるObservableValue<Boolean>を決定します。つまりチェックボックスがオンの場合、そのプロパティはtrueに設定され、オフの場合はfalseに設定されます。逆に、プロパティがプログラムでtrue(またはfalse)に設定されている場合、チェックボックスがオン(またはオフ)になります。

ここでの典型的な使用例は、ListViewの項目のタイプがその状態の一部としてBooleanPropertyを持つことです。したがって、通常は、これをデータを表すある種のカスタムクラスで使用します。次のように、内部Itemクラスを使用します。

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.CheckBoxListCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;

public class ListViewWithCheckBox extends Application {

    @Override
    public void start(Stage primaryStage) {
        ListView<Item> listView = new ListView<>();
        for (int i=1; i<=20; i++) {
            Item item = new Item("Item "+i, false);

            // observe item's on property and display message if it changes:
            item.onProperty().addListener((obs, wasOn, isNowOn) -> {
                System.out.println(item.getName() + " changed on state from "+wasOn+" to "+isNowOn);
            });

            listView.getItems().add(item);
        }

        listView.setCellFactory(CheckBoxListCell.forListView(new Callback<Item, ObservableValue<Boolean>>() {
            @Override
            public ObservableValue<Boolean> call(Item item) {
                return item.onProperty();
            }
        }));

        BorderPane root = new BorderPane(listView);
        Scene scene = new Scene(root, 250, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static class Item {
        private final StringProperty name = new SimpleStringProperty();
        private final BooleanProperty on = new SimpleBooleanProperty();

        public Item(String name, boolean on) {
            setName(name);
            setOn(on);
        }

        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 BooleanProperty onProperty() {
            return this.on;
        }

        public final boolean isOn() {
            return this.onProperty().get();
        }

        public final void setOn(final boolean on) {
            this.onProperty().set(on);
        }

        @Override
        public String toString() {
            return getName();
        }

    }

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

ListView<String>を本当に持っている場合、チェックボックスをクリックして設定しているプロパティがどうなるかは明確ではありません。ただし、チェックボックスの選択された状態にバインドする目的のためだけに、コールバックでの作成を停止するものはありません。

import javafx.application.Application;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.CheckBoxListCell;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.util.Callback;

public class ListViewWithStringAndCheckBox extends Application {

    @Override
    public void start(Stage primaryStage) {
        ListView<String> listView = new ListView<>();
        for (int i = 1; i <= 20 ; i++) {
            String item = "Item "+i ;
            listView.getItems().add(item);
        }

        listView.setCellFactory(CheckBoxListCell.forListView(new Callback<String, ObservableValue<Boolean>>() {
            @Override
            public ObservableValue<Boolean> call(String item) {
                BooleanProperty observable = new SimpleBooleanProperty();
                observable.addListener((obs, wasSelected, isNowSelected) -> 
                    System.out.println("Check box for "+item+" changed from "+wasSelected+" to "+isNowSelected)
                );
                return observable ;
            }
        }));

        BorderPane root = new BorderPane(listView);
        Scene scene = new Scene(root, 250, 400);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

この場合、BooleanPropertysが頻繁に作成および破棄される可能性があることに注意してください。これはおそらく実際には問題ではありませんが、専用のモデルクラスを使用した最初のバージョンの方がパフォーマンスが向上する可能性があります。

Java 8では、コードを簡略化できます。Callbackインターフェースには抽象メソッドが1つしかないため、関数型インターフェース)、Callback<Item, ObservableValue<Boolean>>は、Itemを使用してObservableValue<Boolean>を生成する関数と考えることができます。したがって、最初の例のセルファクトリは lambda式

    listView.setCellFactory(CheckBoxListCell.forListView(item -> item.onProperty()));

または、 メソッド参照 を使用してさらに簡潔に:

    listView.setCellFactory(CheckBoxListCell.forListView(Item::onProperty));
31
James_D
    listView.setCellFactory(CheckBoxListCell.forListView(new Callback<String, ObservableValue<Boolean>>() {
        @Override
        public ObservableValue<Boolean> call(String item) {
            BooleanProperty observable = new SimpleBooleanProperty();
            observable.addListener((obs, wasSelected, isNowSelected) -> 
                System.out.println("Check box for "+item+" changed from "+wasSelected+" to "+isNowSelected)
            );
            return observable ;
        }
    }));

ありがとうございました!これは私の問題を解決するのに役立ちます。

3
user4693191

以前の回答をありがとう。 setCellValueFactoryは不要であるという情報を見逃していますが、割り当てられた値はsetCellFactoryでも実行する必要があります。これが私のアプローチです(以前のソリューションから多くコピーされています)。

public TreeTableColumn<RowContainer, Boolean> treetblcolHide;
...
    treetblcolHide.setCellFactory(CheckBoxTreeTableCell.<RowContainer, Boolean>forTreeTableColumn(new Callback<Integer, ObservableValue<Boolean>>() {
        @Override
        public ObservableValue<Boolean> call(final Integer param) {
            final RowContainer rowitem = treetblcolHide.getTreeTableView().getTreeItem(param).getValue();
            BooleanProperty observable = new SimpleBooleanProperty();
            observable.addListener(new ChangeListener<Boolean>() {
                                       @Override
                                       public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
                                           rowitem.setHideMenuItem(newValue.toString());
                                       }
                                   }
            );
            observable.setValue(Boolean.parseBoolean(rowitem.getHideMenuItem()));
            return observable ;
        }
    }));
0
karnbo