[External] : Re: Unnecessary layouts; TLDR; new method "requestLocalLayout"

John Hendrikx john.hendrikx at gmail.com
Wed Apr 23 15:55:16 UTC 2025


Yeah, that's what I'm seeing, it happens on all kinds of actions, none
of which are triggering a resize that requires layout (like
opening/closing a TitledPane or resizing the whole Window).

--John

On 23/04/2025 16:45, Andy Goryachev wrote:
>
> Possibly related: https://bugs.openjdk.org/browse/JDK-8089992
>
>  
>
> -andy
>
>  
>
>  
>
> *From: *John Hendrikx <john.hendrikx at gmail.com>
> *Date: *Wednesday, April 16, 2025 at 16:13
> *To: *Nir Lisker <nlisker at gmail.com>, Andy Goryachev
> <andy.goryachev at oracle.com>
> *Cc: *openjfx-dev at openjdk.org <openjfx-dev at openjdk.org>
> *Subject: *[External] : Re: Unnecessary layouts; TLDR; new method
> "requestLocalLayout"
>
> I tested this with several controls that were triggering layouts (like
> on cursor movements), and I saw no adverse effects.  Basically, any
> time you interact with a control and it triggers a full layout but its
> bounds didn't change (ie. nothing in the UI changed position or size)
> the full layout was unnecessary.
>
> Most Skins/Controls do the simple thing of registering listeners on
> any properties that may change their appearance and calling
> requestLayout, while calling requestLayout should really be reserved
> for things that change their computeMin/Pref/Max values. If there were
> no changes in any of those, then the parent layout won't have changes
> either (and so on) so the final layout result will be the exact same
> as before, yet tens of thousands of calculations will have been done. 
> Because of how say HBox calculates its size, it also queries any
> siblings, which in turn may be containers...
>
> The only things "stopping" layout propagation are things like scroll
> panes.  This is why TextArea is a lot less likely to trigger a layout
> all the way to the root vs TextField.
>
> --John
>
> On 16/04/2025 17:04, Nir Lisker wrote:
>
>     Sounds good. Have you tried a prototype implementation for a
>     built-in JavaFX control/Pane, just to see how well it works?
>
>      
>
>     On Wed, Apr 16, 2025 at 5:50 PM Andy Goryachev
>     <andy.goryachev at oracle.com> wrote:
>
>         This might be a good idea from an API perspective, but please
>         be careful - this optimization might break the behavior. For
>         instance, the scroll bar might change as a result of a key
>         event in the TextArea, so the text layout is still needed,
>         however expensive.
>
>          
>
>         (and I like Michael's suggestion of naming the method
>         requestLayoutChildren())
>
>          
>
>         -andy
>
>          
>
>          
>
>          
>
>         *From: *openjfx-dev <openjfx-dev-retn at openjdk.org> on behalf
>         of John Hendrikx <john.hendrikx at gmail.com>
>         *Date: *Monday, April 14, 2025 at 08:56
>         *To: *openjfx-dev at openjdk.org <openjfx-dev at openjdk.org>
>         *Subject: *Unnecessary layouts; TLDR; new method
>         "requestLocalLayout"
>
>         I've been writing a container that does layout, and I've been
>         using it
>         extensively in my latest project.
>
>         I noticed that many skins and controls will call
>         requestLayout(), not
>         realizing that this will mark the current node + all parent
>         nodes with
>         `NEEDS_LAYOUT`.  This causes all those containers to call
>         `compute`
>         methods and execute their `layoutChildren`, even though your
>         control may
>         only have changed something that does NOT change its layout
>         bounds (like
>         a color, background, alignment or even things like a cursor
>         shape or
>         position).  These computations are expensive, involving
>         querying of all
>         children of each container to find out their min/pref/max
>         sizes, do
>         content bias calculations, splitting space over each control
>         and many
>         many snapXYZ calls -- all leading to no visual layout change...
>
>         For example, a TextArea or TextField will call requestLayout
>         on every
>         character typed, every cursor movement, and every text content
>         change. 
>         None of those affects their bounds (at least, in my
>         experience, these
>         controls are not continuously resizing themselves when I
>         scroll or type
>         things...).  TextField will even change its cursor shape every
>         time its
>         value is updated, even if that value is simply bound to a
>         Slider and the
>         field doesn't have focus at all -- this field will then
>         trigger layout
>         on itself and all its ancestors even if it is in a completely
>         unrelated
>         area of the UI (not close to the slider).
>
>         It seems that in many cases these controls and skins just want
>         their
>         layoutChildren method to be called, as their main layout logic is
>         located there -- duplicating this logic partially for every minor
>         property change that doesn't affect its bounds is error prone,
>         so I can
>         completely follow this reasoning.  However, using
>         requestLayout to get
>         layoutChildren called is very expensive.
>
>         There is a better way: call setNeedsLayout(true) -- this is a
>         protected
>         method that any Node has access to, and basically will only call
>         layoutChildren on your own Node.  It marks all the parent nodes as
>         `DIRTY_BRANCH`, which means that on a layout pass it will
>         traverse down
>         to see which nodes actually needs layout (it won't call
>         layoutChildren
>         for each ancestor, which is a big win).
>
>         Because of its protected nature (and its required parameter
>         which must
>         be true), it is a bit hard to use.  I'm thinking it might be a
>         good idea
>         to introduce a new method here, a request layout call that
>         schedules a
>         Node for layout without forcing all ancestors to do the same.
>         This way
>         Skin and Control designers can clearly see the two options and
>         choose
>         what is required:
>
>              requestLayout -- my bounds likely have changed (font change,
>         border/padding change, spacing change), so please call compute
>         methods
>         and redo the entire layout
>
>              requestLocalLayout -- my bounds have not changed (color
>         changes,
>         background changes, content changes within a ScrollPane,
>         cursor changes,
>         cursor position changes, alignment changes)
>
>         What do you think?
>
>         --John
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20250423/b3ab394e/attachment-0001.htm>


More information about the openjfx-dev mailing list