Isn't it somewhat counter-intuitive to perform such changes in one of the computePref*() methods? You're adding children in a method which is supposed to compute the preferred width/height.
There should be a better way to do this. In Apache Flex for example, there's a commitProperties() and updateDisplayList() method in which you can do these things, which are called somewhat similar to a pulse in JavaFx (except that you have to invalidate them yourself). On Tue, Nov 5, 2013 at 8:10 PM, Jonathan Giles <jonathan.gi...@oracle.com>wrote: > You're right in that controls don't tend to use ScenePulseListener. This > may be due to an oversight on our part, or just that our requirements > differ (I don't honestly know). > > You're also right that it is important to batch up property changes and > do them once per pulse, rather than as they come in. If this is not done > you do indeed get a severe performance hit (I remember back in the day > before I optimised many of the controls in this way, the performance > impact of not doing this was staggering). > > The way I do it is simple: in places where I receive events from > properties / bindings / listeners, where I know that there is > potentially a lot of changes coming through, I create a boolean (e.g. > 'refreshView' or somesuch). I then set this boolean to true, and in the > appropriate place in the code (most commonly layoutChildren(), but > sometimes in the computePref*() methods), I start the method with code > like this: > > if (refreshView) { > doExpensiveOperationThatShouldHappenOnlyOncePerPulse(); > refreshView = false; > } > > The reason why I sometimes use layoutChildren() and sometimes the > computePref*() methods comes down to the (new) rule in JavaFX 8.0 that > you can not change the children list of a node within the > layoutChildren() method. Because of this, if I need to modify the > children list, I put the above code in the computePref*() method. > > I hope that helps. > > -- Jonathan > > On 6/11/2013 3:58 a.m., John Hendrikx wrote: > > Hi List, > > > > I'm considering using a ScenePulseListener to avoid expensive > > recalculations when multiple bindings trigger an action. > > > > My problem is this: > > > > I like to build Views (Controls) that are dumb and expose properties > > that can be manipulated by whatever is using the View. The View > > listens to its own Properties and adjusts its state accordingly. Some > > of these adjustments are related (like width + height) and can be > > expensive when calculated immediately. So I would like to mark the > > View as "invalid" and recalculate its state (if invalid) on the next > > Pulse. > > > > My current use case I'm looking at is a View that wraps (amongst > > others) a TreeView. The View exposes an ObservableList and a > > BooleanProperty that decides whether the first level of the Tree > > should be displayed as Tabs or as Nodes (which has an impact on what > > Nodes actually are added to the TreeView, and which are added as > > Tabs). User code will thus often set a new list of nodes + change the > > boolean to show tabs or nodes. The View currently naively has > > InvalidationListeners on both of these properties which cause > > TreeNodes to be created after the first change... then discarded and > > recreated after the second change by the user code, ie: > > > > view.nodesProperty().setAll(nodes); // Recreates all > > Tabs/TreeNodes with the current value of expand top level, as we donot > > know another change might be incoming... > > view.expandTopLevelProperty().set(false); // Recreates all > > Tabs/TreeNodes again if expand top level was changed... > > > > This specific problem might be done in a better way, but the point > > remains, how do I avoid expensive calculations when multiple > > properties get changed one after the other by the user code? I'm > > assuming that JavaFX controls already avoid these kinds of things, and > > I'd like to know whether using a ScenePulseListener is the way to go, > > or that it can/should be done in a different way -- examining the code > > for TreeView (and its superclasses), I couldn't find uses of > > ScenePulseListener... > > > > --John > > > > > > > > > >