trabajar programar grafico crear con completo como busqueda binario arboles arbol java listview layout javafx

programar - crear arboles en java



ListView con adornos CellFactory personalizados nodos invisibles (2)

Mi problema de diseño

Tengo un pequeño problema con ListView y no estoy seguro si es por algún conocimiento que me falta o si mi enfoque es defectuoso. Tengo que admitir que aún no tengo claro cómo JavaFX maneja el diseño en muchos casos posibles.

La captura de pantalla anterior muestra el resultado obtenido dos veces con exactamente el mismo código, excepto que en el segundo una forma invisible que uso para el diseño coherente se hace visible para la depuración .

Las diversas clases involucradas por el Group extensión de CellFactory , lo intenté con algún otro Parent sin mucho éxito hasta el momento.

Cómo reproducir

En lugar de compartir StarShape , StarRow y algunas otras clases de misceláneos (me gustaría que me lo pidieran) escribí una muestra para reproducir el problema. La clase extiende la Application y anula el método de start(...) como tal:

@Override public void start(Stage primaryStage) throws Exception { final StackPane root = new StackPane(); final Scene scene = new Scene(root, 400, 600); final ListView<Boolean> listView = new ListView<>(); listView.setCellFactory(this::cellFactory); for (int i = 0; i < 5 ; i++) { listView.getItems().add(true); listView.getItems().add(false); } root.getChildren().add(listView); primaryStage.setScene(scene); primaryStage.setTitle("ListView trims the invisible"); primaryStage.show(); }

donde this::cellFactory es

private ListCell<Boolean> cellFactory(ListView<Boolean> listView) { return new ListCell<Boolean>() { @Override protected void updateItem(Boolean item, boolean empty) { super.updateItem(item, empty); if (empty || item == null) { setText(null); } else { final Rectangle tabShape = new Rectangle(); tabShape.setHeight(20); tabShape.setWidth(40); tabShape.setVisible(item); final Label label = new Label(item.toString()); label.setLayoutX(40); final Group cellRoot = new Group(); cellRoot.getChildren().add(tabShape); cellRoot.getChildren().add(label); setGraphic(cellRoot); } } }; }

Lo anterior mostrará un ListView<Boolean> con formas negras delante de elementos true (debido a tabShape.setVisible(item); bit). Los elementos false ven como objetos Label normales como si la forma invisible en su Group no estuviera allí (pero lo es).

Comentarios de cierre

Al depurar esto, resulta que a los grupos con las formas invisibles se les dan valores de propiedad negativos de layoutX . Por lo tanto, los controles de Label no están alineados como me gustaría. No sucede cuando llamo a setLayoutX y setLayoutY fuera de un ListView (las formas invisibles sí fuerzan las compensaciones), pero probablemente no sea el único lugar donde ocurriría.

¿Qué está pasando y cómo evitarlo? Alternativamente, como supongo que me estoy acercando a este error , ¿cuál sería el camino correcto? En otras palabras, ¿cuál es la pregunta que debería hacer en lugar de esto?


Supongo que me estoy acercando a esto mal

No tu no eres. Al igual que con todos los diseños, a menudo hay varias formas de abordar el mismo problema. Su enfoque es realmente correcto y está muy cerca de una solución funcional.

Puedes lograr lo que buscas con un simple cambio de 1 línea. Es decir, cambiar el Group a un HBox .

Un HBox asegura que los elementos se ordenan horizontalmente, uno tras otro. También permiten que elementos invisibles ocupen espacio.

También comenté una línea: label.setLayoutX(40) . Hice esto porque HBox no respetará esta configuración, y en realidad no la necesita. Automáticamente desplazará los elementos horizontalmente en la medida necesaria.

@Override protected void updateItem(Boolean item, boolean empty) { super.updateItem(item, empty); if (empty || item == null) { setText(null); } else { final Rectangle tabShape = new Rectangle(); tabShape.setHeight(20); tabShape.setWidth(40); tabShape.setVisible(item); final Label label = new Label(item.toString()); //label.setLayoutX(40); final HBox cellRoot = new HBox(); cellRoot.getChildren().add(tabShape); cellRoot.getChildren().add(label); setGraphic(cellRoot); } }

Cuando realizo esos cambios, su diseño se procesará así:

Importante : su ejemplo y sus capturas de pantalla son ligeramente diferentes. Es posible que desee utilizar un VBox para su ejemplo de estrella (V para ''vertical'', H para ''horizontal'').


Tomando el comentario de @dlatikay , en lugar de establecer los elementos del marcador de posición en invisible, puede hacerlos transparentes al establecer su opacidad en 0.0 .

Aplicado a MCVE a partir de su pregunta, esto se haría reemplazando:

tabShape.setVisible(item);

con:

tabShape.setOpacity(item ? 1.0 : 0.0);

En términos de experiencia del usuario, puede dar un paso más. En lugar de configurar las estrellas "inactivas" para que sean totalmente transparentes, puede configurarlas para que sean casi transparentes, como en esta maqueta (con la opacidad establecida en 0.1 ):

Los beneficios que veo son:

  1. Indica no solo la calificación de un elemento en la lista, sino también la calificación máxima.
  2. Evita espacios vacíos incómodos para elementos de lista con cero estrellas.