Checkbox selected bind with TableView - javafx

How to bind with TableView selection model with checkbox isSelected in table view.In manually (using mouse multiple select) select the item in tableview
ObservableList<T> observableList = tableView.getSelectionModel().getSelectedItems();
System.out.println(observableList);
how to bind checkbox with tableview
box.selectedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
if (t1) {
Object object = getTableView().getItems().get(getTableRow().getIndex());
objects.add(object);
getTableView().getItems().set(getTableRow().getIndex(), object);
tableView.getSelectionModel().getSelectedItem(); //tableView.getSelectionModel().setSelectedIndex(getTableRow().getIndex());
} else {
Object object = getTableView().getItems().get(getTableRow().getIndex());
objects.remove(object);
}
System.out.println(objects);
}
});
if Checkbox is selected in row that row item bind with getSelectionModel().getSelectedItems() or how set manually setSelectedItems in tableView

Add to this line in box.selectedProperty().addListener()
tableView.getSelectionModel().select(getTableRow().getIndex());
box.selectedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
if (t1) {
tableView.getSelectionModel().select(getTableRow().getIndex());
} else {
tableView.getSelectionModel().clearSelection(getTableRow().getIndex());
}
}
});

Related

Cannot save selected checkbox to variable

I am a problem with javafx. I have GridPane with about 40 CheckBoxes. I need make user can select only one CheckBox and selected CheckBox is saved to a variable.
This is method for work with checkboxes:
public static class createBet {
public static CheckBox bet;
public static CheckBox isBet(CheckBox[] group, int finalI, AnchorPane resultBlock) {
for (CheckBox j : group) {
if (j.equals(bet)) {
j.setSelected(false);
}
}
ObservableList resultLabels = resultBlock.getChildren();
Label label_num = (Label)resultLabels.get(0);
Label label_win = (Label)resultLabels.get(1);
if (group[finalI].isSelected()) {
bet = group[finalI];
resultBlock.setStyle("-fx-border-color: black;");
label_num.setStyle("-fx-text-fill: black");
label_win.setStyle("-fx-text-fill: black");
}
else {
bet = null;
resultBlock.setStyle("-fx-border-color: gray");
label_num.setStyle("-fx-text-fill: gray");
label_win.setStyle("-fx-text-fill: gray");
}
return bet;
}
}
This is a class for final variables:
public class bets {
public CheckBox numberBet = null;
public CheckBox colorBet = null;
public CheckBox evenBet = null;
}
There I use this classes:
//(block with variables and links to FXML)
createBet bet = new createBet();
bets bets = new bets();
for (int i = 0; i < numbersGroup.length; i++) {
int finalI = i;
numbersGroup[i].selectedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
bets.numberBet = createBet.isBet(numbersGroup, finalI, resultNum);
}
});
}
}
}
Checkboxes are selected correctly, but variables for selected CheckBox (class bets) always equal null.
UPD. I comment class createBet and add code from it to the public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue). It not change the situation - variable bets.numberBet is changing in the listener only, outside it this variable allways equals null.
I want use numberBet in the whole code, it's main problem.
My solution for this problem. I DON'T set varbable numberBet with method isBet. isBetwork for change CheckBoxes and activation for block resultNum only.
Variables i set in inner action, where thei are used.
new version of class:
public class Bet {
private CheckBox bet;
public void forBet(CheckBox[] group, int finalI, AnchorPane resultBlock) {
for (CheckBox j : group) {
if (j.equals(bet)) {
j.setSelected(false);
}
}
ObservableList resultLabels = resultBlock.getChildren();
Label label_num = (Label)resultLabels.get(0);
Label label_win = (Label)resultLabels.get(1);
if (group[finalI].isSelected()) {
bet = group[finalI];
resultBlock.setStyle("-fx-border-color: black;");
label_num.setStyle("-fx-text-fill: black");
label_win.setStyle("-fx-text-fill: black");
}
else {
bet = null;
resultBlock.setStyle("-fx-border-color: gray");
label_num.setStyle("-fx-text-fill: gray");
label_win.setStyle("-fx-text-fill: gray");
}
}
public CheckBox startBet(CheckBox[] group) {
for (CheckBox i : group){
if (i.isSelected()) {
bet = i;
break;
}
}
return bet;
}
}
variables:
public CheckBox numberBet = null;
public CheckBox colorBet = null;
public CheckBox evenBet = null;
Using for methods:
Bet Bet = new Bet();
for (int i = 0; i < numbersGroup.length; i++) {
int finalI = i;
numbersGroup[i].selectedProperty().addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
Bet.forBet(numbersGroup, finalI,resultNum);
}
});
}
btn_start.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
numberBet = Bet.startBet(numbersGroup);
System.out.println(numberBet);
}
});
I think, it's resolve my issue.

Bind CheckBoxTableCell to BooleanBinding

I want to bind a CheckBox in a TableViewCell to a BooleanBinding. The following sample consists of a TableView with a column name and isEffectiveRequired. The checkbox in the column is bound to the Expression:
isRequired.or(name.isEqualTo("X"))
So an item is "effectivly required" when the item in the row is required OR the name is an X, then the expression should be true.
Unfortunately the CheckBox does not reflect the change. For debugging I added a textfield, showing the nameProperty, requiredProperty and the computed effectiveRequiredProperty.
Interestingly when returning just the isRequiredProperty instead of the binding the checkbox works.
public ObservableBooleanValue effectiveRequiredProperty() {
// Bindings with this work:
// return isRequired;
// with this not
return isRequired.or(name.isEqualTo(SPECIAL_STRING));
}
So what is the difference between a Property and a ObservableValue in regard to a CheckBox?
public class TableCellCBBinding extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) throws Exception {
init(primaryStage);
primaryStage.show();
}
private void init(Stage primaryStage) {
primaryStage.setScene(new Scene(buildContent()));
}
private Parent buildContent() {
TableView<ViewModel> tableView = new TableView<>();
tableView.setItems(sampleEntries());
tableView.setEditable(true);
tableView.getColumns().add(buildRequiredColumn());
tableView.getColumns().add(buildNameColumn());
// Add a Textfield to show the values for the first item
// As soon as the name is set to "X", the effectiveRequiredProperty should evaluate to true and the CheckBox should reflect this but it does not
TextField text = new TextField();
ViewModel firstItem = tableView.getItems().get(0);
text.textProperty()
.bind(Bindings.format("%s | %s | %s", firstItem.nameProperty(), firstItem.isRequiredProperty(), firstItem.effectiveRequiredProperty()));
return new HBox(text, tableView);
}
private TableColumn<ViewModel, String> buildNameColumn() {
TableColumn<ViewModel, String> nameColumn = new TableColumn<>("Name");
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
nameColumn.setCellFactory(TextFieldTableCell.forTableColumn());
nameColumn.setEditable(true);
return nameColumn;
}
private TableColumn<ViewModel, Boolean> buildRequiredColumn() {
TableColumn<ViewModel, Boolean> requiredColumn = new TableColumn<>("isEffectiveRequired");
requiredColumn.setMinWidth(50);
// This is should bind my BindingExpression from to ViewModel to the CheckBox
requiredColumn.setCellValueFactory( p -> p.getValue().effectiveRequiredProperty());
requiredColumn.setCellFactory( CheckBoxTableCell.forTableColumn(requiredColumn));
return requiredColumn;
}
private ObservableList<ViewModel> sampleEntries() {
return FXCollections.observableArrayList(
new ViewModel(false, "A"),
new ViewModel(true, "B"),
new ViewModel(false, "C"),
new ViewModel(true, "D"),
new ViewModel(false, "E"));
}
public static class ViewModel {
public static final String SPECIAL_STRING = "X";
private final StringProperty name;
private final BooleanProperty isRequired;
public ViewModel(boolean isRequired, String name) {
this.name = new SimpleStringProperty(this, "name", name);
this.isRequired = new SimpleBooleanProperty(this, "isRequired", isRequired);
this.name.addListener((observable, oldValue, newValue) -> System.out.println(newValue));
}
public StringProperty nameProperty() {return name;}
public final String getName(){return name.get();}
public final void setName(String value){
name.set(value);}
public boolean isRequired() {
return isRequired.get();
}
public BooleanProperty isRequiredProperty() {
return isRequired;
}
public void setRequired(final boolean required) {
this.isRequired.set(required);
}
public ObservableBooleanValue effectiveRequiredProperty() {
// Bindings with this work:
// return isRequired;
// with this not
return isRequired.or(name.isEqualTo(SPECIAL_STRING));
}
}
}
When typing an X into the name the checkbox in the row should be checked.
When typing an X into the name the checkbox in the row is not checked. It's never checked like it is not bound at all.
CheckBoxXXCells don't live up to their doc when it comes to binding their selected state, f.i. (citing here just for signature, even if not set explicitely):
public final Callback <Integer,​ObservableValue<Boolean>> getSelectedStateCallback()
Returns the Callback that is bound to by the CheckBox shown on screen.
clearly talks about an ObservableValue, so we would expect that it at least shows the selection state.
Actually, the implementation does exactly nothing if it's not a property, the relevant part from its updateItem:
StringConverter<T> c = getConverter();
if (showLabel) {
setText(c.toString(item));
}
setGraphic(checkBox);
if (booleanProperty instanceof BooleanProperty) {
checkBox.selectedProperty().unbindBidirectional((BooleanProperty)booleanProperty);
}
ObservableValue<?> obsValue = getSelectedProperty();
if (obsValue instanceof BooleanProperty) {
booleanProperty = (ObservableValue<Boolean>) obsValue;
checkBox.selectedProperty().bindBidirectional((BooleanProperty)booleanProperty);
}
checkBox.disableProperty().bind(Bindings.not(
getTableView().editableProperty().and(
getTableColumn().editableProperty()).and(
editableProperty())
));
To work around, use a custom cell that updates the selected state in its updateItem. With the added quirk that we need to disable the check's firing to really keep the visuals in sync with backing state:
requiredColumn.setCellFactory(cc -> {
TableCell<ViewModel, Boolean> cell = new TableCell<>() {
CheckBox check = new CheckBox() {
#Override
public void fire() {
// do nothing - visualizing read-only property
// could do better, like actually changing the table's
// selection
}
};
{
getStyleClass().add("check-box-table-cell");
check.setOnAction(e -> {
e.consume();
});
}
#Override
protected void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
} else {
check.setSelected(item);
setGraphic(check);
}
}
};
return cell;
});

