dre*_*lax 19 macos cocoa alerts document-based
当我显示这样的NSAlert时,我立刻得到了回复:
int response;
NSAlert *alert = [NSAlert alertWithMessageText:... ...];
response = [alert runModal];
Run Code Online (Sandbox Code Playgroud)
问题是这是应用程序模式,我的应用程序是基于文档的.我使用工作表在当前文档的窗口中显示警报,如下所示:
int response;
NSAlert *alert = [NSAlert alertWithMessageText:... ...];
[alert beginSheetModalForWindow:aWindow
modalDelegate:self
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
contextInfo:&response];
//elsewhere
- (void) alertDidEnd:(NSAlert *) alert returnCode:(int) returnCode contextInfo:(int *) contextInfo
{
*contextInfo = returnCode;
}
Run Code Online (Sandbox Code Playgroud)
唯一的问题是beginSheetModalForWindow:直接返回,所以我无法可靠地询问用户问题并等待回复.如果我可以将任务分成两个区域,那么这不会是一件大事,但我不能.
我有一个循环来处理大约40个不同的对象(在树中).如果一个对象出现故障,我希望警报显示并询问用户是继续还是中止(继续在当前分支处理),但由于我的应用程序是基于文档的,因此Apple人机界面指南要求在警报为时使用工作表特定于文件.
如何显示警报表并等待响应?
Phi*_*ipp 14
我们创建了一个类别NSAlert来同步运行警报,就像应用程序模式对话框一样:
NSInteger result;
// Run the alert as a sheet on the main window
result = [alert runModalSheet];
// Run the alert as a sheet on some other window
result = [alert runModalSheetForWindow:window];
Run Code Online (Sandbox Code Playgroud)
代码可以通过GitHub获得,并且下面发布了当前版本的完整性.
头文件NSAlert+SynchronousSheet.h:
#import <Cocoa/Cocoa.h>
@interface NSAlert (SynchronousSheet)
-(NSInteger) runModalSheetForWindow:(NSWindow *)aWindow;
-(NSInteger) runModalSheet;
@end
Run Code Online (Sandbox Code Playgroud)
实施文件NSAlert+SynchronousSheet.m:
#import "NSAlert+SynchronousSheet.h"
// Private methods -- use prefixes to avoid collisions with Apple's methods
@interface NSAlert ()
-(IBAction) BE_stopSynchronousSheet:(id)sender; // hide sheet & stop modal
-(void) BE_beginSheetModalForWindow:(NSWindow *)aWindow;
@end
@implementation NSAlert (SynchronousSheet)
-(NSInteger) runModalSheetForWindow:(NSWindow *)aWindow {
// Set ourselves as the target for button clicks
for (NSButton *button in [self buttons]) {
[button setTarget:self];
[button setAction:@selector(BE_stopSynchronousSheet:)];
}
// Bring up the sheet and wait until stopSynchronousSheet is triggered by a button click
[self performSelectorOnMainThread:@selector(BE_beginSheetModalForWindow:) withObject:aWindow waitUntilDone:YES];
NSInteger modalCode = [NSApp runModalForWindow:[self window]];
// This is called only after stopSynchronousSheet is called (that is,
// one of the buttons is clicked)
[NSApp performSelectorOnMainThread:@selector(endSheet:) withObject:[self window] waitUntilDone:YES];
// Remove the sheet from the screen
[[self window] performSelectorOnMainThread:@selector(orderOut:) withObject:self waitUntilDone:YES];
return modalCode;
}
-(NSInteger) runModalSheet {
return [self runModalSheetForWindow:[NSApp mainWindow]];
}
#pragma mark Private methods
-(IBAction) BE_stopSynchronousSheet:(id)sender {
// See which of the buttons was clicked
NSUInteger clickedButtonIndex = [[self buttons] indexOfObject:sender];
// Be consistent with Apple's documentation (see NSAlert's addButtonWithTitle) so that
// the fourth button is numbered NSAlertThirdButtonReturn + 1, and so on
NSInteger modalCode = 0;
if (clickedButtonIndex == NSAlertFirstButtonReturn)
modalCode = NSAlertFirstButtonReturn;
else if (clickedButtonIndex == NSAlertSecondButtonReturn)
modalCode = NSAlertSecondButtonReturn;
else if (clickedButtonIndex == NSAlertThirdButtonReturn)
modalCode = NSAlertThirdButtonReturn;
else
modalCode = NSAlertThirdButtonReturn + (clickedButtonIndex - 2);
[NSApp stopModalWithCode:modalCode];
}
-(void) BE_beginSheetModalForWindow:(NSWindow *)aWindow {
[self beginSheetModalForWindow:aWindow modalDelegate:nil didEndSelector:nil contextInfo:nil];
}
@end
Run Code Online (Sandbox Code Playgroud)
解决方案是打电话
[NSApp runModalForWindow:alert];
Run Code Online (Sandbox Code Playgroud)
在beginSheetModalForWindow之后.此外,您需要实现捕获"对话框已关闭"操作的委托,并调用[NSApp stopModal]作为响应.
这里是解决这一问题的NSAlert类别(如通过与菲利普·弗雷德里克提出,由洛朗P改善:我用一个代码块,而不是委托的解决方案建议,因此它再次简化).
@implementation NSAlert (Cat)
-(NSInteger) runModalSheetForWindow:(NSWindow *)aWindow
{
[self beginSheetModalForWindow:aWindow completionHandler:^(NSModalResponse returnCode)
{ [NSApp stopModalWithCode:returnCode]; } ];
NSInteger modalCode = [NSApp runModalForWindow:[self window]];
return modalCode;
}
-(NSInteger) runModalSheet {
return [self runModalSheetForWindow:[NSApp mainWindow]];
}
@end
Run Code Online (Sandbox Code Playgroud)
万一有人来找这个(我做了),我解决了以下问题:
@interface AlertSync: NSObject {
NSInteger returnCode;
}
- (id) initWithAlert: (NSAlert*) alert asSheetForWindow: (NSWindow*) window;
- (NSInteger) run;
@end
@implementation AlertSync
- (id) initWithAlert: (NSAlert*) alert asSheetForWindow: (NSWindow*) window {
self = [super init];
[alert beginSheetModalForWindow: window
modalDelegate: self didEndSelector: @selector(alertDidEnd:returnCode:) contextInfo: NULL];
return self;
}
- (NSInteger) run {
[[NSApplication sharedApplication] run];
return returnCode;
}
- (void) alertDidEnd: (NSAlert*) alert returnCode: (NSInteger) aReturnCode {
returnCode = aReturnCode;
[[NSApplication sharedApplication] stopModal];
}
@end
Run Code Online (Sandbox Code Playgroud)
然后同步运行NSAlert就像:
AlertSync* sync = [[AlertSync alloc] initWithAlert: alert asSheetForWindow: window];
int returnCode = [sync run];
[sync release];
Run Code Online (Sandbox Code Playgroud)
请注意,如所讨论的那样存在重新引发问题的可能性,因此如果这样做,请小心.
不幸的是,您在这里无能为力。您基本上必须做出决定:重新架构您的应用程序,以便它可以以异步方式处理对象,或者使用未经批准、已弃用的架构来呈现应用程序模式警报。
如果不知道有关您的实际设计以及如何处理这些对象的任何信息,则很难提供任何进一步的信息。不过,我的脑海中浮现出一些想法可能是:
然而,这对于您的需要来说可能确实过于复杂。在这种情况下,我的建议是仅使用已弃用的用法,但这实际上取决于您的用户需求。
| 归档时间: |
|
| 查看次数: |
15201 次 |
| 最近记录: |