In my JavaFX application I'm using Checkboxes
in a TreeView
to change the visibility of nodes.
- checkbox selected = some nodes are visible
- checkbox deselected = some nodes are invisible
In a special case, however, the user should be prompted to confirm their selection, because problems can arise when activating a specific checkbox. A dialog window opens in which the user can choose between "Yes" and "No". If the user chooses "Yes", nodes become visible and everything is fine. But if the user chooses "No", the checkbox should be deselected again.
My idea was to check the condition (in this case press "no" in a dialog window) in the ChangeListener
and if it's true, set the selected value to false.
But for whatever reason, it didn't work. After that, I figured out that it works with the refresh()
method of the TreeView
.
Questions
- Why doesn't it work without the
refresh()
method, whysetSelected()
is ignored? - Should I use the
refresh()
method? - Is there a better workaround to change the selection status?
Minimal reproducible example
Using the refresh()
line will show the desired behavior: The checkbox remains unselected after clicking because 5 > 4 (5>4 simulates for example pressing "no" in a dialog window).
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.CheckBoxTreeItem;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.controlsfx.control.CheckTreeView;
public class HelloApplication extends Application {
enum Names { TEST1, TEST2, TEST3, TEST4 }
private final CheckTreeView<String> checkTreeView = new CheckTreeView<>();
@Override
public void start(Stage stage) {
VBox vBox = new VBox();
Scene scene = new Scene(vBox, 500, 500);
setTreeView();
vBox.getChildren().add(checkTreeView);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
public void setTreeView() {
CheckBoxTreeItem<String> rootItem = new CheckBoxTreeItem<>("Root");
rootItem.setExpanded(true);
for (Names name : Names.values()) {
CheckBoxTreeItem<String> item = new CheckBoxTreeItem<>(name.toString(), null);
item.selectedProperty().addListener(this.onSelectionChanged(item));
rootItem.getChildren().add(item);
}
this.checkTreeView.setRoot(rootItem);
}
private ChangeListener<Boolean> onSelectionChanged(CheckBoxTreeItem<String> item) {
return (observableValue, previousChoice, newChoice) -> {
if (newChoice) { // if checkbox is selected
// if anything happens... for example press a "no" button in a dialog window
if (5 > 4) {
System.out.println("reset checkbox status");
item.setSelected(previousChoice);
}
}
// it works with refresh:
// this.checkTreeView.refresh();
};
}
}
EDIT:
The solution of @VGR with
Platform.runLater(() -> item.setSelected(previousChoice));
works for the minimal reproducible example, but not for my real application. As already discussed in the comments, with Platform.runLater()
it's
working most of the time
and
there's no guarantee because the exact timing is unspecified, will break f.i. if something in the pending events does also use runlater.
so it doesn't seem to be the best way to do that.
Aucun commentaire:
Enregistrer un commentaire