JavaFX 8,带Checkboxes的ListView

jan*_*jan 11 java checkbox listview javafx

我想创建一个简单的ListView.我已经想通了我可以使用方法setCellFactory()但我不明白如何正确使用它们.到目前为止,我有:

myListView.setCellFactory(CheckBoxListCell.forListView(property));
Run Code Online (Sandbox Code Playgroud)

由于"属性"被称为回调 - 我认为Callback与双向边界有关.所以我创建了一个

property = new CallBack<String, ObservableValue<Boolean>>();
Run Code Online (Sandbox Code Playgroud)

我的编译器告诉我是否创建了一个新的Callback,我需要覆盖方法调用.

在这里,我被卡住了.该怎么办这个方法调用?我可以实现它,但我应该返回什么,或者使用它?我想在任何listItem上单击我的复选框,并在控制台中显示"hi".

Jam*_*s_D 30

如果你有a ListView<String>,则a中的每个项ListView都是a String,而CheckBoxListCell.forListView(...)方法需要a Callback<String, ObservableValue<Boolean>>.

在Java 8之前的思维方式中,a Callback<String, ObservableValue<Boolean>>是定义单个方法的接口,

public ObservableValue<Boolean> call(String s) ;
Run Code Online (Sandbox Code Playgroud)

因此,您需要一些实现该接口的东西,并传入该类型的对象.

文档还告诉您如何使用该回调:

给定类型为T的对象(从ListView.items列表中取出的值)的回调函数将返回一个ObservableValue,表示是否选择了给定项.此ObservableValue将双向绑定(意味着单元格中的CheckBox将根据用户交互设置/取消设置此属性,并且CheckBox将反映ObservableValue的状态,如果它在外部更改).

(因为你有一个ListView<String>,这里TString.)因此,对于列表视图中的每个元素(每个元素是a 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果你真的有一个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);
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下,BooleanProperty可能会经常创建和丢弃s.这在实践中可能不是问题,但它确实意味着具有专用模型类的第一个版本可能表现更好.

在Java 8中,您可以简化代码.因为Callback接口只有一个抽象方法(使其成为功能接口),所以你可以将a Callback<Item, ObservableValue<Boolean>>视为一个接受Item并生成一个的函数ObservableValue<Boolean>.因此,第一个示例中的单元工厂可以使用lambda表达式编写:

    listView.setCellFactory(CheckBoxListCell.forListView(item -> item.onProperty()));
Run Code Online (Sandbox Code Playgroud)

或者,更简洁地使用方法参考:

    listView.setCellFactory(CheckBoxListCell.forListView(Item::onProperty));
Run Code Online (Sandbox Code Playgroud)