阻止直到 NSAlert(显示为模式表)被解除

Posted

技术标签:

【中文标题】阻止直到 NSAlert(显示为模式表)被解除【英文标题】:Block until NSAlert (shown as a modal sheet) is dismissed 【发布时间】:2011-11-10 18:42:43 【问题描述】:

我目前正在通过实现我认为 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。

所以我的问题是:

如何阻止我的方法返回,直到“工作表”被解除?

或者我是不是走错了路?

【问题讨论】:

【参考方案1】:

您必须在显示表单后为您的表单启动一个模态会话,并在关闭表单后停止会话。

检查这个:https://github.com/incbee/NSAlert-SynchronousSheet,我认为这会有所帮助。

【讨论】:

谢谢!这正是我想要的。【参考方案2】:

你可以在beginSheetModalForWindow:...之后使用这个:

[[NSRunLoop mainRunLoop] runMode:NSModalPanelRunLoopMode beforeDate:[NSDate distantFuture]]

但是,在关闭工作表之前,它会使您应用中的任何其他窗口都无法使用。最好不要挡住那些窗口。

【讨论】:

【参考方案3】:

我创建警报的方法立即返回

我相信这是因为,正如@Josh 所说,工作表仅相对于它所附加的窗口运行模式;它不会冻结整个应用程序。因此,只要beginSheetModal... 执行,您的方法的其余部分就会继续运行,以return returnCode 结束(这里返回-1),而无需等待用户响应警报。

返回代码是 用户 最终按下警报面板上的哪个按钮(NSAlertFirstButtonReturn、NSAlertSecondButtonReturn 等)的替身 - 它们列在 NSAlert 类的末尾参考)。您在 alertDidEnd 方法中使用它来操作用户按下的任何按钮以关闭警报。这就是alertDidEnd 选择器包含returnCode 的原因。

另一方面,当您在else 块中使用runModal 方法时,您需要显式调用alertDidEnd 并将runModal 方法结束时返回的数字提供给它——也就是当用户关闭警报。

这是您的代码的修订版本:

int returnCode = -1;
if (displayAsSheet) 
    [alert beginSheetModalForWindow:nativeWindow modalDelegate:delegate didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:) contextInfo:nil];
    // The selector alertDidEnd has the returnCode int. The alert will then set that code to whatever the user chooses, and will send the altered int on to alertDidEnd.
 
else 
    // Here, everything stops once runModal is called, until the user dismisses the alert, at which time the runModal method returns the int representing the button the user pushed, and you assign the return to your variable "returnCode."
    returnCode = [alert runModal];
    [self alertDidEnd:alert returnCode:returnCode contextInfo:nil];

// Omit the line returning the returnCode.

然后alertDidEnd 方法执行如下操作:

- (void)alertDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo  
switch (returnCode) 
    case NSAlertFirstButtonReturn:
        // Do whatever should happen when first button is pushed.
        break;
    case NSAlertSecondButtonReturn: 
        // Do whatever should happen when second button is pushed.
        break;
    default:
        break;
    
    // Unfreeze things.
    [[NSApplication sharedApplication] stopModal];

顺便说一句,一种运行工作表并冻结整个应用程序的方法,而不仅仅是附加工作表的窗口,如果你想要的话:modal tips

【讨论】:

【参考方案4】:

你的想法有点错误。如果您的方法能够等待工作表结束,则应用程序的事件循环将被阻止,用户将无法与 UI 交互。当您将runModal 用于警报时,会创建一个 new 运行循环来处理警报——这就是为什么无法对应用程序执行任何其他操作的原因。 sheet 选项的重点是允许用户在显示警报时做其他事情 - 即,它明确接管事件处理。

您可以通过附加子窗口来查看伪造的表格。

【讨论】:

【参考方案5】:

您可以尝试设置一个布尔值来冻结您想要在应用程序上冻结的任何内容(设置冻结 = YES)直到工作表被移除(设置冻结 = 否)。 在一般情况下,您不需要阻止方法:您只希望在用户做出选择之前不要发生某些事情。

例如,我有一个使用陀螺仪的应用。它有一些行为,而没有其他行为。 所以我有一个布尔值,用于任何使用陀螺仪数据将行为路由到好的方法的方法。我的 useGyro Boolean 在以下情况下为 NO:用户正在选择要启用或不启用哪种硬件功能,以及设备上没有陀螺仪时。

与我拥有的 mapView 相同:当用户被系统询问是否想要定位时,有时我会冻结使用用户位置的任何行为。当他做出选择时,我会更改该布尔值。

【讨论】:

以上是关于阻止直到 NSAlert(显示为模式表)被解除的主要内容,如果未能解决你的问题,请参考以下文章

如何解除浏览器的阻止功能

网页活动内容被阻止,点击允许依然出现

如何解决Access操作或事件已被禁用模式阻止

怎样解除被防火墙阻止运行的程序

由于许多连接错误,主机“主机名”被阻止;使用 'mysqladmin flush-hosts' 解除阻塞

expressJWT 阻止公用文件夹,如何解除阻止?