如果您有一个
ListView<String>
,那么
ListView
中的每个项目都是一个
String
,而
CheckBoxListCell.forListView(...)
方法需要一个
Callback<String,ObservableValue<Boolean>>
。
在Java 8之前,
Callback<String,ObservableValue<Boolean>>
是定义单个方法的接口。
public ObservableValue<Boolean> call(String s) ;
因此,您需要一个实现该接口的东西,并传入该类型的对象。
文档还告诉您如何使用该回调:
给定类型为 T 的对象(这是从 ListView.items 列表中取出的值),将返回表示是否选择给定项目的 ObservableValue。该 ObservableValue 将被双向绑定(这意味着单元格中的复选框将根据用户交互设置/取消设置此属性,如果该属性在外部更改,则复选框将反映 ObservableValue 的状态)。
(由于您有一个 ListView<String>
,因此此处的 T
是 String
。)因此,对于列表视图中的每个元素(每个元素都是 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);
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);
}
}
请注意,在这种情况下,
BooleanProperty
可能会频繁地被创建和丢弃。实际上这可能不是问题,但这意味着第一个版本(有专门的模型类)可能执行得更好。
在Java 8中,您可以简化代码。由于
Callback
接口只有一个抽象方法(使其成为一个
函数式接口),您可以将
Callback<Item, ObservableValue<Boolean>>
看作一个函数,它接受一个
Item
并生成一个
ObservableValue<Boolean>
。因此,第一个示例中的单元格工厂可以使用
lambda表达式编写:
listView.setCellFactory(CheckBoxListCell.forListView(item -> item.onProperty()))
或者,更加简洁地使用方法引用:
listView.setCellFactory(CheckBoxListCell.forListView(Item::onProperty))