如何将CheckBox添加到JavaFX中的TableView

在我的Java桌面应用程序中,我有一个TableView,其中我想要一个包含CheckBoxes的列。

我确实找到了这个已经完成的地方http://www.jonathangiles.net/javafx/2.0/CellFactories/但由于下载不可用,因为我不知道Jonathan Giles多久会回复我的电子邮件我以为我’请问……

如何将CheckBox放入TableView的单元格中?

您需要在TableColumn上设置CellFactory。

例如:

Callback, TableCell> booleanCellFactory = new Callback, TableCell>() { @Override public TableCell call(TableColumn p) { return new BooleanCell(); } }; active.setCellValueFactory(new PropertyValueFactory("active")); active.setCellFactory(booleanCellFactory); class BooleanCell extends TableCell { private CheckBox checkBox; public BooleanCell() { checkBox = new CheckBox(); checkBox.setDisable(true); checkBox.selectedProperty().addListener(new ChangeListener () { public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { if(isEditing()) commitEdit(newValue == null ? false : newValue); } }); this.setGraphic(checkBox); this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); this.setEditable(true); } @Override public void startEdit() { super.startEdit(); if (isEmpty()) { return; } checkBox.setDisable(false); checkBox.requestFocus(); } @Override public void cancelEdit() { super.cancelEdit(); checkBox.setDisable(true); } public void commitEdit(Boolean value) { super.commitEdit(value); checkBox.setDisable(true); } @Override public void updateItem(Boolean item, boolean empty) { super.updateItem(item, empty); if (!isEmpty()) { checkBox.setSelected(item); } } } 

使用javafx.scene.control.cell.CheckBoxTableCell并完成工作!

  ObservableList< TableColumn< RSSReader, ? >> columns = _rssStreamsView.getColumns(); [...] TableColumn< RSSReader, Boolean > loadedColumn = new TableColumn<>( "Loaded" ); loadedColumn.setCellValueFactory( new Callback,ObservableValue>(){ @Override public ObservableValue call( CellDataFeatures p ){ return p.getValue().getCompleted(); }}); loadedColumn.setCellFactory( new Callback,TableCell>(){ @Override public TableCell call( TableColumn p ){ return new CheckBoxTableCell<>(); }}); [...] columns.add( loadedColumn ); 

更新:使用Java 8 lambda表达式的相同代码

  ObservableList< TableColumn< RSSReader, ? >> columns = _rssStreamsView.getColumns(); [...] TableColumn< RSSReader, Boolean > loadedColumn = new TableColumn<>( "Loaded" ); loadedColumn.setCellValueFactory( f -> f.getValue().getCompleted()); loadedColumn.setCellFactory( tc -> new CheckBoxTableCell<>()); [...] columns.add( loadedColumn ); 

行数除以2! (16 ==> 8)

更新:使用Java 10“var”上下文单词的相同代码

  var columns = _rssStreamsView.getColumns(); [...] var loadedColumn = new TableColumn( "Loaded" ); loadedColumn.setCellValueFactory( f -> f.getValue().getCompleted()); loadedColumn.setCellFactory( tc -> new CheckBoxTableCell<>()); [...] columns.add( loadedColumn ); 

编辑添加完整function的可编辑示例(Java 8)

 public class Os { private final StringProperty name = new SimpleStringProperty(); private final BooleanProperty delete = new SimpleBooleanProperty(); public Os( String nm, boolean del ) { name .set( nm ); delete.set( del ); } public StringProperty nameProperty () { return name; } public BooleanProperty deleteProperty() { return delete; } } public class FxEditableCheckBox extends Application { @Override public void start( Stage stage ) throws Exception { final TableView view = new TableView<>(); final ObservableList> columns = view.getColumns(); final TableColumn nameColumn = new TableColumn<>( "Name" ); nameColumn.setCellValueFactory( new PropertyValueFactory<>( "name" )); columns.add( nameColumn ); final TableColumn loadedColumn = new TableColumn<>( "Delete" ); loadedColumn.setCellValueFactory( new PropertyValueFactory<>( "delete" )); loadedColumn.setCellFactory( tc -> new CheckBoxTableCell<>()); columns.add( loadedColumn ); final ObservableList items = FXCollections.observableArrayList( new Os( "Microsoft Windows 3.1" , true ), new Os( "Microsoft Windows 3.11" , true ), new Os( "Microsoft Windows 95" , true ), new Os( "Microsoft Windows NT 3.51", true ), new Os( "Microsoft Windows NT 4" , true ), new Os( "Microsoft Windows 2000" , true ), new Os( "Microsoft Windows Vista" , true ), new Os( "Microsoft Windows Seven" , false ), new Os( "Linux all versions :-)" , false )); view.setItems( items ); view.setEditable( true ); final Button delBtn = new Button( "Delete" ); delBtn.setMaxWidth( Double.MAX_VALUE ); delBtn.setOnAction( e -> { final Set del = new HashSet<>(); for( final Os os : view.getItems()) { if( os.deleteProperty().get()) { del.add( os ); } } view.getItems().removeAll( del ); }); stage.setScene( new Scene( new BorderPane( view, null, null, delBtn, null ))); BorderPane.setAlignment( delBtn, Pos.CENTER ); stage.show(); } public static void main( String[] args ) { launch( args ); } } 

编辑添加完整function的可编辑示例(Java 10)

 public class Os { private final StringProperty name = new SimpleStringProperty(); private final BooleanProperty delete = new SimpleBooleanProperty(); public Os( String nm, boolean del ) { name .set( nm ); delete.set( del ); } public StringProperty nameProperty () { return name; } public BooleanProperty deleteProperty() { return delete; } } public class FxEditableCheckBoxJava10 extends Application { @Override public void start( Stage stage ) throws Exception { final var view = new TableView(); final var columns = view.getColumns(); final var nameColumn = new TableColumn( "Name" ); nameColumn.setCellValueFactory( new PropertyValueFactory<>( "name" )); columns.add( nameColumn ); final var loadedColumn = new TableColumn( "Delete" ); loadedColumn.setCellValueFactory( new PropertyValueFactory<>( "delete" )); loadedColumn.setCellFactory( tc -> new CheckBoxTableCell<>()); columns.add( loadedColumn ); final var items = FXCollections.observableArrayList( new Os( "Microsoft Windows 3.1" , true ), new Os( "Microsoft Windows 3.11" , true ), new Os( "Microsoft Windows 95" , true ), new Os( "Microsoft Windows NT 3.51", true ), new Os( "Microsoft Windows NT 4" , true ), new Os( "Microsoft Windows 2000" , true ), new Os( "Microsoft Windows Vista" , true ), new Os( "Microsoft Windows Seven" , false ), new Os( "Linux all versions :-)" , false )); view.setItems( items ); view.setEditable( true ); final var delBtn = new Button( "Delete" ); delBtn.setMaxWidth( Double.MAX_VALUE ); delBtn.setOnAction( e -> { final var del = new HashSet(); for( final var os : view.getItems()) { if( os.deleteProperty().get()) { del.add( os ); } } view.getItems().removeAll( del ); }); stage.setScene( new Scene( new BorderPane( view, null, null, delBtn, null ))); BorderPane.setAlignment( delBtn, Pos.CENTER ); stage.show(); } public static void main( String[] args ) { launch( args ); } } 
 TableColumn select = new TableColumn("CheckBox"); select.setMinWidth(200); select.setCellValueFactory(new Callback, ObservableValue>() { @Override public ObservableValue call( TableColumn.CellDataFeatures arg0) { Person user = arg0.getValue(); CheckBox checkBox = new CheckBox(); checkBox.selectedProperty().setValue(user.isSelected()); checkBox.selectedProperty().addListener(new ChangeListener() { public void changed(ObservableValue ov, Boolean old_val, Boolean new_val) { user.setSelected(new_val); } }); return new SimpleObjectProperty(checkBox); } }); table.getColumns().addAll( select); 

最简单的解决方案可能是在FXML中完成:

  1. 首先创建以下类:

     public class CheckBoxCellFactory implements Callback, TableCell> { @Override public TableCell call(TableColumn p) { return new CheckBoxTableCell<>(); } } 
  2. 然后在FXML中包含一个单元工厂:

          

您还需要在FXML中添加导入,例如


额外奖励:您可以通过向CheckBoxCellFactory类添加字段来使工厂更具可自定义性,例如确定复选框的显示位置,例如:

 private Pos alignment = Pos.CENTER; public Pos getAlignment() { return alignment; } public void setAlignment(Pos alignment) { this.alignment = alignment; } 