how to do the Check-Box enable disable in a Table-Column In JavaFX if i select one check-box i need to disable the remaining check-Boxes

how to do the Check-Box enable disable in a Table-Column In JavaFX if i select one check-box i need to disable the remaining check-Boxes .
if i select one check-box i need to disable the remaining check-Boxes in the table view, in JavaFx.
colSelect.setCellFactory(new Callback<TableColumn<LogVoiceBroadCast, Boolean>, TableCell<LogVoiceBroadCast, Boolean>>()
{
#Override
public TableCell<LogVoiceBroadCast, Boolean> call(TableColumn<LogVoiceBroadCast, Boolean> param) {
final TableCell<LogVoiceBroadCast, Boolean> cell = new TableCell<LogVoiceBroadCast, Boolean>() {
#Override
public void updateItem(Boolean value, boolean empty) {
super.updateItem(value, empty);
if (!empty || value != null) {
CheckBox checkBox = new CheckBox();
checkBox.setSelected(false);
checkBox.addEventHandler(MouseEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent mouseEvent) {
if (!checkBox.isSelected()) {
LogVoiceBroadCast item = (LogVoiceBroadCast) getTableRow().getItem();
voiceFiles.add(item);
} else {
LogVoiceBroadCast item = (LogVoiceBroadCast) getTableRow().getItem();
voiceFiles.remove(item);
}
}
});
final HBox hbox = new HBox(checkBox);
hbox.setAlignment(Pos.CENTER);
hbox.setSpacing(12);
setGraphic(hbox);
} else {
setGraphic(null);
}
}
};
cell.setAlignment(Pos.CENTER);
return cell;
}
});
You shouldn't use a for input events to trigger listen to changes in the CheckBox state. Instead add a listener to the CheckBox.selected property.
Furthermore you need to implement a way of restoring the CheckBox state, since different TableCells may be used for the "checked row". Use some observable data structure to store this kind of information and use a listener to update the state of the CheckBoxes:
TableView<Integer> table = new TableView<>();
for (int i = 0; i < 100; i++) {
table.getItems().add(i);
}
TableColumn<Integer, Number> column = new TableColumn<>();
column.setCellValueFactory(cd -> new SimpleIntegerProperty(cd.getValue()));
// property to store the checked row item or null, if no row is checked
final ObjectProperty<Integer> selectedValue = new SimpleObjectProperty<>();
TableColumn<Integer, Void> checkBoxColumn = new TableColumn<>();
checkBoxColumn.setCellFactory(col -> new TableCell<Integer, Void>() {
private final CheckBox checkBox = new CheckBox();
private final ChangeListener<Boolean> selectionListener = (o, oldValue, newValue) -> {
if (newValue) {
// use the row item as selected item, when checkbox is selected
selectedValue.set((Integer) getTableRow().getItem());
} else {
// clear selected item, when checkbox is unselected
selectedValue.set(null);
}
};
private final ChangeListener<Integer> listener = (o, oldValue, newValue) -> {
if (!isEmpty()) {
// update state without triggering the listener
checkBox.selectedProperty().removeListener(selectionListener);
if (newValue == null) {
checkBox.setSelected(false);
checkBox.setDisable(false);
} else {
boolean match = newValue.equals(getTableView().getItems().get(getIndex()));
checkBox.setSelected(match);
checkBox.setDisable(!match);
}
checkBox.selectedProperty().addListener(selectionListener);
}
};
{
// listener should not prevent garbage collection of cell
selectedValue.addListener(new WeakChangeListener<>(listener));
checkBox.selectedProperty().addListener(selectionListener);
setAlignment(Pos.CENTER);
}
#Override
protected void updateItem(Void item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
setGraphic(checkBox);
listener.changed(null, null, selectedValue.get());
}
}
});
table.getColumns().addAll(column, checkBoxColumn);

