On Tue, 4 Aug 2026 22:05:15 GMT, Andy Goryachev <[email protected]> wrote:
>> This PR shows how virtual layouts could be implemented, as discussed on the >> mailinglist: >> https://mail.openjdk.org/archives/list/[email protected]/thread/PLNSQ3ZI63AVKEFKNT5GT6WHAD2GYMPC/ >> >> It would work by making new non-Node containers called Layouts which can >> contain a mix of either Nodes or other Layouts. Allowing Layouts to nest >> makes it possible to create a substructure similar to how nesting >> StackPane/HBox/VBox etc works today. An example is a simple control that has >> a graphic with a title and subtitle stacked vertically next to it: >> >> >> +-------------+-----------------------------------------+ >> | | | >> | | Title | >> | | | >> | Graphic +-----------------------------------------+ >> | | | >> | | Subtitle | >> | | | >> +-------------+-----------------------------------------+ >> >> For a control to model this, it would need a VBox containing the Title and >> Subtitle, and an HBox containing the Graphic and the VBox. The two >> containers are heavy-weight Nodes and this incurs sufficiently large memory >> and performance penalties that most standard JavaFX controls will opt to >> instead roll their own layout code to avoid paying the cost for these. >> >> With virtual layouts, the control could make use of non-Node containers. The >> control would add its three children (Graphic, Title and Subtitle) as direct >> children for display in the scene graph, but would offload their positioning >> to a virtual layout. This roughly looks like this: >> >> >> public class TitledGraphic extends Region { >> private final HBoxLayout root; >> >> public TitledGraphic(Node graphic, String titleText, String >> subtitleText) { >> // Flat scene graph: >> getChildren().addAll(graphic, title, subtitle); >> >> // Create virtual layout: >> root = HBoxLayout.of(graphic, VBoxLayout.of(title, subtitle)); >> } >> >> @Override >> protected void layoutChildren() { >> root.resizeRelocate(0, 0, getWidth(), getHeight()); >> } >> >> @Override protected double computeMinWidth(double height) { return >> root.minWidth(height); } >> @Override protected double computeMinHeight(double width) { return >> root.minHeight(width); }... > > modules/javafx.graphics/src/main/java/javafx/scene/layout/StackPane.java line > 141: > >> 139: private static final Callback<Layoutable, Pos> ALIGNMENT_LOOKUP = >> child -> StackPane.getAlignment((Node) child); >> 140: >> 141: private final StackPaneLayout stackPaneLayout = new >> StackPaneLayout(MARGIN_LOOKUP, ALIGNMENT_LOOKUP); > > would it make more sense to make StackPaneLayout an abstract class instead of > using callbacks? There are multiple ways to go about it; the reason the callbacks exist is that we need to access/track child constraints. Options include: - Just provide callbacks to get at the constraints (the callbacks already existed in `StackPane`, and the solution doesn't look to bad) - Instead of delegating this functionality back to the owner, we could make this accessible on the `Layoutable` interface (add constraint get/set methods) -- such methods would however introduce new API on `Node` so I've left them out of this proposal (their implementation could just store them in the properties map, so trivial implementation, just more formalized then using `getProperties`) - Special constraint methods could also live in a subinterface (to keep them separate as they're a bit specific), so you could have `Constrainable` -> `Layoutable` -> `Measurable`. - Expose `getProperties` on the `Layoutable` interface; this would be API compatible, but would put a generic method on `Layoutable` that seems out of place The reason I wouldn't make it abstract is that these callbacks will be optional. They are primarily needed for the original heavy-weight containers (ie. `StackPane`) to provide the full functionality they offered before. However, for embedded use, you can drop these providers if you don't need per-child constraints. Ideally, you can then just write: `StackPaneLayout.of(child1, child2, child3)` or: StackPaneLayout.of( child1, HBoxLayout.of( VBoxLayout.of( child2, child3 ), VBoxLayout.of( child4, child5 ) ) ); There is a gap still however, which we should address: constraints can only be put on `Node`s in this proof of concept; if I wanted to put a stackpane-related constraint on the `HBoxLayout` above, I can't as it isn't a `Node`. ------------- PR Review Comment: https://git.openjdk.org/jfx/pull/2241#discussion_r3717551851