和FXML:

    

小而简单。

 row.setCellValueFactory(c -> new SimpleBooleanProperty(c.getValue().getIsDefault())); row.setCellFactory(tc -> new CheckBoxTableCell<>()); 

有一种非常简单的方法,您不需要使用SimpleBooleanProperty或其他任何方式修改模型类,只需按照以下步骤操作:

1 – 假设您有一个带有isUnemployed方法的“Person”对象:

 public class Person { private String name; private Boolean unemployed; public String getName(){return this.name;} public void setName(String name){this.name = name;} public Boolean isUnemployed(){return this.unemployed;} public void setUnemployed(Boolean unemployed){this.unemployed = unemployed;} } 

2 – 创建回调类

 import javafx.beans.property.SimpleObjectProperty; import javafx.beans.value.ObservableValue; import javafx.scene.control.CheckBox; import javafx.scene.control.TableColumn; import javafx.util.Callback; public class PersonUnemployedValueFactory implements Callback, ObservableValue> { @Override public ObservableValue call(TableColumn.CellDataFeatures param) { Person person = param.getValue(); CheckBox checkBox = new CheckBox(); checkBox.selectedProperty().setValue(person.isUnemployed()); checkBox.selectedProperty().addListener((ov, old_val, new_val) -> { person.setUnemployed(new_val); }); return new SimpleObjectProperty<>(checkBox); } } 

3 – 将回调绑定到表列

如果您使用FXML,请将回调类放在列中:

         ...   

不要忘记在FXML中导入该类:

  

没有FXML,就这样做:

 TableColumn column = (TableColumn) personTable.getColumns().get(0); column.setCellValueFactory(new PersonUnemployedValueFactory()); 

4 – 就是这样

一切都应该按预期工作,当您单击复选框时将值设置为支持bean,并在您加载表中的项目列表时正确设置复选框值。

为了将EDITABLE复选框链接到模型,最简单的解决方案是:

假设您有一个包含两个字段的Person模型类,“name”字符串和“selected”布尔值:

 public class Person { private final SimpleBooleanProperty selected; private final SimpleStringProperty name; public Person(String name) { this.selected = new SimpleBooleanProperty(false); this.name = new SimpleStringProperty(name); } public boolean isSelected() { return selected.get(); } public SimpleBooleanProperty selectedProperty() { return selected; } public void setSelected(boolean selected) { this.selected.set(selected); } public String getName() { return name.get(); } public SimpleStringProperty nameProperty() { return name; } public void setName(String name) { this.name.set(name); } } 

您只需在控制器中执行以下操作:

 @FXML private TableColumn checkBoxCol; @FXML private TableColumn nameCol; @Override public void initialize(URL location, ResourceBundle resources) { checkBoxCol.setCellFactory( CheckBoxTableCell.forTableColumn(checkBoxCol) ); checkBoxCol.setCellValueFactory( new PropertyValueFactory<>("selected") ); nameCol.setCellValueFactory( new PropertyValueFactory<>("name") ); } 

