我想尽了一切办法,但运气不好。
我有一个项目,本质上是一种编程语言的“解释器”。因此,事件被传递到解释器循环,被解释的代码执行任何操作(在本例中,更新内存位图),然后解释器循环返回,事件处理程序返回。最终会调用应用程序的drawRect,并将内存位图绘制到NSView。大多数时候这一切都很好。
但是在一些情况下,解释的“代码”想要产生一个短动画,并通过更新内存位图、usleep()'ing几毫秒、更新内存位图、usleep()'ing等来实现。动画只需要不到一秒钟的时间,因此线程阻塞不应成为问题。
问题是没有任何动画显示,直到解释的“代码”结束,事件返回后,屏幕才会更新。
当解释的代码指示要睡眠时,调用的睡眠函数如下所示:
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代码(删除所有执行位图常规blitting的代码)如下所示:
-(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) 解释器看到“sleep”调用,调用Ksleep()。
4) Ksleep锁定焦点,它似乎创建了一个上下文,若并没有它,调试器会在drawRect()函数期间发出0x0上下文的警告,而使用lockFocus则不会并且似乎有一个有效的上下文值。
5) Ksleep将视图标记为需要更新,并调用(varyingly)“display”和/或“drawRect”等。
6) drawRect例程确实获得了控制(断点表示在这方面一切正常)。'inSleep'设置正确。它按预期逐步完成drawRect中的所有内容。但是显示屏上什么也没有显示,直到。。。
7) drawRect返回到Ksleep,睡眠超时,解释器继续解释,解释的代码进行更多的绘制和睡眠,大约10次(因此重复步骤2-7大约10次)。
从程序启动到鼠标操作导致“动画”尝试,视图中会绘制一个黄色矩形。一旦发生导致鼠标点击的“动画”,在动画完全完成之前,窗口中不会更新任何内容(即使在整个动画尝试中多次执行drawRect),然后矩形变为蓝色。但断点表明,每次调用KSleep()例程时,执行都会通过drawRect(inSleep为true)。
这是线的东西吗?(程序没有显式创建任何线程。)
我并不是特别想寻求关于如何避免动画/KSleep结构的建议,我意识到这不是Macos的首选方法,但这是一种从其他地方移植旧项目的尝试,修改“解释”代码以避免这种情况是不可能的。
感谢您的任何想法或建议。