ListView avec CellFactory personnalisé coupe les nœuds invisibles

Mon problème de mise en page

J’ai un petit problème avec ListView et je ne sais pas si c’est à cause de certaines connaissances qui me manquent ou si mon approche est erronée. Je dois avouer que je ne sais pas encore comment JavaFX gère la mise en page dans les nombreux cas possibles.

ListView réduit ma tentative de mise en page

La capture d’écran ci-dessus montre le résultat que j’obtiens deux fois avec le même code, sauf que sur le second, une forme invisible que j’utilise pour une mise en page cohérente est visible pour le débogage .

Les différentes classes impliquées par CellFactory étendent le Group , j’ai essayé avec un autre Parent sans grand succès jusqu’à présent.


Comment reproduire

Plutôt que de partager mon StarShape , StarRow et quelques autres classes (je serais ravi de vous le demander), j’ai écrit un échantillon reproduisant le problème. La classe étend l’ Application et remplace la méthode de start(...) tant que telle:

 @Override public void start(Stage primaryStage) throws Exception { final StackPane root = new StackPane(); final Scene scene = new Scene(root, 400, 600); final ListView 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(); } 

this::cellFactory est

 private ListCell cellFactory(ListView listView) { return new ListCell() { @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.toSsortingng()); label.setLayoutX(40); final Group cellRoot = new Group(); cellRoot.getChildren().add(tabShape); cellRoot.getChildren().add(label); setGraphic(cellRoot); } } }; } 

Ce qui précède affichera un ListView avec des formes noires devant true éléments true (à cause de tabShape.setVisible(item); bit). Les éléments false ressemblent à des objects Label classiques comme si la forme invisible de leur Group n’était pas là (mais c’est le cas).


Clôture des commentaires

Le débogage, il s’avère que les groupes avec les formes invisibles reçoivent des valeurs de propriété layoutX négatives . Ainsi, les contrôles Label ne sont pas alignés comme je le souhaiterais. Cela ne se produit pas lorsque j’appelle setLayoutX et setLayoutY dehors d’un ListView (les formes invisibles forcent les décalages), mais ce n’est probablement pas le seul endroit où cela se produirait.

Qu’est-ce qui se passe et comment l’éviter? Sinon, comme je suppose que je me trompe , quelle serait la bonne solution? En d’autres termes, quelle est la question que je devrais poser au lieu de cela?

En prenant le commentaire de @dlatikay , au lieu de définir les éléments de l’espace réservé sur invisible, vous pouvez les rendre transparents en définissant leur opacité sur 0.0 .

Appliqué au MCVE à partir de votre question, cela se ferait en remplaçant:

 tabShape.setVisible(item); 

avec:

 tabShape.setOpacity(item ? 1.0 : 0.0); 

En termes d’expérience utilisateur, vous pouvez aller plus loin. Au lieu de définir les écanvass “inactives” sur une transparence totale, vous pouvez les définir de manière presque transparente, comme dans cette maquette (avec une opacité de 0.1 ):

maquette

Les avantages que je vois sont:

  1. Il indique non seulement la notation d’un élément dans la liste, mais également la note maximale.
  2. Il évite les espaces vides pour les éléments de liste avec des écanvass nulles.

Je suppose que je m’approche de ce problème

Non, vous ne l’êtes pas. Comme pour toutes les mises en page, il existe souvent plusieurs manières d’aborder le même problème. Votre approche est en fait correcte et vous êtes très proche d’une solution de travail.

Vous pouvez réaliser ce que vous recherchez avec un simple changement de ligne. C’est-à-dire changer le Group en HBox .

Un HBox garantit que les éléments sont ordonnés horizontalement, l’un après l’autre. Ils permettent également aux éléments invisibles de prendre de la place.

J’ai également commenté une ligne: label.setLayoutX(40) . Je l’ai fait parce que HBox ne respectera pas ce paramètre, et en fait vous n’en avez pas besoin. Il décale automatiquement les éléments horizontalement de la manière requirejse.

 @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.toSsortingng()); //label.setLayoutX(40); final HBox cellRoot = new HBox(); cellRoot.getChildren().add(tabShape); cellRoot.getChildren().add(label); setGraphic(cellRoot); } } 

Lorsque j’effectue ces modifications, votre mise en page sera rendue comme suit:

entrer la description de l'image ici


Important : Votre exemple et vos captures d’écran sont légèrement différents. Vous voudrez peut-être utiliser un VBox pour votre exemple d’écanvas (V pour ‘vertical’, H pour ‘horizontal’).