这是一个完整的工作示例,展示了如何使模型与视图保持同步…..

 package org.pauquette.example; import javafx.application.Application; import javafx.beans.property.SimpleBooleanProperty; import javafx.beans.property.SimpleObjectProperty; import javafx.beans.property.SimpleStringProperty; import javafx.beans.value.ChangeListener; import javafx.beans.value.ObservableValue; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.event.ActionEvent; import javafx.event.EventHandler; import javafx.scene.Scene; import javafx.scene.control.Button; import javafx.scene.control.CheckBox; import javafx.scene.control.ContentDisplay; import javafx.scene.control.Label; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; import javafx.scene.layout.HBox; import javafx.scene.layout.VBox; import javafx.stage.Stage; import javafx.util.Callback; public class CheckBoxExample extends Application { class BooleanCell extends TableCell { private CheckBox checkBox; public BooleanCell() { checkBox = new CheckBox(); checkBox.setDisable(true); checkBox.selectedProperty().addListener(new ChangeListener() { public void changed(ObservableValue observable, Boolean oldValue, Boolean newValue) { if (isEditing()) commitEdit(newValue == null ? false : newValue); } }); this.setGraphic(checkBox); this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY); this.setEditable(true); } @Override public void cancelEdit() { super.cancelEdit(); checkBox.setDisable(true); } public void commitEdit(Boolean value) { super.commitEdit(value); checkBox.setDisable(true); } @Override public void startEdit() { super.startEdit(); if (isEmpty()) { return; } checkBox.setDisable(false); checkBox.requestFocus(); } @Override public void updateItem(Boolean item, boolean empty) { super.updateItem(item, empty); if (!isEmpty()) { checkBox.setSelected(item); } } } // Pojo class. A Javabean public class TableData { SimpleBooleanProperty favorite; SimpleStringProperty stooge; // A javabean typically has a zero arg constructor // https://docs.oracle.com/javase/tutorial/javabeans/ public TableData() { } // but can have others also public TableData(String stoogeIn, Boolean favoriteIn) { stooge = new SimpleStringProperty(stoogeIn); favorite = new SimpleBooleanProperty(favoriteIn); } /** * @return the stooge */ public String getStooge() { return stooge.get(); } /** * @return the favorite */ public Boolean isFavorite() { return favorite.get(); } /** * @param favorite * the favorite to set */ public void setFavorite(Boolean favorite) { this.favorite.setValue(favorite); } /** * @param stooge * the stooge to set */ public void setStooge(String stooge) { this.stooge.setValue(stooge); } } // Model class - The model in mvc // Typically a representation of a database or nosql source public class TableModel { ObservableList stooges = FXCollections.observableArrayList(); public TableModel() { stooges.add(new TableData("Larry", false)); stooges.add(new TableData("Moe", true)); stooges.add(new TableData("Curly", false)); } public String displayModel() { StringBuilder sb=new StringBuilder(); for (TableData stooge : stooges) { sb.append(stooge.getStooge() + "=" + stooge.isFavorite() + "|"); } return sb.toString(); } /** * @return the stooges */ public ObservableList getStooges() { return stooges; } public void updateStooge(TableData dataIn) { int index=stooges.indexOf(dataIn); stooges.set(index, dataIn); } } public static void main(String[] args) { launch(args); } private TableModel model; private TableModel getModel() { if (model == null) { model = new TableModel(); } return model; } @Override public void start(Stage primaryStage) throws Exception { final VBox view=new VBox(10); final TableView table = new TableView<>(); final ObservableList> columns = table.getColumns(); final TableModel model = getModel(); final TableColumn stoogeColumn = new TableColumn<>("Stooge"); stoogeColumn.setCellValueFactory(new PropertyValueFactory<>("stooge")); columns.add(stoogeColumn); final Button showModelButton = new Button("Show me the Model, woo,woo,woo"); final Label showModelLabel = new Label("Model? Whats that?"); showModelButton.setOnAction(new EventHandler() { @Override public void handle(ActionEvent event) { showModelLabel.setText(model.displayModel()); }}); final TableColumn favoriteColumn = new TableColumn("Favorite"); favoriteColumn.setCellValueFactory( new Callback, ObservableValue>() { @Override public ObservableValue call(TableColumn.CellDataFeatures arg0) { TableData data = arg0.getValue(); CheckBox checkBox = new CheckBox(); checkBox.selectedProperty().setValue(data.isFavorite()); checkBox.selectedProperty().addListener(new ChangeListener() { public void changed(ObservableValue ov, Boolean old_val, Boolean new_val) { data.setFavorite(new_val); checkBox.setSelected(new_val); model.updateStooge(data); } }); return new SimpleObjectProperty(checkBox); } }); columns.add(favoriteColumn); table.setItems(model.getStooges()); HBox hbox = new HBox(10); hbox.getChildren().addAll(showModelButton,showModelLabel); view.getChildren().add(hbox); view.getChildren().add(table); Scene scene = new Scene(view, 640, 380); primaryStage.setScene(scene); primaryStage.show(); } } 

