On Wed, 21 Oct 2026 11:10:46 GMT, John Hendrikx <[email protected]> wrote:
>>> This is basically a general problem for any program that allows arbitrary
>>> callbacks (which in JavaFX are often hidden in events/listeners). Calling
>>> any callback while you're structure isn't in a fully consistent state is
>>> problematic if your code must continue working no matter what
>>
>> If I understand this correctly, this is not a problem per se, as long as the
>> process converges and has no loops. In other words, a single property
>> change might trigger a cascade of updates which must eventually settle.
>>
>> Once settled, the `layoutChildren()` does the layout and updates the scene
>> graph.
>>
>> Perhaps what we need is to detect the loops? Or am I missing something?
>>
>> --
>>
>> Another, related, scenario is when the update cascade requires explicit
>> layout pass (or N passes, as it happened in RichTextArea with N=2). It is
>> possible to let the multiple pulses do their job, at the risk of flicker or
>> perpetual layout going on (I've seen that). I think it is better to
>> explicitly acknowledge these cases and design for them.
>
> Layout is already special, it is done once per frame at most, and the
> deferral system (`requestLayout`) protects somewhat against the things that
> callbacks can do (and even then there is documentation stating you shouldn't
> be binding or modifying certain layout specific properties).
>
> Properties that defer calling their listeners already exist, because
> callbacks would interfere with whatever they're trying to achieve.
>
> Most user callbacks won't interfere, but almost any group of two properties
> that are being manipulated "as part of a whole" can be interfered with with a
> specially crafted listener on one of them. Loop detection only buys you that
> you notice that the properties are inconsistent (like the warning in #1081)
> but there's no route to fix it as any fix attempt can be thwarted by a
> listener user callback.
> > I do have a solution for this, that I use for my own programs. They're
> > basically a different kind of property that allows the owner of the
> > property (ie. the control, table, whatever) to control when listeners fire
> > (something we see already in some areas of FX where properties are
> > "customized" to delay firing, but that's usually manual and not coordinated
> > across multiple properties).
>
> I'm all ears. A solution to this problem in JavaFX would be great. Yeah
> JavaFX already uses this mechanism for e.g. `focusProperty` and it makes
> sense.
>
> > For example, if I need to change 3 properties, but they're all related
> > (let's say x,y,z) I can change all three, and only at the end of my changes
> > have the listeners fire.
>
> This is exactly what we need.
In my FX Flow library, I have a solution for externally read only properties
`UpdatableValue`, but general solutions can be built as well. It works like
this:
// these are private inside some class (like a ReadOnlyPropertyWrapper)
private final UpdatableValue<Double> x = UpdatableValue.of();
private final UpdatableValue<Double> y = UpdatableValue.of();
// UpdatableValue don't have a normal "set" or "setValue" method at all,
// instead manipulate using `UpdatableValue.set` method:
UpdatableValue.set(
x, 100, // these are all typed parameters, despite how it looks
y, 100
);
// or using `batch` method:
UpdatableValue.batch(() -> {
UpdatableValue.set(x, 100);
UpdatableValue.set(y, 100);
// supports nesting, can start another batch here, listeners only
// fire at the end of the top most level batch
});
// exposing as read only:
public final ObservableValue<Double> x() {
return x.asObservableValue();
}
For more arbitrary property manipulation, I've also got a different system, but
it requires wrapping all properties that should participate in a transaction.
If we ever add something like this to FX (where we can change the property code
itself) the wrapping may not be needed. The `UpdatableValue` system is more
light-weight, and works much more like how read only properties work.
-------------
PR Review Comment: https://git.openjdk.org/jfx/pull/2347#discussion_r4336229330