la selección ListView CheckBoxListCell: JavaFX

Sunflame:

Tengo un problema con el ListViewuso de una CheckBoxListCell. Cuando activar / desactivar un elemento, el elemento no está seleccionado / enfocada que podría esperarse ya que la casilla de verificación es también parte de la partida no sólo la parte de texto.

Aquí es un código simple que puede verificarlo.

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.CheckBoxListCell;
import lombok.Getter;

import java.net.URL;
import java.util.ResourceBundle;

public class Controller implements Initializable {
    @FXML private ListView<Model> listView;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
//      without selection
//      listView.setCellFactory(CheckBoxListCell.forListView(Model::getSelected));

        // actual "bad" solution
        listView.setCellFactory(factory -> {
            CheckBoxListCell<Model> cell = new CheckBoxListCell<Model>() {
                @Override
                public void updateItem(Model item, boolean empty) {
                    super.updateItem(item, empty);
                    if (empty) {
                        setText(null);
                        setGraphic(null);
                        return;
                    }
                    ((CheckBox) getGraphic()).selectedProperty().addListener(
                            (observable, oldValue, newValue) -> listView.getSelectionModel().select(getItem()));
                }
            };
            cell.setSelectedStateCallback(Model::getSelected);
            return cell;
        });

        ObservableList<Model> items = FXCollections.observableArrayList();

        items.add(new Model("A", true));
        items.add(new Model("B", true));
        items.add(new Model("C", false));

        listView.setItems(items);
    }

    @Getter
    private class Model {
        String text;
        BooleanProperty selected;

        private Model(String text, Boolean selected) {
            this.text = text;
            this.selected = new SimpleBooleanProperty(selected);
        }

        @Override public String toString() {
            return text;
        }
    }
}

.fxml:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.control.ListView?>
<AnchorPane xmlns="http://javafx.com/javafx"
            xmlns:fx="http://javafx.com/fxml"
            fx:controller="list.Controller">
<ListView fx:id="listView"/>
</AnchorPane>

Como se puede ver hay una solución que encontré, o mejor dicho una solución sucia, pero no me gusta mucho es ya que se llama en cada updateItem y se añade al oyente n veces, lo cual no es tan grande.

Cualesquiera otras ideas / soluciones ¿Cómo puedo lograr que cuando activar / desactivar el cuadro combinado se selecciona todo el artículo / enfocados.

kleopatra:

Esta respuesta sólo cubre una parte de la pregunta: ¿Cómo asegurarse de que un oyente en una propiedad de la gráfica de una célula está registrada una sola vez (si no tenemos control sobre cuando el gráfico es conjunto).

Los pasos a seguir:

  1. definir un InvalidationListener que se instala el oyente "real" (nota: tiene que ser un campo para ser capaz de eliminar más adelante)
  2. registrar el detector en la propiedad gráfica de la célula en el momento de instancias
  3. implementar el registro del método "real" para eliminar el oyente gráficos inicial, además de instalar lo que sea necesario

El fragmento de código (cuidado: la escucha de la propiedad seleccionada no es una buena idea, ya que se disparará cada vez que cambian los datos, no sólo cuando el usuario hace clic en la casilla de verificación!):

listView.setCellFactory(factory -> {
    CheckBoxListCell<Model> cell = new CheckBoxListCell<Model>() {
        // a listener on the graphicProperty: it installs the "real" listener
        InvalidationListener graphicListener = g -> {
            // installs the "real" listener on the graphic control once it is available 
            registerUIListener();
        };

        {
            // install the graphic listener at instantiation
            graphicProperty().addListener(graphicListener);
        }

        /** method to install a listener on a property of the graphic control
         * and unregisters the initially installed listener
         */
        private void registerUIListener() {
            if (!(getGraphic() instanceof CheckBox)) throw new IllegalStateException("checkBox expected");
            graphicProperty().removeListener(graphicListener);
            ((CheckBox) getGraphic()).selectedProperty().addListener(
                    (observable, oldValue, newValue) -> listView.getSelectionModel().select(getItem()));
        }
    };
    cell.setSelectedStateCallback(Model::selectedProperty);
    return cell;
});

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=234899&siteId=1
Recomendado
Clasificación