在事件处理程序

时间:2018-04-26 20:43:33

标签: macos events sleep drawrect

我已经尝试了我能想到的一切,但没有运气。

我有一个项目本质上是编程语言的“解释器”。因此事件被传递给解释器循环,解释的代码执行任何操作(在这种情况下,更新内存位图),然后解释器循环返回并且事件处理程序返回。最终调用app的drawRect,并将内存位图绘制到NSView。这一切都很好。

但是......在某些情况下,解释的'代码'想要导致短动画,并通过更新内存位图,usleep()几毫秒,更新内存位图,usleep( )动画需要不到一秒的时间,所以线程堵塞应该不是问题。

问题是没有动画显示,并且在解释的'代码'结束之后屏幕才会更新,并且事件会返回。

当解释的代码表明它想要睡眠时调用的睡眠函数如下所示:

void KSleep(DWORD tm) {

    if( [pView lockFocusIfCanDraw] ) {
        inSleep = true;
        [pView setNeedsDisplay:YES];
        [pView display];
        [pView drawRect:NSMakeRect(0, 0, pView.frame.size.width, pView.frame.size.height)];
        [pView unlockFocus];
    }
    usleep(tm*1000);
}

'inSleep'是我为测试目的设置的全局变量,'pView'是窗口唯一视图的全局NSView *。注意:是的,上面的一些代码是冗余的,我只是将它包含在内,以表明我已尝试过多种组合,试图向操作系统表明视图是脏的并更新它。他们都没有工作。

drawRect代码(删除所有执行按位运行blit的位图的代码)如下所示:

-(void)drawRect:(CGRect)rect {

    CGContextRef context = [[NSGRaphicsContext currentContext] graphicsPort];
    CGContextSaveGState(context);
    if( inSleep ) CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 1.0);
    else CGContextSetRGBFillColor(context, 1.0, 1.0, 0.0, 1.0);
    CGContextFillRect(context, CGRectMake(0,0,200,200));
    CGContextRestoreGState(context);
}

所以:
1)发生-mouseDown()事件,并使用事件调用解释器 2)解释后的代码绘制到位图(我忽略了这一点,因为它对于屏幕更新的工作或不工作并不重要),并调用“睡眠”。 3)解释器看到“睡眠”调用,调用Ksleep()(上图) 4)Ksleep锁定焦点,这似乎创建了一个上下文,因为没有它,调试器在drawRect()函数期间吐出0x0上下文的警告,并且使用lockFocus它没有并且似乎具有有效的上下文值。
5)Ksleep将视图标记为需要更新并调用(变化地)'display'和/或'drawRect'等。
6)drawRect例程得到控制(断点表明在这方面一切正常)。 'inSleep'设置正确。它按预期逐步完成drawRect中的所有内容。但是没有显示在显示屏上,直到...
7)drawRect返回Ksleep,睡眠超时,解释器保持解释,解释的代码做更多的绘图和更多的睡眠,大约10次(因此重复步骤2-7大约10次)。

从程序启动到鼠标操作导致“动画”尝试,在视图中绘制一个黄色矩形。一旦发生'动画'导致鼠标点击,NOTHING会在窗口中更新,直到动画完全结束(即使drawRect IS在整个动画尝试中执行多次),然后矩形变为蓝色。但断点显示,每次调用KSleep()例程时,执行都会通过drawRect('inSleep'为true)。

这是一个线程吗? (该程序没有明确创建任何线程。)

我并不是特别关注如何避免动画/ KSleep结构的建议,我意识到这不是首选的Macos方法,但这是尝试从其他地方移植旧项目,并修改'解释'代码以避免这种情况不可能。

感谢您的任何想法或建议。

1 个答案:

答案 0 :(得分:0)

我找到的解决方案是将所有解释器代码放入第二个线程,释放主线程以便能够更新显示。即使drawRect例程正在运行和绘制,在完成并返回当前“命令解释”循环之后,它才会被刷新到显示器。此页面包含有关该主题的大量信息: https://developer.apple.com/library/content/technotes/tn2133/_index.html

此外,所有'invalidate'调用/语句必须保存/缓冲到一个包含所有无效的公共“最小矩形”,然后在“命令解释”返回之后完成无效操作和/或之前睡眠()完成了。

PITA。