Use ScenePulseListener to avoid expensive recalculations?
Tomas Mikula
tomas.mikula at gmail.com
Thu Nov 7 06:18:30 PST 2013
Hi Martin,
On Thu, Nov 7, 2013 at 2:32 PM, Martin Sladecek
<martin.sladecek at oracle.com> wrote:
> This is something different. When properties depends on each other (using
> bindings), the binding computation is deferred to the first query (get()
> call) of the dependant. That means, if q depends on p, you can call p.set()
> as many times you want, but the recomputation will be triggered just before
> first q.get() call.
The point of my first example was inconsistency.
Suppose this scenario (remember, the invalidation listeners of p are
deferred until the next pulse):
[pulse]
...
p.set()
...
q.get() // returned value not consistent with the value of p
...
[pulse]
I like my objects to appear consistent to the outside world at all
times, so that the client code doesn't have to deal with the
inconsistencies.
> Also in your second example, the second invalidation of
> s would be practically a no-op.
It is not if you have an invalidation (or change) listener registered on s.
Tomas
>
> Of course, this doesn't work if you have a ChangeListener on q, because the
> ChangeListener basically need to do get() in order to compute the new
> property value (which is passed as an argument to it's method).
>
> When it's not a property you want to recompute, but an internal state (you
> use to setup the children), layoutChildren() should be the method for you.
>
> -Martin
>
>
> On 11/07/2013 02:08 PM, Tomas Mikula wrote:
>>
>> On Thu, Nov 7, 2013 at 11:58 AM, John Hendrikx <hjohn at xs4all.nl> wrote:
>>>
>>> Hm, I found it googling, and since it showed up here:
>>>
>>>
>>> http://docs.oracle.com/javafx/2/api/javafx/scene/Scene.ScenePulseListener.html
>>>
>>> I figured it was public, but I just noticed the class is defined package
>>> private.
>>
>> Although not part of the public API, you can use
>>
>> import com.sun.javafx.tk.TKPulseListener;
>> import com.sun.javafx.tk.Toolkit;
>>
>> Toolkit.getToolkit().addSceneTkPulseListener(new
>> TKPulseListener(){...})
>>
>>
>> Anyway, I don't think deferring property invalidation until the next
>> pulse is very useful in general, for the following reasons:
>>
>> 1) It can lead to inconsistent observable state of your objects.
>> Consider an object with properties p, q, where the value of q depends
>> on the value of p, and consider changing the value of p. Now, right
>> after
>> p.set(x);
>> returns, the state of the object is inconsistent until the next pulse,
>> and this inconsistency is observable to the outside world.
>>
>> 2) It doesn't (in general) avoid recalculations. Consider properties
>> p, q, r, s, whose invalidation listeners are deferred until the next
>> pulse, with bindings
>> p <- q <- r <- s
>> p <- s
>> and consider changing the value of p in pulse 0. The invalidation
>> listeners will fire as follows:
>> pulse 1: p
>> pulse 2: q, s
>> pulse 3: r
>> pulse 4: s
>> As you see, the listeners of s are called twice, causing potentially
>> expensive recalculation.
>>
>> For these reasons, I'm in favor of the approach suggested by Yennick,
>> where you "commit" the properties yourself.
>>
>> Regards,
>> Tomas
>
>
More information about the openjfx-dev
mailing list