我在程序中注意到,当我调用NSRunAlertPanel()时,等待返回(用户尚未点击按钮)时,NSTimer()不会触发。它会定期激活,直到NSRunAlertPanel()行,但在用户单击对话框上的按钮之前不会再次调用。
即使对话框在屏幕上,有没有办法让计时器保持运行?
答案 0 :(得分:1)
警报面板正在启动自己的事件循环(通过-[NSApplication runModalForWindow:]
,与最初安排计时器的(可能是主要的)事件循环分开。这是为了防止用户与任何其他元素进行交互。应用程序,直到处理警报。
在我的脑海中,有两种方法可以让计时器在面板出现时仍然点亮:运行主运行循环,并将计时器添加到面板的运行循环中。老实说,我不确定其中任何一个是如何运作的。
对于第一个,您可以轻松地获得应用程序的主运行循环:[NSRunLoop mainRunLoop]
,然后将其告知runUntilDate:
将来短时间(不到一秒)。这将要求您设置一个(while
)循环,让主循环和模态运行循环交替运行一小段时间。这里的问题是让主运行循环处于活动状态将允许处理输入,从而破坏了面板的模态。
对于第二个,您只需参考计时器,然后执行[[NSRunLoop currentRunLoop] addTimer:forMode:]
。我在这里不确定的是计时器的开火日期如何与重新添加到另一个循环相互作用,但你可以尝试一下。
希望我是一个白痴,并且遗漏了一些非常明显的东西,并且很快会出现另一个答案并提供正确的解决方案。
答案 1 :(得分:1)
感谢W'rkncacnter的建议!以下是我的解决方案的清理版本。
将计时器放在屏幕上时,我使用:
timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTimer) userInfo:nil repeats:YES];
每秒调用以下代码:
- (void) updateTimer {
secondsRemaining--;
if (secondsRemaining <= 0) {
[timer invalidate];
[[NSApplication sharedApplication] abortModal];
[self finishStuff];
}
[self updateTimerText];
}
- (void) updateTimerText {
NSInteger seconds = (int) secondsRemaining;
NSInteger hours = seconds / (60 * 60);
seconds -= hours * (60 * 60);
NSInteger minutes = seconds / 60;
seconds -= minutes * 60;
[timerText setStringValue:[NSString stringWithFormat:@"%02ld:%02ld:%02ld", hours, minutes, seconds]];
}
请注意“abortModal”代码。如果NSRunAlertPanel()在计时器用完时打开,它将被关闭。 当我想显示对话框时,我运行以下代码:
[[NSRunLoop currentRunLoop] addTimer:timer
forMode:NSModalPanelRunLoopMode];
NSInteger buttonClicked = NSRunAlertPanel(@"Finish?", @"Are you sure you are done?", @"No", @"Yes", nil);
//"YES" clicked
if (buttonClicked == NSAlertAlternateReturn) {
[timer invalidate];
[self finishStuff];
}
请注意,我将计时器AGAIN添加到另一个运行循环 - 对于模态窗口。计时器仍在原始运行循环中,并在对话框关闭时继续。