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

Reply via email to