获取 JavaFX 表中的复选框值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/20879242/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Get Checkbox value in a table in JavaFX
提问by Ravindu
I have a table and it has a column with checkboxes.
我有一张桌子,它有一列带有复选框。
On a button click I want to find out which checkboxes are checked and which are not. So far I managed to create checkboxes in a table. The code is as follows.
单击按钮时,我想找出哪些复选框已选中,哪些未选中。到目前为止,我设法在表格中创建了复选框。代码如下。
public class TTEs implements Initializable {
@FXML
private TableView<TestObject> tableReport;
@FXML
private TableColumn<TestObject, String> name;
@FXML
private TableColumn<TestObject, Boolean> checkbox;
@FXML
public void getValues() {
//the method will get what check boxes are checked (this part is the problem)
}
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
ObservableList<TestObject> data = FXCollections.observableArrayList();
data.add(new TestObject("Test 1", true));
data.add(new TestObject("Test 2", false));
tableReport.setItems(data);
name.setCellValueFactory(new PropertyValueFactory<TestObject, String>("name"));
checkbox.setCellValueFactory(new PropertyValueFactory<TestObject, Boolean>("checked"));
checkbox.setCellFactory(new Callback<TableColumn<TestObject, Boolean>,
TableCell<TestObject, Boolean>>() {
public TableCell<TestObject, Boolean> call(TableColumn<TestObject, Boolean> p) {
return new CheckBoxTableCell<TestObject, Boolean>();
}
});
}
//CheckBoxTableCell for creating a CheckBox in a table cell
public static class CheckBoxTableCell<S, T> extends TableCell<S, T> {
private final CheckBox checkBox;
private ObservableValue<T> ov;
public CheckBoxTableCell() {
this.checkBox = new CheckBox();
this.checkBox.setAlignment(Pos.CENTER);
setAlignment(Pos.CENTER);
setGraphic(checkBox);
}
@Override public void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText(null);
setGraphic(null);
} else {
setGraphic(checkBox);
if (ov instanceof BooleanProperty) {
checkBox.selectedProperty().unbindBidirectional((BooleanProperty) ov);
}
ov = getTableColumn().getCellObservableValue(getIndex());
if (ov instanceof BooleanProperty) {
checkBox.selectedProperty().bindBidirectional((BooleanProperty) ov);
}
}
}
}
}
When I debug, I find that:
当我调试时,我发现:
ov = getTableColumn().getCellObservableValue(getIndex());
if (ov instanceof BooleanProperty) {
checkBox.selectedProperty().bindBidirectional((BooleanProperty) ov);
}
In the above condition, it never goes inside the if
statement, meaning that the ov
is not an instance of BooleanProperty
. But when I print the class of ov
,
在上述条件下,它永远不会进入if
语句内部,这意味着ov
不是 的实例BooleanProperty
。但是当我打印类时ov
,
System.out.println(ov.getClass().getName());
it prints as
它打印为
javafx.beans.property.ReadOnlyObjectWrapper
ReadOnlyObjectWrapper
is a subclass of BooleanProperty
, so why is the instanceof
check not working?
ReadOnlyObjectWrapper
是 的子类BooleanProperty
,那么为什么instanceof
检查不起作用?
回答by Reegan Miranda
package checkboxtablecelltest;
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.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.CheckBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;
/**
*
* @author reegan
*/
public class CheckBoxTableCellTest extends Application {
@Override
public void start(Stage primaryStage) {
final TableView<Person> tableView = new TableView<Person>();
tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
tableView.setItems(FXCollections.observableArrayList(
new Person("Robert", "Plant"),
new Person("Neil", "Young"),
new Person("Willie", "Nelson"),
new Person("Natalie", "Merchant")));
tableView.getItems().get(3).setVegetarian(true);
final TableColumn<Person, String> firstNameCol = new TableColumn<Person, String>("First Name");
final TableColumn<Person, String> lastNameCol = new TableColumn<Person, String>("Last Name");
final TableColumn<Person, Boolean> vegetarianCol = new TableColumn<Person, Boolean>("Vegetarian");
tableView.getColumns().addAll(firstNameCol, lastNameCol, vegetarianCol);
firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));
lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));
vegetarianCol.setCellValueFactory(new PropertyValueFactory<Person, Boolean>("vegetarian"));
vegetarianCol.setCellFactory(CheckBoxTableCell.forTableColumn(vegetarianCol));
vegetarianCol.setEditable(true);
tableView.setEditable(true);
final BorderPane root = new BorderPane();
root.setCenter(tableView);
final HBox controls = new HBox(5);
final Button infoButton = new Button("Show details");
infoButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
for (Person p : tableView.getItems()) {
System.out.printf("%s %s (%svegetarian)%n", p.getFirstName(),
p.getLastName(), p.isVegetarian() ? "" : "not ");
System.out.println(tableView.getSelectionModel().getSelectedItems());
}
System.out.println();
}
});
controls.getChildren().add(infoButton);
root.setBottom(controls);
Scene scene = new Scene(root, 300, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
public static class Person {
private StringProperty firstName;
private StringProperty lastName;
private BooleanProperty vegetarian;
public Person(String firstName, String lastName) {
this.firstName = new SimpleStringProperty(firstName);
this.lastName = new SimpleStringProperty(lastName);
this.vegetarian = new SimpleBooleanProperty(false);
}
public String getFirstName() {
return firstName.get();
}
public String getLastName() {
return lastName.get();
}
public boolean isVegetarian() {
return vegetarian.get();
}
public void setFirstName(String firstName) {
this.firstName.set(firstName);
}
public void setLastName(String lastName) {
this.lastName.set(lastName);
}
public void setVegetarian(boolean vegetarian) {
this.vegetarian.set(vegetarian);
}
public StringProperty firstNameProperty() {
return firstName;
}
public StringProperty lastNameProperty() {
return lastName;
}
public BooleanProperty vegetarianProperty() {
return vegetarian;
}
}
}
`
`
回答by OttPrime
Loop through the data model of your TableView
checking the boolean value that is bound to each CheckBox
.
循环TableView
检查绑定到 each 的布尔值的数据模型CheckBox
。
@FXML
public void getValues(){
ObservableList<TestObject> data = tableReport.getItems();
for (TestObject item : data){
//check the boolean value of each item to determine checkbox state
}
}
回答by Jens-Peter Haack
The main problem with your approach is the CheckBoxTableCell usage: A Cell is a heavily reused 'rendering' machine. If you try to add a state, like the CheckBox variable, you are in trouble.
您的方法的主要问题是 CheckBoxTableCell 的使用:Cell 是重用的“渲染”机器。如果您尝试添加状态,例如 CheckBox 变量,则会遇到麻烦。
The most simple fix to your problem is to allocate the checkbox each time. The following code provides a working checkbox column:
解决问题的最简单方法是每次分配复选框。以下代码提供了一个有效的复选框列:
public static class Member {
private StringProperty myName;
private BooleanProperty myCheck;
public Member(String name, boolean checked) {
myName = new SimpleStringProperty(name);
myCheck = new SimpleBooleanProperty(checked);
}
public StringProperty nameProperty() { return myName; }
public BooleanProperty checkProperty() { return myCheck; }
}
VBox testTable6(VBox box) { // check box bind to cell property
ObservableList<Member> members = FXCollections.observableArrayList();
members.add(new Member("peter", true));
members.add(new Member("gernot", true));
members.add(new Member("fritz", false));
TableView<Member> table = new TableView<Member>();
table.prefHeightProperty().bind(box.heightProperty());
table.setItems(members);
TableColumn<Member,String> c1 = new TableColumn<Member,String>("Name");
c1.setCellValueFactory(new PropertyValueFactory<Member,String>("name"));
table.getColumns().add(c1);
TableColumn<Member,Boolean> c2 = new TableColumn<Member,Boolean>("Membercheck");
c2.setCellValueFactory(new PropertyValueFactory<Member,Boolean>("check"));
c2.setCellFactory(column -> new TableCell<Member, Boolean>(){
public void updateItem(Boolean check, boolean empty) {
super.updateItem(check, empty);
if (check == null || empty) {
setGraphic(null);
} else {
CheckBox box = new CheckBox();
BooleanProperty checked = (BooleanProperty)column.getCellObservableValue(getIndex());
box.setSelected(checked.get());
box.selectedProperty().bindBidirectional(checked);
setGraphic(box);
}
}
}
);
table.getColumns().add(c2);
box.getChildren().addAll(table);
return box;
}
As the bidirectional property binding is a weak binding, carbage collection will work properly even if you are unable to unbind explicitely.
由于双向属性绑定是弱绑定,即使您无法明确解除绑定,carbage 收集也能正常工作。
The unchecked cast to BooleanProperty is not a good style anyhow here, sorry. Consider to access the whole object using:
无论如何,对 BooleanProperty 的未经检查的强制转换在这里不是一个好的风格,抱歉。考虑使用以下方法访问整个对象:
...
Member member = table.getItems().get(getIndex());
box.setSelected(member.checkProperty().get());
box.selectedProperty().bindBidirectional(member.checkProperty());
....
by the way: the birdeirectional binding will NOT set the selected property in that moment, only if it is changed afterward! so the explicit assignment:
顺便说一句:birdeirectional 绑定不会在那一刻设置 selected 属性,只有在之后更改它!所以显式赋值:
box.setSelected(member.checkProperty().get());
is mandatory here.
这里是强制性的。
回答by gotozero
Tested on Java 8.
Only 4 simple things.
在 Java 8 上测试。
只有 4 件简单的事情。
1) Make CheckBoxCellFactory class. Put somewhere in your project.
1) 创建 CheckBoxCellFactory 类。放在你的项目中的某个地方。
public class CheckBoxCellFactory implements Callback {
@Override
public TableCell call(Object param) {
CheckBoxTableCell<Person,Boolean> checkBoxCell = new CheckBoxTableCell();
return checkBoxCell;
}
}
2) Your model class. Person for example.
2)你的模型类。以人为例。
public static class Person {
private SimpleBooleanProperty checked = new SimpleBooleanProperty(false);
// other columns here
public SimpleBooleanProperty checkedProperty() {
return this.checked;
}
public java.lang.Boolean getChecked() {
return this.checkedProperty().get();
}
public void setChecked(final java.lang.Boolean checked) {
this.checkedProperty().set(checked);
}
// getter/setter for other columns
}
3) Made modifications in your fxml file. The section of your TableView -> TableColumn gonna look like this:
3) 在您的 fxml 文件中进行了修改。您的 TableView -> TableColumn 的部分将如下所示:
<TableColumn fx:id="checkBoxTableColumn" maxWidth="34.0" minWidth="26.0" prefWidth="34.0" resizable="false" sortable="false">
<cellValueFactory><PropertyValueFactory property="checked" /></cellValueFactory>
<cellFactory><partarch.fx.CheckBoxCellFactory /></cellFactory>
</TableColumn>
4) If you want to make your checkbox being editable
4) 如果你想让你的复选框可编辑
- 4.1 Open fxml in the Scene Builder.
- 4.2 Select checkBox column and then check "Editable" property in the Properties pane.
- 4.3 Select TableView containing your checkbox and do the same(check "Editable" property in the Properties pane).
- 4.1 在场景生成器中打开 fxml。
- 4.2 选择复选框列,然后在属性窗格中选中“可编辑”属性。
- 4.3 选择包含您的复选框的 TableView 并执行相同的操作(选中“属性”窗格中的“可编辑”属性)。
回答by user1210708
A little off topic - but in Kotlin you can do this:
有点离题 - 但在 Kotlin 中你可以这样做:
isPvtColumn.cellFactory = Callback { CheckBoxTableCell<KeyWithProperties, Boolean>() }
isPvtColumn.cellValueFactory = Callback {
a -> a.value.private
}
This is all there is to it
这就是它的全部
回答by Antonio Gabriel Andrade
In the initialize method, switch your custom factory for the one provided by JavaFX:
在 initialize 方法中,将自定义工厂切换为 JavaFX 提供的工厂:
@Override
public void initialize(URL arg0, ResourceBundle arg1) {
ObservableList<TestObject> data = FXCollections.observableArrayList();
data.add(new TestObject("Test 1", true));
data.add(new TestObject("Test 2", false));
tableReport.setItems(data);
name.setCellValueFactory(new PropertyValueFactory<TestObject, String>("name"));
checkbox.setCellValueFactory(new PropertyValueFactory<TestObject, Boolean>("checked"));
checkbox.setCellFactory(
CheckBoxTableCell.forTableColumn(checkbox)
);
}
Now your data is binded to the column and you can iterate over the items and check for the "checked" field:
现在您的数据已绑定到该列,您可以遍历项目并检查“已检查”字段:
@FXML
public void getValues(){
ObservableList<TestObject> data = tableReport.getItems();
for (TestObject item : data){
//check the boolean value of each item to determine checkbox state
}
}