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