Threading and Node.lookup

Philipp Dörfler phdoerfler at gmail.com
Thu Mar 21 04:33:39 PDT 2013


I created another gist showing that just attaching to a Scene is not enough:
https://gist.github.com/phdoerfler/5212324

This code is running in the FX application thread. Showing the stage fixes the lookup. Running the code in Platform.runLater does - as expected - not buy you anything extra.
This seems obvious, but I remember having some code which does different things depending on whether it's running inside of Platform.runLater, even when already running in the FXAT. That was ScalaFX code however running in a DelayedInit trait.

~ philipp

Am 20.03.2013 um 14:42 schrieb Scott Palmer <swpalmer at gmail.com>:

> #3 doesn't appear to be a requirement.
> 
> Re #4 If you have attached a Scene you had to do it on the FX Application thread, so runLater probably doesn't buy you anything.
> 
> It seems that just being attached to the Scene is the requirement.
> 
> Scott
> 
> On 2013-03-20, at 7:27 AM, Philipp Dörfler <phdoerfler at gmail.com> wrote:
> 
>> So in order to reliably lookup a node, one has to:
>> 
>> 1. Create a Scene with that scenegraph in it
>> 2. Attach that Scene to a Stage
>> 3. Show that Stage
>> 4. OR alternatively (does not help always), call this without a Scene, but in Platform.runLater
>> 
>> This this a bit too arcane for my taste. I can see that due to limitations one has to create a Scene and place nodes in there. I can't say I'm exceptionally happy with that, but it'll do for now. Those restrictions are probably there for a reason.
>> However - I don't entirely understand why sometimes it is necessary to actually _show_ a Stage with your nodes to have CSS lookups work (As indicated by John. I ran into this, too). Any chance that this might change? I'm not talking about querying CSS attributes unknown to that point. Only thing I want to do are simple lookups.
>> Is it because of Skin and that it is unknown how exactly the scene graph is composed without evaluating all Control's skins, thus creating more nodes which then might in turn have CSS style-classes (or IDs for that matter) assigned? Is this only possibly by showing a stage?
>> 
>> Assuming that this is not going to change any time soon: Is it possible to re-invent the wheel, thus manually traversing the scene graph and querying each and every node for it's id and style class and so on or would that need to be attached to a Scene (and thus runLater...) and/or need to be shown, too?
>> 
>> Cheers and thanks for your time,
>> ~ Philipp
>> 
>> Am 20.03.2013 um 11:20 schrieb Kevin Rushforth <kevin.rushforth at oracle.com>:
>> 
>>> There are some limitations in the CSS engine that require it to be attached to the scene before it will process nodes. I ran into this with snapshot, so a common workaround for apps that want to take a snapshot of a Node that isn't attached to a scene is to create a dummy Scene and attach the node in question to that Scene. See http://javafx-jira.kenai.com/browse/RT-22558 for example.
>>> 
>>> -- Kevin
>>> 
>>> 
>>> Richard Bair wrote:
>>>> Actually in this case the CSS engine should process immediately (it won't batch up this call, it must be synchronous) -- however it may be that there are some shared data structures being foiled by multiple threads. Not sure though, just a wild guess :-)
>>>> 
>>>> On Mar 20, 2013, at 12:41 AM, Tom Schindl <tom.schindl at bestsolution.at> wrote:
>>>> 
>>>> 
>>>>> Hi,
>>>>> 
>>>>> The problem is that the lookup system depends on the CSS-Engine (you can
>>>>> pass any CSS-Selector!) to having processed the Node.
>>>>> 
>>>>> My guess is that the CSS-Engine does only processes nodes when they are
>>>>> attached to the Scene (there's no reason for it to process them if they
>>>>> are not attached).
>>>>> 
>>>>> Tom
>>>>> 
>>>>> Am 20.03.13 04:47, schrieb Scott Palmer:
>>>>> 
>>>>>> Yes, good point.  In that case I could delay the connection to the Scene object and instead do the lookup via the root node.  But still in this case, has a rendering pass ("pulse") happened yet on such a Scene?  Since Scene objects must be constructed and modified on the FX app thread I guess it makes sense that they would do an initial layout pass on the root node?  So perhaps John is correct.  It's late and I don't have time to construct a test case now.
>>>>>> 
>>>>>> Scott
>>>>>> 
>>>>>> 
>>>>>> On 2013-03-19, at 10:35 PM, Kevin Rushforth <kevin.rushforth at oracle.com> wrote:
>>>>>> 
>>>>>> 
>>>>>>>> Node background = scene.lookup("#background");
>>>>>>>> 
>>>>>>> Note that this particular call references a scene, so must be done on the FX application thread. You should not touch the scene or a node that is connected to a scene on a background thread.
>>>>>>> 
>>>>>>> -- Kevin
>>>>>>> 
>>>>>>> 
>>>>>>> 
>>>>>>> Scott Palmer wrote:
>>>>>>> 
>>>>>>>> On 2013-03-19, at 8:30 PM, John Smith <John_Smith at symantec.com> wrote:
>>>>>>>> 
>>>>>>>> 
>>>>>>>>> "the node lookup function doesn't function (just returns null) until a rendering pass has been run on the scene"
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>> I don't think that is exactly right.  I'm sure I used the lookup method to grab nodes from a scene graph that I made with Scene Builder *prior* to showing it.
>>>>>>>> 
>>>>>>>> Yep… I just checked my code, this doesn't return nulls:
>>>>>>>> 
>>>>>>>>>>>>>>>> Parent root = FXMLLoader.load(location);
>>>>>>>> Scene scene = new Scene(root);
>>>>>>>> Node top = scene.lookup("#top");
>>>>>>>> Node background = scene.lookup("#background");
>>>>>>>>>>>>>>>> 
>>>>>>>> The Scene clearly was just constructed and isn't showing or part of a Stage.
>>>>>>>> The only difference is that this is called on the Platform thread. So something must be happening that needs to run on the Platform thread.
>>>>>>>> 
>>>>>>>> You are correct about the width/height stuff that requires a layout pass to have happened before you get reasonable values.
>>>>>>>> 
>>>>>>>> Scott
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> 
>>>>>>>>> +1 to Philipp's question.
>>>>>>>>> 
>>>>>>>>> It's always been the case that the node lookup function doesn't function (just returns null) until a rendering pass has been run on the scene.
>>>>>>>>> 
>>>>>>>>> With Philipp's sample at (https://gist.github.com/phdoerfler/5201162) , if you implemented it as an Application, placed the item to be looked up in a stage, and called lookup only *after* you called stage.show on your scene, then the lookup would work (without requiring Platform.runLater) - so some side effect of showing the scene on the stage allows nodes in the scene to be looked up.
>>>>>>>>> 
>>>>>>>>> It works the same way as trying to get the height and width of a node before it has been shown on stage - that also does not really work as you might expect because the css needs to be processed in the rendering pass to accurately determine the height and width.  I understand why height and width work the way they do, but I was never really sure why lookup doesn't just work immediately and the delayed behavior isn't documented anywhere.
>>>>>>>>> 
>>>>>>>>> Likely there is some hidden impl_ function you could use to trigger the rendering pass, after which the lookup would work.
>>>>>>>>> 
>>>>>>>>> - John
>>>>>>>>> 
>>>>>>>>> -----Original Message-----
>>>>>>>>> From: openjfx-dev-bounces at openjdk.java.net [mailto:openjfx-dev-bounces at openjdk.java.net] On Behalf Of Kevin Rushforth
>>>>>>>>> Sent: Tuesday, March 19, 2013 4:50 PM
>>>>>>>>> To: Philipp Dörfler
>>>>>>>>> Cc: openjfx-dev at openjdk.java.net List
>>>>>>>>> Subject: Re: Threading and Node.lookup
>>>>>>>>> 
>>>>>>>>> One of the scene graph or FXML folks should be able to reply.
>>>>>>>>> 
>>>>>>>>> -- Kevin
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>> Philipp Dörfler wrote:
>>>>>>>>> 
>>>>>>>>> 
>>>>>>>>>> Ok, threading aside: Where's my mistake?
>>>>>>>>>> 
>>>>>>>>>> https://gist.github.com/phdoerfler/5201162
>>>>>>>>>> 
>>>>>>>>>> ~ philipp
>>>>>>>>>> 
>>>>>>>>>> Am 20.03.2013 um 00:30 schrieb Kevin Rushforth <kevin.rushforth at oracle.com>:
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>> 
>>>>>>>>>>>> As to my understanding, one only has to use Platform.runLater for accessing nodes already attached to a Scene.
>>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>>>>> In general is is legal to call accessor and mutator methods on a Node not attached to a Scene from any thread. I don't specifically know whether lookup does anything that would add additional threading restrictions.
>>>>>>>>>>> 
>>>>>>>>>>> -- Kevin
>>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>>>> Philipp Dörfler wrote:
>>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>>>> 
>>>>>>>>>>>> Hi,
>>>>>>>>>>>> 
>>>>>>>>>>>> does fooNode.lookup("#bar") have to be called using Platform.runLater if fooNode is not attached to any Scene?
>>>>>>>>>>>> As to my understanding, one only has to use Platform.runLater for accessing nodes already attached to a Scene.
>>>>>>>>>>>> 
>>>>>>>>>>>> However, fooNode.lookup seems to fail (= return null) for nodes which are not contained directly in it, but in another node (in my case: a ScrollPane), which is then contained in fooNode. The scene graph was provided by FXMLLoader.load(...).
>>>>>>>>>>>> 
>>>>>>>>>>>> Placing those lookups in Platform.runLater suddenly causes them to work.
>>>>>>>>>>>> 
>>>>>>>>>>>> This feels like an arcane bug to me, but I might be missing some core concepts.
>>>>>>>>>>>> So - did I miss something or is this a bug?
>>>>>>>>>>>> 
>>>>>>>>>>>> Cheers,
>>>>>>>>>>>> Philipp
>>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>>>>>> 
>>>>>>>> 
>>>>> -- 
>>>>> B e s t S o l u t i o n . a t                        EDV Systemhaus GmbH
>>>>> ------------------------------------------------------------------------
>>>>> tom schindl                 geschäftsführer/CEO
>>>>> ------------------------------------------------------------------------
>>>>> eduard-bodem-gasse 5-7/1   A-6020 innsbruck     fax      ++43 512 935833
>>>>> http://www.BestSolution.at                      phone    ++43 512 935834
>>>>> 
>>>> 
>>>> 
>> 
> 



More information about the openjfx-dev mailing list