Javafx TableView data refresh

I have combobox, tableview as TableView<Person> and 3 columns.
I want to populate the updated data in TableView as per item I select in combobox.
My Issue: every time I select the item in combobox, the data in table view is added. I want the details to be displayed for the selected item only.
Code:
public class MyTableController {
private TableView<Person> personTableView;
private ObservableList<Person> personTableViewData= FXCollections.observableArrayList();
initialize() {
comboBox.valueProperty().addListener(new ChangeListener<String>() {
#Override public void changed(ObservableValue ov, String oldValue, String newValue) {
List<Person> filteredPersonList =
personList.stream().filter(person -> person.getFirstName().contains(newValue)).collect(Collectors.toList());
personTableViewData.addAll(filteredPersonList);
personTableView.setItems(personTableViewData);
}
}
Use ObservableList.setAll instead of ObservableList.addAll or alternatively create a new ObservableList. Otherwise you're adding new items to the same list on every change instead of replacing the items:
initialize() {
personTableView.setItems(personTableViewData);
comboBox.valueProperty().addListener(new ChangeListener<String>() {
#Override public void changed(ObservableValue ov, String oldValue, String newValue) {
List<Person> filteredPersonList =
personList.stream().filter(person -> person.getFirstName().contains(newValue)).collect(Collectors.toList());
personTableViewData.setAll(filteredPersonList);
}
}

How to enable/disable a button based on boolean property within a tablerow

As the title states, I'm trying to enable/disable a button within a table row based upon a boolean within that table row's data. Here's my code so far:
col.setCellFactory(new Callback<TableColumn<ExampleRow, String>, TableCell<ExampleRow, String>>() {
#Override
public TableCell call(final TableColumn<ExampleRow, String> param){
final Button btn = new Button("Save");
final TableCell<ExampleRow, String> cell = new TableCell<ExampleRow, String>(){
#Override
public void updateItem(String item, boolean empty){
super.updateItem(item, empty);
if(empty){
setGraphic(null);
setText(null);
} else {
btn.setPrefWidth(col.getWidth());
btn.setPadding(Insets.EMPTY);
btn.setOnAction(event -> {
});
setGraphic(btn);
setText(null);
}
}
};
ExampleRow row = (ExampleRow)cell.getTableRow().getItem(); //NPE here
btn.setDisable(!row.hasChanged());
return cell;
}
});
Unfortunately my code breaks on the fifth from the bottom line. If I exclude that line and change the line below to btn.setDisable(true) it works wonderfully. What can I do to disable this button based upon the data in which the button resides?
You aren't using the item anyways, so you could just make it a Boolean and use the value of the changed property. This allows you to enable/disable the button in the updateItem method:
Example:
public static class Item {
private final BooleanProperty changed = new SimpleBooleanProperty();
public final boolean isChanged() {
return this.changed.get();
}
public final void setChanged(boolean value) {
this.changed.set(value);
}
public final BooleanProperty changedProperty() {
return this.changed;
}
}
#Override
public void start(Stage primaryStage) {
TableView<Item> table = new TableView();
table.getItems().addAll(new Item(), new Item(), new Item());
TableColumn<Item, Boolean> column = new TableColumn<>();
column.setCellValueFactory(cd -> cd.getValue().changedProperty());
column.setCellFactory(col -> new TableCell<Item, Boolean>() {
final Button btn = new Button("Save");
{
btn.setOnAction(evt -> {
Item item = (Item) getTableRow().getItem();
item.setChanged(false);
});
}
#Override
protected void updateItem(Boolean item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setGraphic(null);
} else {
btn.setDisable(!item);
setGraphic(btn);
}
}
});
table.getColumns().add(column);
Button btn = new Button("change");
btn.setOnAction((ActionEvent event) -> {
Item item = table.getSelectionModel().getSelectedItem();
if (item != null) {
item.setChanged(true);
}
});
VBox root = new VBox(btn, table);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
BTW: TableView uses the cellFactory to create the cells. The item, table and tableRow properties are updated later. Therefore retrieving any of those values in the cellFactory's call method itself makes no sense, since none of those values have been assigned at that time.

Resources