LayoutChildren documentation
Johan Vos
johan.vos at gluonhq.com
Sun Sep 11 08:52:48 UTC 2022
Hi John,
This is not a solution for your specific problem (new children added
without CSS being applied), but in general, I have run into similar issues
many times. I find the JavaFX JavaDoc very valuable for most JavaFX
application developers, but for lower-level library development, or for
JavaFX core development, there are a number of things that are crucial but
not in the javadoc.
One of the key things I often have to almost reverse engineer, is the exact
flow that happens when a pulse is requested (e.g. Toolkit.java,
QuantumToolkit.java and the Scene.ScenePulseListener).
I personally don't think JavaDoc is the best place to address this, as it
might confuse the app developers. I think the openjfx wiki would be a good
place for this but it requires time and a good understanding (which
requires even more time).
The page at https://wiki.openjdk.org/display/OpenJFX/Graphics provides the
skeleton that can be the basis for this. As usual, the problem is that time
spent on this can not be spent in fixing bugs -- although in the
medium/long term, having this improved semi-internal (or at least
lower-level) doc would allow more developers to fix issues faster.
- Johan
On Sun, Sep 11, 2022 at 8:10 AM John Hendrikx <john.hendrikx at gmail.com>
wrote:
> TLDR; I think layoutChildren should mention it is not a good practice to
> modify the list of children during the layout pass as CSS won't be
> applied to them for 1 rendered frame, and perhaps mention a solution
> (Scene#addPreLayoutPulseListener?)
>
> I've been recently bit by an issue that I think might need to be
> documented a bit better.
>
> LayoutChildren is typically overriden for custom layouts.
>
> It's documentation:
>
> * Invoked during the layout pass to layout the children in this
> * {@code Parent}. By default it will only set the size of managed,
> * resizable content to their preferred sizes and does not do any node
> * positioning.
> * <p>
> * Subclasses should override this function to layout content as
> needed.
>
> A custom layout can be simple, but sometimes may involve adding or
> removing children dynamically based on the content of the control. What
> layoutChildren here does not mention is that if you add children during
> layoutChildren, there will be 1 rendered frame where these children
> don't have any CSS styling applied. The system detects however that
> children were modified and layoutChildren will be called again (in the
> same pass AFAIK), resulting hopefully in a stable set of children.
>
> The problem here is the fact that a frame is rendered without any CSS
> applied. For applications using a black background in general, the new
> children with a white background will cause a temporary "white flash" to
> be rendered. It took me ages to figure out where it came from, and it
> wasn't always easy to reproduce (if the children already existed, they
> were just modified, it only happened for cases where new children had to
> be added during the layout pass and which were clearly visible somewhere).
>
> Obviously, changes to CSS files had no effect on solving this (like
> setting everything to have a black or transparent) background at ".root"
> level.
>
> Calling #applyCSS on the newly added children during #layoutChildren
> does not solve the problem. Still one frame is rendered without CSS, and
> a white flash occurs.
>
> Adding the children during the #computeXXX methods is too late as well,
> the CSS pass has finished already by that time. This does however avoid
> having #layoutChildren called again in the same pass if children are
> added. There is this issue that relates to this:
> https://bugs.openjdk.org/browse/JDK-8091873 where it is suggested to
> perhaps add a more general method for this.
>
> What I needed is a callback for my control before layout occurs and
> before CSS is applied.
>
> Scene has a #addPreLayoutPulseListener which mentions it is called
> before CSS is applied. Its #addPostLayoutPulseListener counterpart also
> mentions `AnimationTimer` as a way to get a callback before CSS is
> applied. Implementing this call back and changing the list of children
> there solved the "white flash" problem. It feels a bit overkill though
> to listen to every pulse on a Scene just for the layout of one control
> (that may not need layout during most passes).
>
> Aside from changing the documentation to ensure people understand that
> modifying the list of children during layout can have temporary CSS
> issues, I'm wondering what would be the preferred solution to this
> problem. Is there a different way of handling this that I haven't found,
> aside from the #addPreLayoutPulseListener or AnimationTimer ? If not,
> could the issue (https://bugs.openjdk.org/browse/JDK-8091873) perhaps be
> resolved by adding two methods? One that is called before CSS is
> applied, and one before any compute methods are called? If adding a
> method that is called before CSS, is there even a way to determine if a
> Node needs this call to prevent calling it on every Node on every layout
> pulse?
>
> The current solution I'm using is like 15 lines of code as part of a
> ListView skin:
>
> private final Runnable pulseListener = () -> content.manageCells();
>
> private void updatePreLayoutPulseListener(Scene old, Scene current) {
> if(old != null) {
> old.removePreLayoutPulseListener(pulseListener);
> }
> if(current != null) {
> current.addPreLayoutPulseListener(pulseListener);
> }
> }
>
> And in the constructor:
>
> updatePreLayoutPulseListener(null, skinnable.getScene());
>
> skinnable.sceneProperty().addListener((obs, old, current) ->
> updatePreLayoutPulseListener(old, current));
>
> And in dispose:
>
> updatePreLayoutPulseListener(skinnable.getScene(), null);
>
> --John
>
>
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/openjfx-dev/attachments/20220911/47ba6850/attachment-0001.htm>
More information about the openjfx-dev
mailing list