Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

221
Vistas
Reset checkbox selection in ChangeListener under condition

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

  1. Why doesn't it work without the refresh() method, why setSelected() is ignored?
  2. Should I use the refresh() method?
  3. 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 it doesn't seem to be the best way to do that. 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.

A solution / workaround that always works is desired...

over 4 years ago · Santiago Trujillo
2 Respuestas
Responde la pregunta

0

You are resetting the checkbox item too soon. It hasn’t finished its event processing yet.

You want to wait until it’s finished before you reset it. Use Platform.runLater to make sure you reset it after all pending events have been processed:

Platform.runLater(() -> item.setSelected(previousChoice));
over 4 years ago · Santiago Trujillo Denunciar

0

What we are seeing in the OPs example actually is the standard behavior of bidirectionally bound properties, reduced to a simple (no ui, just properties) example.

The scenario:

  • there are two boolean properties, representing the data (checkBoxTreeItem) and ui (checkBox) selected properties
  • they are wired the same way as in a checkBoxTreeCell, that is the ui is bidirectionally bound to the data
  • a listener to the data reverts the data to false on receiving a change from false -> true

Just for showing that - though nor recommended - reverting a the state of the sender in a listener is working: we set the data property to true. At the end, both data and ui are false as we want it.

before data.set(true)
    state of data/ui: false / false
enter listener to ui: true
enter listener to data: true
enter listener to ui: false
enter listener to data: false
 ... returning
listener to data - after reset false
after data.set(true) - state of data/ui: false / false

For the real simulation of the OP's context: set the ui property (user clicks the checkBox) - at the end, the data property is reverted while the ui property is not. Technically, that's done in BidirectionalBinding which ignores incoming changes while updating.

before ui.set(true)
    state of data/ui: false / false
enter listener to data: true
enter listener to data: false
 ... returning
listener to data - after reset false
enter listener to ui: true
after ui.set(true) - state of data/ui: false / true

The example:

public class BidiBindingUpdating {

    public static void main(String[] args) {
        BooleanProperty data = new SimpleBooleanProperty();
        BooleanProperty ui = new SimpleBooleanProperty();
        ui.bindBidirectional(data);

        // listener to item: revert to false
        data.addListener((src, ov, nv) -> {
            System.out.println("enter listener to data: " + nv);
            if (!nv) {
                System.out.println(" ... returning");
                return;
            }
            data.set(ov);
            System.out.println("listener to data - after reset " + data.get());
        });

        // listener to check: logging only
        ui.addListener((src, ov, nv) -> {
            System.out.println("enter listener to ui: " + nv);
        });

        // set item directly:
        System.out.println("before data.set(true)");
        System.out.println("    state of data/ui: " + data.get() + " / " + ui.get());
        data.set(true);
        System.out.println("after data.set(true) - state of data/ui: " + data.get() + " / " + ui.get());

        // set bound property:
        System.out.println("\nbefore ui.set(true)");
        System.out.println("    state of data/ui: " + data.get() + " / " + ui.get());
        ui.set(true);
        System.out.println("after ui.set(true) - state of data/ui: " + data.get() + " / " + ui.get());

    }
}
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda