How to add CheckBox's to a TableView in JavaFX

前端 未结 13 504
日久生厌
日久生厌 2020-11-30 00:32

In my Java Desktop Application I have a TableView in which I want to have a column with CheckBoxes.

I did find where this has been done http://www.jonathangiles.net/

相关标签:
13条回答
  • 2020-11-30 01:12

    This is what ended up working for me (note that the object in my model is Candidate and the checkbox determines whether or not they are excluded, hence isExcluded()):

    tableColumnCandidateExcluded.setCellValueFactory(
        c -> {
          Candidate candidate = c.getValue();
          CheckBox checkBox = new CheckBox();
          checkBox.selectedProperty().setValue(candidate.isExcluded());
          checkBox
              .selectedProperty()
              .addListener((ov, old_val, new_val) -> candidate.setExcluded(new_val));
          return new SimpleObjectProperty(checkBox);
        });
    
    0 讨论(0)
  • 2020-11-30 01:13

    This is the way is do it

    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) is necesary to prevent focus getting stuck on it.

    • setGraphic(null) is necesary to erase anything left behind after deleting an item or whenever the source list changes

    • cb.selectedProperty().addListener((obs,old,niu)->(your stuff...)); this is where you catch the new value of the CheckBox and do whatever you want with it.

    Heres another one with a ToggleGroup and 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);
            }
        };
    });
    

    I did some test and memory consumption is basically the same as using a ComboBoxTableCell

    This is how my little application looks (sry, my main language is Spanish and i build it for personal use)

    0 讨论(0)
  • 2020-11-30 01:15
    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);
    
    0 讨论(0)
  • 2020-11-30 01:16

    The simplest solution in order to have an EDITABLE checkbox linked to the model is:

    Assuming that you have a Person model class with two fields, a "name" string and the "selected" boolean value:

    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);
        }
    }
    

    All you have to do in the controller is:

    @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")
        );
    }
    
    0 讨论(0)
  • 2020-11-30 01:17

    You need to set a CellFactory on the TableColumn.

    For example:

    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);
                }
            }
        }
    
    0 讨论(0)
  • 2020-11-30 01:19

    Here's a 3rd party lib that will do it http://www.jonathangiles.net/javafx/2.0/CellFactories/docs/api/net/jonathangiles/javafx/control/cell/tableview/CheckBoxTableCell.html

    0 讨论(0)
提交回复
热议问题