如何将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 extends Boolean> 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 extends Boolean> ov, Boolean old_val, Boolean new_val) { user.setSelected(new_val); } }); return new SimpleObjectProperty(checkBox); } }); table.getColumns().addAll( select);
最简单的解决方案可能是在FXML中完成:
-
首先创建以下类:
public class CheckBoxCellFactory
implements Callback, TableCell > { @Override public TableCellcall(TableColumnp) { return new CheckBoxTableCell<>(); } } -
然后在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 extends Boolean> 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 extends Boolean> 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 extends Boolean> 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(); } }
如果你不需要使用编辑事件制作复选框