关于 NSApp 的 ModalForWindow、NSAlert 的 ModalForWindow 和 ModalSession 的提示
我进行了大量的实验才消除了对 Objective-C 的“ModalForWindow”语言以及随后如何使用模态会话的一些困惑。也许以下提示会节省一些时间:(
如果您对这个概念不熟悉:当窗口(通常是面板)运行模式时,它会阻止应用程序的其他部分响应,直到它被关闭为止。)
“ ModalForWindow”在不同的情况下意味着不同的东西。 如果您使用 loadNibNamed 来显示由 xib 定义的面板,并且希望它以模态方式运行,请在显示后调用此方法:
// Make panelReviewImports modal, so that no other part of app will respond.
[[NSApplication sharedApplication] runModalForWindow:self.panelReviewImports];
并在其解除方法中跟进此操作:
[[NSApplication sharedApplication] stopModal];
但对于 NSAlert,beginSheetModalForWindow 中的“窗口”指的是警报将作为工作表附加的窗口,该窗口将被冻结,直到警报被解除。但应用不会被冻结;所有其他窗口将保持可操作状态。 如果您想以表格形式附加提醒,并且还 冻结应用程序的其余部分,在 beginSheet 代码之后简单调用 runModal 并显式使用返回代码,如下所示:(
[alert beginSheetModalForWindow:self.window
modalDelegate:self didEndSelector:@selector(abandonmentAlertDidEnd:returnCode:contextInfo:)
contextInfo:nil];
NSInteger returnCode = [alert runModal];
[self abandonmentAlertDidEnd:alert returnCode:returnCode contextInfo:nil];
当然,您将已将放弃AlertDidEnd:returnCode:contextInfo: 代码实现为类方法。)
或者,如果您希望警报作为居中面板运行,请自行调用 runModal。
假设您要运行面板模式,然后在用户提交无效条目时发出警报。在显示警报之前,您必须停止 Modal - 之后,由于某种原因,对 runModalForWindow 的另一次调用无法正常工作。对于这种情况,您需要一个模态会话:
1) 将 NSModalSession 属性添加到您的控制器类中,因为 modalSession 必须可跨多个方法访问。
2) 显示面板后,调用 beginModalSessionForWindow 来实例化 modalSession:
self.modalSession = [[NSApplication sharedApplication] beginModalSessionForWindow:self.panelForInput];
3) 接下来是一个调用 runModalSession 的 while 循环,当其返回值不等于 NSRunContinuesResponse 时中断:
while ([[NSApplication sharedApplication] runModalSession:self.modalSession] == NSRunContinuesResponse)
continue;
循环将中断,应用程序将在以下情况下释放:用户单击面板的按钮之一。 (在面板的文本字段中键入内容将使模态会话保持不变。)
4) 在按钮处理中,如果用户的输入无效,则使用 runModal 调用警报。
5) 紧接在警报调用下方,在警报解除后将执行的代码中,放置与上面使用的相同的 while 循环。专家组的模式会议恢复。
6) 在处理关闭面板时,无论是在有效输入还是取消时,您都调用 endModalSession,奇怪的是,这还不够;即使您从未调用过 runModalForWindow,您也必须调用 stopModal。
[[NSApplication sharedApplication] endModalSession:self.modalSession];
[[NSApplication sharedApplication] stopModal];
[self.panelForInput close];
It took me quite a bit of experimentation to clear up some confusion over Objective-C’s “ModalForWindow” language and, subsequently, how to use a modal session. Maybe the following tips will save somebody some time:
(In case you’re new to the concept: When a window, usually a panel, runs modal, it prevents some other part of the app from responding until it has been dismissed.)
“ModalForWindow” means different things in different circumstances.
If you are using loadNibNamed to display a panel defined by a xib and you want it to run modal, call this once it is displayed:
// Make panelReviewImports modal, so that no other part of app will respond.
[[NSApplication sharedApplication] runModalForWindow:self.panelReviewImports];
and follow up with this in its dismissal methods:
[[NSApplication sharedApplication] stopModal];
But for NSAlert, the “window” in beginSheetModalForWindow refers to the window to which the alert will be attached as a sheet, which window will be frozen until the alert is dismissed. But the app won’t be frozen; all other windows will remain operable.
If you want to attach an alert as a sheet and also
freeze the rest of the app, follow the beginSheet code with a simple call to runModal and use the return code explicitly, like this:
[alert beginSheetModalForWindow:self.window
modalDelegate:self didEndSelector:@selector(abandonmentAlertDidEnd:returnCode:contextInfo:)
contextInfo:nil];
NSInteger returnCode = [alert runModal];
[self abandonmentAlertDidEnd:alert returnCode:returnCode contextInfo:nil];
(Of course, you will have implemented the abandonmentAlertDidEnd:returnCode:contextInfo: code as a class method.)
Or, if you want the alert to run as a centered panel, call runModal by itself.
Suppose you want to run a panel modal, followed by an alert if the user submits an invalid entry. You’d have to stopModal before you show the alert — after which, for some reason, another call to runModalForWindow fails to work properly. For this scenario, you need a modal session:
1) Add an NSModalSession property to your controller class, because the modalSession must be accessible across multiple methods.
2) Once you have displayed the panel, call beginModalSessionForWindow to instantiate the modalSession:
self.modalSession = [[NSApplication sharedApplication] beginModalSessionForWindow:self.panelForInput];
3) Follow this up with a while-loop that calls runModalSession, breaking when its return does not equal NSRunContinuesResponse:
while ([[NSApplication sharedApplication] runModalSession:self.modalSession] == NSRunContinuesResponse)
continue;
The loop will break and the app will free up when the user clicks on one of the panel’s buttons. (Typing in the panel’s textfield will leave the modal session intact.)
4) In your button handling, if the user’s entry is invalid, you call an alert with runModal.
5) Immediately below the alert call, in the code which will execute once the alert is dismissed, you put the same while-loop used above. The panel’s modal session resumes.
6) In your handling to close the panel, either upon valid entry or cancel, you call endModalSession, which, oddly, isn’t enough; you must also call stopModal, even though you never called runModalForWindow.
[[NSApplication sharedApplication] endModalSession:self.modalSession];
[[NSApplication sharedApplication] stopModal];
[self.panelForInput close];
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题就是答案。我只是发布这个来结束它。抱歉扭曲了 stackoverflow 格式。
The question is the answer. I'm just posting this to close it out. Sorry for twisting the stackoverflow format.