阻止直到 NSAlert(显示为模式表)被关闭
我目前正在通过实现一个我认为在 Titanium Appcelerator Desktop SDK 中缺少的功能来学习(通过实践)objective-c:一种使用自定义按钮文本进行模式对话框并可选择将其显示为“工作表”的方法。
一切都很花哨并且工作正常,但是,当将 NSAlert 显示为“表”时,我创建警报的方法会立即返回,这就是我想要防止的。
创建警报的方法返回一个 int (来自 NSAlert 的返回代码)。
里面的代码基本上可以归结为:
int returnCode = -1;
if (displayAsSheet) {
[alert beginSheetModalForWindow:nativeWindow modalDelegate:delegate didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
} else {
returnCode = [alert runModal];
}
return returnCode;
modalDelegate 是一个实现所需功能的对象:
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo;
现在它只执行 returnCode 的 NSLog。
所以我的问题是:
如何阻止我的方法返回,直到“工作表”被解除为止?
或者我以错误的方式处理这个问题?
I'm currently learning (by doing) objective-c by implementing a feature I felt is missing in the Titanium Appcelerator Desktop SDK: A way to do modal dialog with custom button texts and optionally to display them as a "sheet".
All is dandy and working, however, when displaying the NSAlert as a "sheet" my method that's creating the alert returns immediately and that's what I want to prevent.
The method's creating the alert returns an int (the return code from the NSAlert).
The code inside basically boils down to:
int returnCode = -1;
if (displayAsSheet) {
[alert beginSheetModalForWindow:nativeWindow modalDelegate:delegate didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
} else {
returnCode = [alert runModal];
}
return returnCode;
The modalDelegate is an object that's implementing the needed:
- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo;
and for now it just does a NSLog of the returnCode.
So my question is:
How can I block my method from returning until the "sheet" has been dismissed?
Or am I going about this the wrong way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您必须在显示工作表后为其启动模式会话,并在关闭工作表后停止会话。
检查这个:https://github.com/incbee/NSAlert-SynchronousSheet,我认为它会乐于助人。
You must start a modal session for you sheet after showing it and stop the session after closing sheet.
Check this: https://github.com/incbee/NSAlert-SynchronousSheet, I think it will be helpfull.
您可以在
beginSheetModalForWindow:...
之后使用它:但是,它会使应用程序中的任何其他窗口无法使用,直到工作表被关闭。最好不要挡住那些窗户。
You could use this after
beginSheetModalForWindow:...
:However, it will make any other windows in your app unusable until the sheet is dismissed. It would be better not to block those windows.
我相信这是因为,正如 @Josh 所说,该工作表仅相对于它所附加的窗口以模式方式运行;它不会冻结整个应用程序。因此,一旦
beginSheetModal...
执行,方法的其余部分就会继续运行,并以return returnCode
(此处返回 -1)结束,而无需等待用户响应警报。返回代码代表用户最终按下警报面板上的哪个按钮(NSAlertFirstButtonReturn、NSAlertSecondButtonReturn 等——它们列在 NSAlert 类引用的末尾)。您可以在
alertDidEnd
方法中使用它来对用户按下的任何按钮进行操作以消除警报。这就是alertDidEnd
选择器包含 returnCode 的原因。另一方面,当您在
else
块中使用runModal
方法时,您需要显式调用alertDidEnd
并向其提供以下情况下返回的数字:runModal
方法结束——此时用户关闭警报。这是代码的修订版本:
然后
alertDidEnd
方法执行类似以下操作:顺便说一下,有一种运行工作表并冻结整个应用程序的方法,而不是只是附有工作表的窗口,如果这就是您想要的:模态提示
I believe that's because, as @Josh says, the sheet is running modal only relative to the window to which it is attached; it is not freezing the entire app. Therefore, as soon as
beginSheetModal...
executes, the rest of your method continues to run, concluding withreturn returnCode
(here returning -1), without waiting for the user to respond to the alert.The return code is a stand-in for which button on the alert panel the user ends up pushing (NSAlertFirstButtonReturn, NSAlertSecondButtonReturn, etc. -- they're listed at the end of the NSAlert class ref). You use it in your
alertDidEnd
method to act upon whichever button the user pushed to dismiss the alert. That's why thealertDidEnd
selector includes the returnCode.On the other hand, when you use the
runModal
method in yourelse
block, you need to explicitly callalertDidEnd
and feed it the number returned when therunModal
method ends -- which is when the user dismisses the alert.Here's a revised version of your code:
Then the
alertDidEnd
method does something like this:By the way, there is a way of running a sheet and freezing the entire app, not just the window to which the sheet is attached, if that's what you want: modal tips
你思考这个问题的方式有点错误。如果您的方法能够等待工作表结束,则应用程序的事件循环将被阻止,并且用户将无法与 UI 交互。当您使用
runModal
作为警报时,会创建一个新运行循环来处理警报 - 这就是为什么不能对应用程序执行任何其他操作。工作表选项的要点是允许用户在显示警报时执行其他操作 - 即,它明确不接管事件处理。您可以考虑通过附加子窗口来伪造工作表。
You're thinking about this slightly the wrong way. If your method were able to wait for the sheet to end, the app's event loop would be blocked and there would be no way for the user to interact with the UI. When you use
runModal
for the alert, a new run loop is created to handle the alert -- this is why nothing else can be done to the app. The point of the sheet option is to allow the user to do other things while the alert is displayed -- i.e., it expressly does not take over the event handling.You could look into faking the sheet by attaching a child window.
您可以尝试设置一个布尔值来冻结您想要在应用程序上冻结的任何内容(设置冻结=是)直到工作表被删除(设置冻结=否)。< br>
在一般情况下,您不需要阻止方法:您只是希望在用户做出选择之前某些事情不会发生。
例如,我有一个使用陀螺仪的应用程序。它有一些行为,以及一些其他行为。
因此,我有一个布尔值,可用于任何使用陀螺仪数据将行为路由到好的方法的方法。当以下情况时,我的 useGyro Boolean 为 NO:用户正在选择要启用或不启用哪种硬件功能,以及当陀螺仪在设备上不可用时。
我的地图视图也是如此:当系统询问用户是否想要定位时,我会冻结使用用户位置的任何行为。当他做出选择时,我会更改该布尔值。
You could try to set a boolean that freezes anything you want to freeze on your app (set freeze = YES) until the sheet is removed (set freeze = NO).
In the general case, you don't need to block a method : you just want some things not to happen until the user has made a choice.
For example, I have an app that uses gyroscope. It has some behaviour with, and some other behaviour without.
So I have a boolean that is used in any method that uses the gyro data to route the behaviour to the good one. My useGyro Boolean is NO when : the user is choosing what kind of hardware feature it want to enable or not, and when gyro is not available on the device.
The same thing with a mapView I have : when the user is aked by the system if it wants to be located, there is a moment where I freeze any behaviour using the user location. When he has made his choice, I change that bool value.