Dealing with nested events for a single property in JavaFX

steve.x.northover at oracle.com steve.x.northover at oracle.com
Thu Jun 21 17:17:28 PDT 2012


Exactly what is happening now?  Are we recursing ?  If so, although 
normally unwanted, I believe this is *correct*.  It allows very smart 
people to make a change, ignore the event caused by it and keep going by 
stacking a boolean state within a listener.  If we queue, then how do 
they do this?

Steve

On 21/06/2012 7:38 PM, Daniel Zwolenski wrote:
> Jonathan's second JIRA (http://javafx-jira.kenai.com/browse/RT-17772) uses
> a TextProperty with a ChangeListener, i.e. it is not limited to 'Event
> events'.
>
>
> On Fri, Jun 22, 2012 at 9:30 AM, Richard Bair<richard.bair at oracle.com>wrote:
>
>> No I believe the value would still be "true" immediately. And to be clear
>> I'm talking about Event events here, not change notification listeners. So
>> ActionEvent, MouseEvent, etc.
>>
>> But that does give pause to consider listeners as well. I don't think you
>> can queue those up. So specifically I think this issue is about whether:
>>
>> node.fireEvent(newEvent)
>>
>> is layered or queued, without having to be placed on the actual EventQueue
>> (ie: runLater).
>>
>> Richard
>>
>> On Jun 21, 2012, at 4:18 PM, Daniel Zwolenski wrote:
>>
>> It's not totally clear: I assume you are talking about a queue per
>> property? Or do you mean one big queue for all properties?
>>
>> In either case I think we introduce a potential problem with this. Let's
>> say we have:
>>
>>    BooleanProperty one;
>>    BooleanProperty two;
>>    two.bind(one);
>>
>> Then in normal code we do this:
>>
>>    one.set(true);
>>    two.get(); // value is 'true' as a result of binding
>>
>> But if we do the exact same code in a callback it has a different result:
>>
>>    one.onValueChanged() {
>>      one.set(true);
>>      two.get(); // value is 'false' as event hasn't been processed yet
>>    }
>>
>> With a queue per property the problem is limited to only when you are
>> listening on your own value and just maybe we could get away with that (I'm
>> not convinced though, 'feels' dangerous). With one big queue it is really
>> nasty as it would totally change the semantics of code depending on whether
>> it was being called from within a property callback or not.
>>
>>
>>
>> On Fri, Jun 22, 2012 at 8:54 AM, Richard Bair<richard.bair at oracle.com>wrote:
>>
>>> Right, so what it comes down to is: do we layer events, or queue events?
>>> RunLater is wrong because we might insert a pulse between events on the
>>> queue so you will render things incorrectly for some brief period of time.
>>>
>>> It seems like handling events sequentially as they occur is the right
>>> semantic, rather than the "onion" approach where partway through handling
>>> event 1 we issue event 2. The problem here is that event 2 is handled, and
>>> then the rest of event 1 is handled, which now has the wrong state (if it
>>> was carrying state related to that first event.
>>>
>>> Of course by queuing events it is possible people will end up with
>>> handling so many events that the app thread is always busy and not
>>> processing the queue -- but then they can get into infinite recursion and
>>> all kinds of other issues, so I don't see that as a problem but just the
>>> nature of the beast.
>>>
>>> Richard
>>>
>>> On Jun 21, 2012, at 3:47 PM, Jonathan Giles wrote:
>>>
>>>> The point is: can we have a better solution by considering changing the
>>> event API such that it queues events, rather than do them immediately as
>>> they are fired.
>>>> -- Jonathan
>>>>
>>>> On 22/06/2012 10:46 a.m., Slavko Scekic wrote:
>>>>> So, the point is: be careful? :)
>>>>>
>>>>> On Fri, Jun 22, 2012 at 12:39 AM, Jonathan Giles<
>>> jonathan.giles at oracle.com<mailto:jonathan.giles at oracle.com>>  wrote:
>>>>>     runLater is wrong more often than it is right - so you're right -
>>>>>     I don't think we should consider that approach (or requiring
>>>>>     people to have to know to do this)
>>>>>
>>>>>     Saying that you should error out when someone tries to update a
>>>>>     property in the event callback is also wrong, I think. There are
>>>>>     legitimate use cases, for example as a last ditch form of
>>>>>     validation: if the value is outside the allowable range, change it
>>>>>     back to something that is valid. Alternatively, when focus is
>>>>>     given to a node, request a focus change on another node. I imagine
>>>>>     our own code would blow up if we took this approach :-)
>>>>>
>>>>>     -- Jonathan
>>>>>
>>>>>
>>>>>     On 22/06/2012 10:31 a.m., Daniel Zwolenski wrote:
>>>>>
>>>>>         Similar to the ConcurrentModification thing you get with
>>>>>         Collections right? Could it be handled in a similar way, i.e.
>>>>>         throw an error if someone tries to update the property they
>>>>>         are modifying while in the update callback for that property?
>>>>>         As you say, it's user error, so slapping them on the wrists is
>>> ok.
>>>>>         The runLater one feels like it could cause its own problems to
>>>>>         me. The 'single' threadedness of JFX is part of it's design.
>>>>>         It gives me deterministic behaviour, this feels like it could
>>>>>         open up small cracks in that. Obviously we wouldn't get
>>>>>         concurrency/deadlock issues but I suspect we could get things
>>>>>         in a non-deterministic order as a result of this (e.g. if
>>>>>         another thread does a runLater somewhere else in the code at
>>>>>         the same time this runLater is being added). Could end up that
>>>>>         my property change is overwritten sometimes but not others,
>>>>>         etc (I'm going more off gut feel here though than concrete
>>>>>         examples).
>>>>>
>>>>>
>>>>>         On Fri, Jun 22, 2012 at 8:20 AM, Jonathan Giles
>>>>>         <jonathan.giles at oracle.com<mailto:jonathan.giles at oracle.com>
>>>>>         <mailto:jonathan.giles at oracle.com
>>>>>         <mailto:jonathan.giles at oracle.com>>>  wrote:
>>>>>
>>>>>            Hi all,
>>>>>
>>>>>            I'm going to keep this brief as I'm fairly comprehensively
>>>>>            underwater on the bug count.
>>>>>
>>>>>            Recently I've found a pattern of bug that, well, I'm fairly
>>>>>         sure
>>>>>            is due to user error, but is not obvious at all (and as such
>>> it
>>>>>            leads to bug reports). In the last week, I've encountered
>>> this
>>>>>            issue twice. The basic issue is that of listening to an
>>>>>         event (for
>>>>>            example, a focus change event), and reacting in such a way
>>>>>         as to
>>>>>            modify the state of this property (which results in another
>>>>>         event
>>>>>            being fired). The end result is non-deterministic (but often
>>>>>            broken behavior). Interestingly, it has in both my cases
>>>>>            manifested itself as something that works once, and then
>>> fails
>>>>>            after that forever more.
>>>>>
>>>>>            In both cases, after much code digging and debugging
>>> (although
>>>>>            today was made much easier by the same issue last week), I
>>>>>         believe
>>>>>            the issue can be worked around simply by wrapping the change
>>> to
>>>>>            the property state (in the event callback) with a
>>>>>            Platform.runLater(new Runnable() { ...}). This forces the
>>>>>         second
>>>>>            property update to happen after the first event has finished
>>>>>            firing (at some point in the future).
>>>>>
>>>>>            However, this isn't a great solution - we're forcing the
>>>>>         event to
>>>>>            fire at a later date where the state may have already
>>>>>         changed. The
>>>>>            better solution, in my opinion, is to improve the event
>>> system
>>>>>            such that it knows whether an event is already firing, and
>>>>>         if so
>>>>>            it will queue up the event to run after the current one has
>>>>>            finished. I would be interested in hearing whether anyone
>>>>>         else has
>>>>>            encountered this kind of bug, or whether they have better
>>>>>         suggestions.
>>>>>
>>>>>            You can see two examples of this bug in the code attached
>>> here
>>>>>            (where the first example is for ComboBox where the value is
>>>>>            updated in the onAction callback....which is called when
>>> value
>>>>>            changes):
>>>>>
>>>>>         http://javafx-jira.kenai.com/browse/RT-22478
>>>>>         http://javafx-jira.kenai.com/browse/RT-17772
>>>>>
>>>>>            -- Jonathan
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>
>>>
>>


More information about the openjfx-dev mailing list