为什么在 javafx 8 中选择 CheckboxTableCell 时 SelectedStateCallback 不起作用?
Why SelectedStateCallback doesn't work when selecting CheckboxTableCell in javafx 8?
我创建了显示问题的演示:
package util;
import javafx.application.Application;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.util.Callback;
public class Demo extends Application {
@Override
public void start(Stage stage) throws Exception {
ObservableList<Domain> data = FXCollections.observableArrayList(new Domain(true), new Domain(false), new Domain(true));
TableView<Domain> tableView = new TableView<>(data);
tableView.setEditable(true);
tableView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
TableColumn column = new TableColumn("Completed");
column.setEditable(true);
column.setCellValueFactory(new PropertyValueFactory<>("completed"));
column.setCellFactory(new Callback<TableColumn, TableCell>() {
public TableCell call(TableColumn p) {
CheckBoxTableCell checkBoxTableCell = new CheckBoxTableCell();
checkBoxTableCell.setSelectedStateCallback(new Callback<Integer, ObservableValue<Boolean>>() {
@Override
public ObservableValue<Boolean> call(Integer index) {
Domain domain = data.get(index);
System.out.println("index=" + index + " " + domain);
return domain.getCompleted();
}
});
return checkBoxTableCell;
}
});
tableView.getColumns().add(column);
Scene scene = new Scene(tableView, 300, 300);
stage.setTitle("ToDoList");
stage.setScene(scene);
stage.show();
}
public class Domain {
private SimpleBooleanProperty completed;
public Domain(boolean b) {
super();
this.completed = new SimpleBooleanProperty(b);
}
public SimpleBooleanProperty getCompleted() {
return completed;
}
public void setCompleted(SimpleBooleanProperty completed) {
this.completed = completed;
}
@Override
public String toString() {
return "Domain [completed=" + completed + "]";
}
}
public static void main(String[] args) {
launch(args);
}
}
因此,当您 运行 它时,您可以看到 table 带有复选框。我的问题是在单击特定复选框时获得正确的 Domain
对象。
Table 根据 Domain.completed
值显示复选框的状态。
单击复选框时,我想从 TableView.items
.
获取相应的域对象
我尝试使用 checkBoxTableCell.setSelectedStateCallback
但它只在启动时触发,而不是在我单击复选框时触发。
selectedStateCallback
提供了 BooleanProperty
,CheckBox
的选定状态(双向)绑定到该 BooleanProperty
。因此,在您的代码中,您已确保该复选框始终代表您在 Domain
对象中定义为 completed
的 属性 的值。因此,您可以只监听这些属性的变化:
for (int i = 0; i < data.size(); i++) {
final String item = "Item "+i ;
Domain d = data.get(i);
d.getCompleted().addListener((obs, wasCompleted, isNowCompleted) -> {
System.out.println("Completed state for "+item+" changed from "+wasCompleted+" to "+isNowCompleted);
});
}
相反,如果您从外部更改属性,复选框将更新:
Button selectAll = new Button("Select all");
selectAll.setOnAction(e ->
data.forEach(domain -> domain.getCompleted().set(true)));
顺便说一句,您的模型应该遵循 JavaFX Properties pattern。对于您当前的实现,如果您对列表中的对象调用 setCompleted(...)
,您将破坏复选框功能(因为复选框将绑定到错误的 属性)。您需要:
public class Domain {
private final BooleanProperty completed ;
public Domain(boolean completed) {
this.completed = new SimpleBooleanProperty(completed);
}
public BooleanProperty completedProperty() {
return completed ;
}
public final boolean isCompleted() {
return completedProperty().get();
}
public final void setCompleted(boolean completed) {
completedProperty().set(completed);
}
}
在你的 selectedStateCallback
中进行相应的更改:
return domain.completedProperty();
我创建了显示问题的演示:
package util;
import javafx.application.Application;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.util.Callback;
public class Demo extends Application {
@Override
public void start(Stage stage) throws Exception {
ObservableList<Domain> data = FXCollections.observableArrayList(new Domain(true), new Domain(false), new Domain(true));
TableView<Domain> tableView = new TableView<>(data);
tableView.setEditable(true);
tableView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
TableColumn column = new TableColumn("Completed");
column.setEditable(true);
column.setCellValueFactory(new PropertyValueFactory<>("completed"));
column.setCellFactory(new Callback<TableColumn, TableCell>() {
public TableCell call(TableColumn p) {
CheckBoxTableCell checkBoxTableCell = new CheckBoxTableCell();
checkBoxTableCell.setSelectedStateCallback(new Callback<Integer, ObservableValue<Boolean>>() {
@Override
public ObservableValue<Boolean> call(Integer index) {
Domain domain = data.get(index);
System.out.println("index=" + index + " " + domain);
return domain.getCompleted();
}
});
return checkBoxTableCell;
}
});
tableView.getColumns().add(column);
Scene scene = new Scene(tableView, 300, 300);
stage.setTitle("ToDoList");
stage.setScene(scene);
stage.show();
}
public class Domain {
private SimpleBooleanProperty completed;
public Domain(boolean b) {
super();
this.completed = new SimpleBooleanProperty(b);
}
public SimpleBooleanProperty getCompleted() {
return completed;
}
public void setCompleted(SimpleBooleanProperty completed) {
this.completed = completed;
}
@Override
public String toString() {
return "Domain [completed=" + completed + "]";
}
}
public static void main(String[] args) {
launch(args);
}
}
因此,当您 运行 它时,您可以看到 table 带有复选框。我的问题是在单击特定复选框时获得正确的 Domain
对象。
Table 根据 Domain.completed
值显示复选框的状态。
单击复选框时,我想从 TableView.items
.
我尝试使用 checkBoxTableCell.setSelectedStateCallback
但它只在启动时触发,而不是在我单击复选框时触发。
selectedStateCallback
提供了 BooleanProperty
,CheckBox
的选定状态(双向)绑定到该 BooleanProperty
。因此,在您的代码中,您已确保该复选框始终代表您在 Domain
对象中定义为 completed
的 属性 的值。因此,您可以只监听这些属性的变化:
for (int i = 0; i < data.size(); i++) {
final String item = "Item "+i ;
Domain d = data.get(i);
d.getCompleted().addListener((obs, wasCompleted, isNowCompleted) -> {
System.out.println("Completed state for "+item+" changed from "+wasCompleted+" to "+isNowCompleted);
});
}
相反,如果您从外部更改属性,复选框将更新:
Button selectAll = new Button("Select all");
selectAll.setOnAction(e ->
data.forEach(domain -> domain.getCompleted().set(true)));
顺便说一句,您的模型应该遵循 JavaFX Properties pattern。对于您当前的实现,如果您对列表中的对象调用 setCompleted(...)
,您将破坏复选框功能(因为复选框将绑定到错误的 属性)。您需要:
public class Domain {
private final BooleanProperty completed ;
public Domain(boolean completed) {
this.completed = new SimpleBooleanProperty(completed);
}
public BooleanProperty completedProperty() {
return completed ;
}
public final boolean isCompleted() {
return completedProperty().get();
}
public final void setCompleted(boolean completed) {
completedProperty().set(completed);
}
}
在你的 selectedStateCallback
中进行相应的更改:
return domain.completedProperty();