这就是这样做的方式

 tbcSingleton.setCellValueFactory(data -> data.getValue().singletonProperty()); tbcSingleton.setCellFactory( param -> { return new TableCell(){ { setAlignment(Pos.CENTER); } protected void updateItem(Boolean item, boolean empty){ if(!empty && item!=null) { CheckBox cb = new CheckBox(); cb.setSelected(item); cb.setFocusTraversable(false); cb.selectedProperty().addListener((obs,old,niu)->listaFXMLController.get(getIndex()).setSingleton(niu)); setGraphic(cb); }else setGraphic(null); } }; }); 
  • cb.setFocusTraversable(false)是必要的,以防止焦点卡在上面。

  • setGraphic(null)必须删除删除项目后或源列表更改时遗留的任何内容

  • cb.selectedProperty()。addListener((obs,old,niu) – >(你的东西……)); 这是您捕获CheckBox的新值并随意执行任何操作的地方。

另一个是ToggleGroup和ToggleButtons

 tbcTipoControlador.setCellValueFactory(data -> data.getValue().controllerTypeProperty()); tbcTipoControlador.setCellFactory( param -> { return new TableCell() { { setAlignment(Pos.CENTER); } protected void updateItem(ControllerType item, boolean empty){ if(!empty && item!=null) { ToggleButton tbModal = new ToggleButton("Modal"); tbModal.selectedProperty().addListener((obs,old,niu)->{ if(niu) listaFXMLController.get(getIndex()).setControllerType(ControllerType.MODAL); }); tbModal.setSelected(item.equals(ControllerType.MODAL)); ToggleButton tbPlain = new ToggleButton("Plain"); tbPlain.selectedProperty().addListener((obs,old,niu)->{ if(niu) listaFXMLController.get(getIndex()).setControllerType(ControllerType.PLAIN); }); tbPlain.setSelected(item.equals(ControllerType.PLAIN)); ToggleButton tbApplication= new ToggleButton("Application"); tbApplication.selectedProperty().addListener((obs,old,niu)->{ if(niu) listaFXMLController.get(getIndex()).setControllerType(ControllerType.APPLICATION); }); tbApplication.setSelected(item.equals(ControllerType.APPLICATION)); ToggleGroup gp = new ToggleGroup(); tbModal.setFocusTraversable(false); tbPlain.setFocusTraversable(false); tbApplication.setFocusTraversable(false); tbModal.setPrefWidth(120); tbPlain.setPrefWidth(120); tbApplication.setPrefWidth(120); gp.getToggles().addAll(tbModal,tbPlain,tbApplication); HBox hb = new HBox(); hb.setAlignment(Pos.CENTER); hb.getChildren().addAll(tbModal,tbPlain,tbApplication); setGraphic(hb); }else setGraphic(null); } }; }); 

我做了一些测试和内存消耗与使用ComboBoxTableCell基本相同

这就是我的小应用程序的外观(sry,我的主要语言是西class牙语,我将其构建为个人用途) 在此处输入图像描述

从以前的答案中汲取灵感,我认为这是最短的版本。

 checkBoxColumn.setCellValueFactory(c -> { c.getValue().booleanProperty().addListener((ch, o, n) -> { // do something }); return c.getValue().booleanProperty(); }); checkBoxColumn.setCellFactory(CheckBoxTableCell.forTableColumn(checkBoxColumn)); 

这是一个第三方库,它将做到这一点http://www.jonathangiles.net/javafx/2.0/CellFactories/docs/api/net/jonathangiles/javafx/control/cell/tableview/CheckBoxTableCell.html

对我来说,使用此解决方案:

 Callback checkboxCellFactory = new Callback() { @Override public TableCell call(TableColumn p) { return new CheckboxCell(); } }; TableColumn selectColumn = (TableColumn) tbvDatos.getColumns().get(1); selectColumn.setCellValueFactory(new PropertyValueFactory("selected")); selectColumn.setCellFactory(checkboxCellFactory); 

和tableCell:

 public class CheckboxCell extends TableCell { CheckBox checkbox; @Override protected void updateItem(Boolean arg0, boolean arg1) { super.updateItem(arg0, arg1); paintCell(); } private void paintCell() { if (checkbox == null) { checkbox = new CheckBox(); checkbox.selectedProperty().addListener(new ChangeListener() { @Override public void changed(ObservableValue ov, Boolean old_val, Boolean new_val) { setItem(new_val); ((RowData)getTableView().getItems().get(getTableRow().getIndex())).setSelected(new_val); } }); } checkbox.setSelected(getValue()); setText(null); setGraphic(checkbox); } private Boolean getValue() { return getItem() == null ? false : getItem(); } } 

如果你不需要使用编辑事件制作复选框