Как добавить CheckBox в TableView в JavaFX
В моем приложении Java Desktop у меня есть TableView, в котором я хочу иметь столбец с CheckBoxes.
Я нашел, где это было сделано http://www.jonathangiles.net/javafx/2.0/CellFactories/, но поскольку загрузка недоступна и потому, что я не знаю, как скоро Джонатан Джайлс ответит на мой адрес электронной почты. Я думал, что спрошу...
Как поместить CheckBox в ячейку моего TableView?
Ответы
Ответ 1
Вам нужно установить CellFactory в TableColumn.
Например:
Callback<TableColumn<TableData, Boolean>, TableCell<TableData, Boolean>> booleanCellFactory =
new Callback<TableColumn<TableData, Boolean>, TableCell<TableData, Boolean>>() {
@Override
public TableCell<TableData, Boolean> call(TableColumn<TableData, Boolean> p) {
return new BooleanCell();
}
};
active.setCellValueFactory(new PropertyValueFactory<TableData,Boolean>("active"));
active.setCellFactory(booleanCellFactory);
class BooleanCell extends TableCell<TableData, Boolean> {
private CheckBox checkBox;
public BooleanCell() {
checkBox = new CheckBox();
checkBox.setDisable(true);
checkBox.selectedProperty().addListener(new ChangeListener<Boolean> () {
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);
}
}
}
Ответ 2
Использует javafx.scene.control.cell.CheckBoxTableCell<S,T>
и проделанную работу!
ObservableList< TableColumn< RSSReader, ? >> columns =
_rssStreamsView.getColumns();
[...]
TableColumn< RSSReader, Boolean > loadedColumn = new TableColumn<>( "Loaded" );
loadedColumn.setCellValueFactory(
new Callback<CellDataFeatures<RSSReader,Boolean>,ObservableValue<Boolean>>(){
@Override public
ObservableValue<Boolean> call( CellDataFeatures<RSSReader,Boolean> p ){
return p.getValue().getCompleted(); }});
loadedColumn.setCellFactory(
new Callback<TableColumn<RSSReader,Boolean>,TableCell<RSSReader,Boolean>>(){
@Override public
TableCell<RSSReader,Boolean> call( TableColumn<RSSReader,Boolean> p ){
return new CheckBoxTableCell<>(); }});
[...]
columns.add( loadedColumn );
ОБНОВЛЕНИЕ: тот же код, используя Java 8 лямбда-выражения
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 );
Количество строк делится на два! (16 == > 8)
EDIT для добавления полнофункционального редактируемого примера
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<Os> view = new TableView<>();
final ObservableList<TableColumn<Os, ?>> columns = view.getColumns();
final TableColumn<Os, Boolean> nameColumn = new TableColumn<>( "Name" );
nameColumn.setCellValueFactory( new PropertyValueFactory<>( "name" ));
columns.add( nameColumn );
final TableColumn<Os, Boolean> loadedColumn = new TableColumn<>( "Delete" );
loadedColumn.setCellValueFactory( new PropertyValueFactory<>( "delete" ));
loadedColumn.setCellFactory( tc -> new CheckBoxTableCell<>());
columns.add( loadedColumn );
final ObservableList<Os> 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<Os> 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 );
}
}
Ответ 3
TableColumn select = new TableColumn("CheckBox");
select.setMinWidth(200);
select.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person, CheckBox>, ObservableValue<CheckBox>>() {
@Override
public ObservableValue<CheckBox> call(
TableColumn.CellDataFeatures<Person, CheckBox> arg0) {
Person user = arg0.getValue();
CheckBox checkBox = new CheckBox();
checkBox.selectedProperty().setValue(user.isSelected());
checkBox.selectedProperty().addListener(new ChangeListener<Boolean>() {
public void changed(ObservableValue<? extends Boolean> ov,
Boolean old_val, Boolean new_val) {
user.setSelected(new_val);
}
});
return new SimpleObjectProperty<CheckBox>(checkBox);
}
});
table.getColumns().addAll( select);
Ответ 4
Самое простое решение, вероятно, сделать это в FXML:
-
Сначала создайте класс ниже:
public class CheckBoxCellFactory<S, T>
implements Callback<TableColumn<S, T>, TableCell<S, T>> {
@Override public TableCell<S, T> call(TableColumn<S, T> p) {
return new CheckBoxTableCell<>();
}
}
-
Затем добавьте ячейку factory в ваш FXML:
<TableColumn text="Select" fx:id="selectColumn" >
<cellFactory>
<CheckBoxCellFactory/>
</cellFactory>
</TableColumn>
Вам также необходимо добавить импорт в FXML, например <?import com.assylias.factories.*?>
Бонус: вы можете сделать factory более настраиваемым, например, чтобы определить, где должен появиться флажок, добавив поля в класс CheckBoxCellFactory
, например:
private Pos alignment = Pos.CENTER;
public Pos getAlignment() { return alignment; }
public void setAlignment(Pos alignment) { this.alignment = alignment; }
И FXML:
<cellFactory>
<CheckBoxCellFactory alignment="BOTTOM_RIGHT"/>
</cellFactory>
Ответ 5
Маленький и простой.
row.setCellValueFactory(c -> new SimpleBooleanProperty(c.getValue().getIsDefault()));
row.setCellFactory(tc -> new CheckBoxTableCell<>());
Ответ 6
Существует очень простой способ сделать это, вам не нужно изменять класс модели с помощью SimpleBooleanProperty или что-то еще, просто выполните следующие действия:
1 - предположим, что у вас есть объект Person с методом isUnemployed:
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<TableColumn.CellDataFeatures<Person, CheckBox>, ObservableValue<CheckBox>> {
@Override
public ObservableValue<CheckBox> call(TableColumn.CellDataFeatures<Person, CheckBox> 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, поместите класс обратного вызова в свой столбец:
<TableView fx:id="personList" prefHeight="200.0" prefWidth="200.0">
<columns>
<TableColumn prefWidth="196.0" text="Unemployed">
<cellValueFactory>
<PersonUnemployedValueFactory/> <!--This is how the magic happens-->
</cellValueFactory>
</TableColumn>
...
</columns>
</TableView>
Не забудьте импортировать класс в свой FXML:
<?import org.yourcompany.yourapp.util.PersonUnemployedValueFactory?>
Без FXML сделайте это так:
TableColumn<Person, CheckBox> column = (TableColumn<Person, CheckBox>) personTable.getColumns().get(0);
column.setCellValueFactory(new PersonUnemployedValueFactory());
4 - Что он
Все должно работать так, как ожидалось, при установке значения bean при щелчке на флажке и правильном определении флажка, когда вы загружаете список элементов в таблице.
Ответ 7
Простейшим решением для установки флажка EDITABLE, связанного с моделью, является:
Предполагая, что у вас есть класс модели Person
с двумя полями, строка "name" и "выбранное" логическое значение:
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<Person, Boolean> checkBoxCol;
@FXML private TableColumn<Person, String> nameCol;
@Override
public void initialize(URL location, ResourceBundle resources) {
checkBoxCol.setCellFactory(
CheckBoxTableCell.forTableColumn(checkBoxCol)
);
checkBoxCol.setCellValueFactory(
new PropertyValueFactory<>("selected")
);
nameCol.setCellValueFactory(
new PropertyValueFactory<>("name")
);
}
Ответ 8
Вот полный рабочий пример, показывающий, как синхронизировать модель с представлением.....
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<TableData, Boolean> {
private CheckBox checkBox;
public BooleanCell() {
checkBox = new CheckBox();
checkBox.setDisable(true);
checkBox.selectedProperty().addListener(new ChangeListener<Boolean>() {
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<TableData> 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<TableData> 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<TableData> table = new TableView<>();
final ObservableList<TableColumn<TableData, ?>> columns = table.getColumns();
final TableModel model = getModel();
final TableColumn<TableData, String> 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<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
showModelLabel.setText(model.displayModel());
}});
final TableColumn<TableData, CheckBox> favoriteColumn = new TableColumn<TableData, CheckBox>("Favorite");
favoriteColumn.setCellValueFactory(
new Callback<TableColumn.CellDataFeatures<TableData, CheckBox>, ObservableValue<CheckBox>>() {
@Override
public ObservableValue<CheckBox> call(TableColumn.CellDataFeatures<TableData, CheckBox> arg0) {
TableData data = arg0.getValue();
CheckBox checkBox = new CheckBox();
checkBox.selectedProperty().setValue(data.isFavorite());
checkBox.selectedProperty().addListener(new ChangeListener<Boolean>() {
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>(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();
}
}
Ответ 9
Это способ сделать это
tbcSingleton.setCellValueFactory(data -> data.getValue().singletonProperty());
tbcSingleton.setCellFactory( param -> {
return new TableCell<FXMLController, Boolean>(){
{
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<FXMLController, ControllerType>() {
{
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, мой основной язык - испанский, и я его создаю для личного использования)
![введите описание изображения здесь]()
Ответ 10
Здесь находится сторонняя библиотека, которая сделает это http://www.jonathangiles.net/javafx/2.0/CellFactories/docs/api/net/jonathangiles/javafx/control/cell/tableview/CheckBoxTableCell.html
Ответ 11
для меня, работает с этим решением:
Callback<TableColumn, TableCell> checkboxCellFactory = new Callback<TableColumn, TableCell>() {
@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<RowData, Boolean> {
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<Boolean>() {
@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();
}
}
если вам не нужно делать флажок с событием редактирования