Re: how to prevent TableView update on key repeat?
Re: how to prevent TableView update on key repeat?
- Subject: Re: how to prevent TableView update on key repeat?
- From: Marc Respass <email@hidden>
- Date: Fri, 04 May 2012 15:39:31 -0400
El may 4, 2012, a las 1:02 p.m., Quincey Morris escribió:
> On May 4, 2012, at 08:25 , Marc Respass wrote:
>
>> When I set the delay to zero, there is no delay. My selector is called immediately as if I didn't change anything.
>
>
> Not exactly. Consider what happens when you mash the arrow key. Thus, there might be multiple (normal) key events queued. The selector won't actually be performed until they're *all* dequeued from the main event queue (because, presumably, any queued perform is further down the queue).
>
> At that point, no subsequent key events can be dequeued until the update has run. IOW, there's a slight hitch every time the event queue empties of key events. That's *much* better than the original (non-performSelector) approach, because at least some of the updates are suppressed.
>
> So a delay of 0 helps key-mashers (and doesn't penalize other methods of selection change, such a click). It doesn't help the key-repeat case very much. Trying to solve the repeat case like this is a neat idea:
>
>> I added this to determine what the delay interval should be
>>
>> NSTimeInterval delayInterval = 0.0;
>> NSEvent *event = [NSApp currentEvent];
>>
>> if(event != nil && [event type] == NSKeyDown && [event isARepeat])
>> {
>> delayInterval = [NSEvent keyRepeatInterval] + 0.01;
>> }
>>
>> [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(selectionDidChange) object:nil];
>> [self performSelector:@selector(selectionDidChange) withObject:nil afterDelay:delayInterval];
>
> but it still has the drawback that there's an additional '[NSEvent keyRepeatInterval] + 0.01 + timeToUpdateDetailView' delay after the last one, during the latter part of which the user is frozen out of the UI.
>
> Let's say, though, that you wanted to pursue the approach that the above code represents. In that case, I probably *would* subclass the table view, and override keyDown: and keyUp:. You could simply set a flag at key down and clear it at key up, and use that information to control the way the performSelectors are timed. (It's still something of a hack, but at least it keeps the NSEvent details out of your selectionDidChange code.)
>
> However, once you get to this level of complexity, then it's probably worthwhile to spend your effort on moving the time-consuming part of the update process into a background thread instead. That would solve the problem for realz, letting keys repeat at their proper rate and letting updates happen as soon as they're ready, without freezes and artificial delays.
>
>> The objection to that was that I don't know what the current event is. If that is true, when [NSApp currentEvent] is useful? It seems that the current event will be the one that caused tableViewSelectionDidChange: to be called.
>
> It's useful when you know that you dequeued the last event and that you haven't dequeued another one since. In this case, you know that the table view dequeued a key event, but you don't know what it did after that. It *might* have created a background async GCD block to do the selection pre-processing, then executed a completion handler on the main thread to send the notification that triggered your method. Or, it *might* have looked ahead in the main event queue and dequeued some event.
>
> Even if you determined empirically that [NSApp currentEvent] gives you the key event, you can't be sure it will continue to do so in future frameworks versions.
Thanks again. Ideally, the update method would just be fast but it is now as fast as it is going to get. The problem that I want to solve is delay update during key-repeat (which is something that Mail does very well).
I subclassed NSTableView adding BOOL isRepeating. I set isRepeating = YES in keyDown: if isRepeating == NO && event isARepeat and isRepeating = NO in keyUp:. I replaced my tableViewSelectionDidChange: with the following.
CMTableView *tableview = [notification object];
NSTimeInterval delayInterval = 0.0;
if(tableview.isRepeating)
{
delayInterval = [NSEvent keyRepeatInterval] + 0.01;
}
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(selectionDidChange) object:nil];
[self performSelector:@selector(selectionDidChange) withObject:nil afterDelay:delayInterval];
If not repeating, update right now. If repeating then delay. Now, the delay is in affect if repeating so tying it to keyRepeatInterval makes sense. Otherwise, the table updates right away. This is working great. What do you think?
Thanks again for the help. It's been really valuable. Events and Run Loop are weak areas for me so I'm learning a lot here.
Marc
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden