I would like to add that not just that Node is heavy, every
   intermediate Pane also need to be processed by CSS, may receive a
   CssStyleHelper (e. g. to hold triggerStates) and counting in to the
   depth. Since this is currently the area I'm looking

   

I would like to add that not just that Node is heavy, every intermediate
Pane also need to be processed by CSS, may receive a CssStyleHelper
(e.g. to hold triggerStates) and counting in to the depth.
Since this is currently the area I'm looking in, I thought this would be
worth to add to the discussion.

I still think improving the memory footprint of Node is a good thing.
But that is a separate problem IMO.

-- Marius

Am 16.07.2026 um 20:35 schrieb John Hendrikx:
> On 16/07/2026 17:26, Andy Goryachev wrote:
>> I see, you want to avoid the overhead of the intermediate pane(s),
>> mainly because the Node class is too heavy.
> Exactly, and not only that, to avoid the overhead of a graphic peer
> (HBox's are still Regions), CSS styling, another layer to go through for
> dispatching/bubbling for events, several dozen fields, and many
> unavoidable properties that are getting created.  A Node can easily
> consume upwards of a few kilo bytes to do "nothing".
>
>> I wonder if a less invasive solution for that problem would be to put
>> the rarely used properties into a hash table instead, something along
>> the lines of https://github.com/andy-goryachev-oracle/jfx/pull/20 .
> I don't see how that would be a less invasive solution, considering
> you'd be introducing a hash map lookup to find properties.  It also
> doesn't solve the problem; a layout container would still have to be a
> Node, and no matter how many properties you stash in that map, it will
> still consume on the order of 10-30x more memory than a non-Node layout
> container.
>
>> This way we'd eliminate most of the overhead and do it without adding
>> any public APIs (apart from exposing the layout classes once they
>> mature).  The reason I dislike the idea of Layoutable is because it
>> impacts all the Node's descendants, even though conceptually it only
>> belongs to Parent.
> That's not quite correct, every Node, including one without children,
> like Shape (not a Parent), Subscene, ImageView, etc, can and must
> participate in layout.  Every Node has:
>
> - resizable + resize + resizeRelocate methods
> - minWidth/prefWidth/maxWidth etc.
> - layout constraint
> - layout x/y
>
> Parent only governs a potential list of children, and governs some flags
> to determine when the layout system should be triggered, but that's
> orthogonal -- these flags would not be part of the proposed interface.
> Parent has nothing to do with whether it can participate in a layout, as
> all Nodes already can.  The children of an HBox are in
> ObservableList<Node> which basically means anything can participate in a
> layout, including shapes, subscenes, imageviews, etc.
>
> The Layoutable interface simply marks something as "being able to
> participate in layout".  It is not a marker for a layout algorithm(!).
> It just so happens though that layout containers themselves (ones that
> can do layouts) also themselves can participate in a "grander" layout,
> just like an HBox can contain more HBoxes.
>
> Remember how this started:
>
> - We discover bugs in LabelSkinBase / TitledPane etc with regards how
> they handle graphic Nodes that use more advanced features (like min/max
> widths, content bias, alignment).  I can put a full scene graph in the
> "graphic" part of a Label (although often a HBox is sufficient), and
> expect that to be handled correctly without bugs.
>
> - We find out that these classes badly duplicate the code that is in
> HBox, taking shorts cuts like only called `prefWidth(-1)` on the graphic
> node and assuming that is sufficient.
>
> - The reason for that was simple: HBox is too heavy; having a HBox or
> VBox in every Labeled would create a massive amount of additional nodes,
> it made sense to optimize those away, just like it made sense to change
> the Skin API to no longer require that it supplies a Node (it still
> works if you do, but none of the FX skins do it that way anymore, again,
> it would be wasting precious Nodes).
>
> - We discuss how it would be nice if the algorithm that HBox has could
> be provided without having to use an HBox, so these classes don't have
> to poorly duplicate very complicated layout logic
>
> We're now here with a proposal that almost couldn't be simpler:
> introduce an interface so both Nodes and a light-weight layout
> containers can have a common ancestor, and have Node implement that; for
> Node it would literally mean:
>
> - Copy a dozen related method signatures + documentation to a new interface
> - Add `@Override` to the affected methods in Node, and strip their
> documentation (that is on the interface now, you won't notice in Javadoc)
> - The change is 100% source and binary compatible, and even has no
> performance impact if calling these methods via a Node reference
>
> Even in core-libs they've done this several times, like introducing
> SequencedCollection/SequenceMap/SequencedSet interfaces, or the
> AbstractStringBuilder which became the new ancestor of StringBuffer when
> StringBuilder was introduced.
>
> Adding such an interface would simply mark Node as something that "can
> participate in layouts", which is already exactly what a Node is (as it
> has hard coded all those methods on it already).
>
> --John
>
>
>> -andy
>>
>>
>>
>>
>> *From: *John Hendrikx <[email protected]>
>> *Date: *Thursday, July 16, 2026 at 03:37
>> *To: *Andy Goryachev <[email protected]>;
>> [email protected] <[email protected]>
>> *Subject: *Re: [External] : Proposal to split off layout and layout
>> metric methods from Node to interfaces it implements
>>
>> This Message Is From an External Sender
>> This message came from outside your organization.
>> Report Suspicious
>> <https://us-phishalarm-ewt.proofpoint.com/EWT/v1/ACWV5N9M2RV99hQ!NB26dgOv2uIP
HxPgvfKeeB8wifO7UNM_qPE-ApXJee7-lnArw9ivFU3vA1OKWzk7SOFWi4LZ-I0apqiGweab_xqLu69y
FJ24pTitxw$>
>>
>>
>> On 15/07/2026 20:10, Andy Goryachev wrote:
>>
>>      Right, static layouts will only work in simple cases, the more
>>      complicated ones will require an instance.
>>
>>      My point is that if we are laying out Nodes, there is no need to
>>      invent another abstraction layer because Nodes contain all the
>>      required data.  This will eliminate the "Bonus" section which some
>>      seem to like.
>>
>> The Bonus section is bonus, all else is still needed.
>>
>> The problem is: we're not laying out only Nodes.  We're also laying
>> out potentially light-weight layout containers (that purposely are not
>> Nodes).  So the list of things to lay out can contain a mix of Nodes
>> and Layouts.  A layout acts as a Node, but isn't one.
>>
>> Let's take my example: A TitleSubtileControl that can have a Graphic
>> on the left and on the right two lines of text one above the other
>> (title and subtitle)
>>
>> - The TitleSubtileControl is a normal Node, that wants to avoid having
>> a nested HBox and VBox so it creates:
>>    - A HBoxLayout within it nested a VBoxLayout and a Graphic (a Layout
>> and a Node)
>>    - A VBoxLayout within it nested a Title and a Subtitle Text (two Nodes)
>>    - It adds only the Nodes to the scenegraph as its children (so:
>> titleSubtitleControl.getChildren().addAll(graphic, title, subtitle)
>>
>> Now the problem is, HBoxLayout needs to accept a VBoxLayout (not a
>> Node) and a Graphic (a Node).  The only way to do that is to store
>> them as Objects since they don't share a common ancestor; VBoxLayout
>> can't be a Node because that would pull in a zillion private fields
>> and properties making it "heavy".
>>
>> The solution I presented is to create this common ancestor, which I've
>> dubbed Layoutable. It contains methods that only layouts need (like
>> VBoxLayout or VBox itself).  These methods already exist on Node,
>> they're just not grouped as part of an interface it implements.  Doing
>> such a change is source and binary compatible.
>>
>> So the end state is:
>>
>> - VBoxLayout implements Layoutable (but is not a Node!)
>> - Node implements Layoutable
>>
>> When VBoxLayout and a Node are nested in HBoxLayout, the HBoxLayout
>> can treat both as Layoutable's making Layouts clean (there would have
>> to be a million instanceof checks otherwise, or we'd need to wrap
>> Nodes in a LayoutableWrapper).
>>
>> Sorry for the confusion with the bonus section, I hope this clarifies
>> why it would a good move to have a common ancestor for Nodes and Layouts.
>>
>> --John
>>
>>
>>
>>      I guess what I am trying to say is that code reuse (and removal of
>>      hard-to-maintain code replication) should be the primary goal,
>>      while adding new features (Canvas) should come last, if ever.
>>
>>      -andy
>>
>>
>>      *From: *John Hendrikx <[email protected]>
>>      *Date: *Wednesday, July 15, 2026 at 10:49
>>      *To: *Andy Goryachev <[email protected]>;
>>      [email protected] <[email protected]>
>>      *Subject: *Re: [External] : Proposal to split off layout and
>>      layout metric methods from Node to interfaces it implements
>>
>>      This Message Is From an External Sender
>>      This message came from outside your organization.
>>      Report Suspicious
>>      <https://us-phishalarm-ewt.proofpoint.com/EWT/v1/ACWV5N9M2RV99hQ!NB26lig
kesgE1bPqfVnUuELFLOB1vmX7gUMnmgafz5PcT3tCIOQ6CH3Y_2TlHn6_oY4aATre-aOhU774w6HiWg4
mLvHIFUYvM_SnXw$>
>>
>>
>>
>>      On 15/07/2026 19:32, Andy Goryachev wrote:
>>
>>           *
>>              Yes, they don't need to be public immediately, although
>>              they definitely can be as they're nothing more than a
>>              "copy" of the layout panes we already have, but packaged
>>              without the Node dependency.  We would need pretty quickly
>>              the Node implementing the Layoutable interface (which
>>              opens the path for people writing their own virtual layouts).
>>
>>
>>
>>          One thing I wanted to mention is that these layout classes can
>>          probably be static (unless they need to keep some internal
>>          state like HBox.tempArray).  If I understand the logic, there
>>          is no need for the Layoutable interface either, the owner Node
>>          is merely delegates layoutChildren() to the corresponding
>>          layout class, passing all the necessary information (scale,
>>          snap, etc.)
>>
>>      If you want virtual layouts to compose, you need to be able to
>>      point at something.  Let's say you have a simple layout:
>>
>>          HorizontalLayout[ Graphic + Text ]
>>
>>      This can be relatively static, agreed.
>>
>>      However, if you want something more complicated:
>>
>>          HorizontalLayout[ Graphic + VerticalLayout[Title + Subtitle] ]
>>
>>      ...then how would the static call look like to HorizontalLayout?
>>
>>      Furthermore, HorizontalLayout would need to accept both Node and
>>      Layout somehow if they don't implement a common interface (so
>>      Object[] ?)
>>
>>      Also, layouts often have a ton of parameters to tweak: padding,
>>      alignment, spacing, margins, snapToPixel, etc... that's a lot of
>>      things to pass in to a static layout.  This quickly invites a
>>      "parameter" object, at which point you can just make the Layout an
>>      instance (which gives more flexibility for also caching things and
>>      other interal bookkeeping).
>>
>>      The best you can do as a "static" solution is to have some
>>      helpers, like the SpaceDistributor class I once created, but the
>>      actual layouts are *far* more complicated, and I don't think you
>>      can easily get away with having them just be a static method call.
>>
>>
>>          In other words, it might be possible to achieve the main goal
>>          of code reuse without any changes to the public APIs.  The
>>          layout classes can be made public later, once matured.
>>
>>      Only if you accept the layouts would be extremely limited (no
>>      mixing of Layouts and Nodes).
>>
>>      Regardless, there wouldn't be any changes to existing public API's
>>      by having Node implement Layoutable.  At most, there would be one
>>      or two methods to offer a better abstraction for just plainly
>>      exposing "getProperties()" on Layoutable.  Implementing an
>>      interface that exposes methods that Node already has is a source
>>      and binary compatible change.
>>
>>      --John
>>
>>
>>          What do you think?
>>
>>          -andy
> >

References

   Visible links:

   Hidden links:
   2. 
https://us-phishalarm-ewt.proofpoint.com/EWT/v1/ACWV5N9M2RV99hQ!N727doPOsOLk1ZPh99KUGFxSAPonZG2OpRgnfIayjZjm2sMdFNKyEO4PdWQHj7WicDRDdaYVkbL2xtbfFgRZPBGPs8LYnExgdJ4$

Reply via email to