NSView setNeedDisplay:rect导致重绘比需要更大的区域

时间:2014-11-27 04:15:36

标签: objective-c xcode macos cocoa

我需要重绘部分NSView。

- (IBAction)onUpdateView:(id)sender
{
    NSRect updatedRect = ... // Redraw updated area only.
    [self.view setNeedsDisplayInRect:updatedRect];
}

当我使用这个简单明了的解决方案时,Quartz Debug会突出显示重绘区域的更多区域 - 直到视图的整个区域。

我注意到如果[NSView setNeedsDisplayInRect]的调用被推迟到下一个运行循环周期,或者我只是执行[runloop runUntilDate:+ 0],问题就会消失:

- (IBAction)onUpdate:(id)sender
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self setNeedsDisplayInRect:updatedRect];
    });
}

- (IBAction)onUpdateAndRunLoop:(id)sender
{
    [self.view setNeedsDisplayInRect:updatedRect];
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.0]]; // EEW
}

但是如果在mouseDown处理程序中调用setNeedsDisplayInRect,它可以在没有所有这些hackery的情况下工作:

-(void)mouseUp:(NSEvent*)event
{
    NSPoint p = [self convertPoint:[event locationInWindow] fromView:nil];

    int size = 100;
    [self setNeedsDisplayInRect:NSMakeRect(p.x-size/2, p.y-size/2, size, size)];
}

发生了什么,该怎么办?

此问题的孤立Xcode项目位于:http://beta.kalinsky.ru/wtf/testRedraw.tar.gz

1 个答案:

答案 0 :(得分:2)

是什么让你如此确定这是不良行为?我在Quartz Debugger下看到的行为表明,当我点击Update按钮时,点击按钮的矩形与传递的dirtyRect的矩形的交集会闪烁。这是预期的,因为系统在runloop(鼠标向上)的同一通道内合并所有需要的绘图以提高效率。

你的其他hacky方法绕过了这种行为,因为按钮的状态是在一个(实际上是两个:鼠标按下和鼠标按下)传递中处理的,你的视图更新是在后续传递中处理的。如果您密切注意延迟绘图点击中的更新闪烁(按钮闪烁,再次打开,然后视图的脏区闪烁),则会进行验证。点击视图本身不涉及任何其他东西(从技术上来说,它是非不透明的祖先),所以所有视图的脏集合的结合仅限于你请求的矩形。

我希望这会有所帮助。