6

我不确定我是否以正确的方式做事,或者我是否已将其全部破解。

我创建了一个非常简单的测试应用程序(不是基于文档的),用于学习如何在 Cocoa 应用程序中使用应用程序模式对话框。

使用应用程序项目“TestModalDialog”,我有一个简单的 MainMenu.xib,带有默认视图和一个按钮,“显示对话框”,我添加了。我创建了第二个名为 TheDialog.xib 的 XIB,它具有“取消”和“确定”按钮。该 xib 有一个从 NSWindowController 派生的名为“TheDialogController”的类作为它的所有者;窗口出口和代表连接到控制器。

在主视图上选择“显示对话框”将启动对话框。选择“取消”或“确定”将关闭对话框。这是非常简单的代码:

//  TestModalDialogAppDelegate.h  
//  TestModalDialog  

#import <Cocoa/Cocoa.h>  

@class TheDialogController;  

@interface TestModalDialogAppDelegate : NSObject <NSApplicationDelegate>  
{  
  NSWindow *window;  
  TheDialogController* theDialogController;  
}  

@property (assign) IBOutlet NSWindow *window;  
- (IBAction)showDialog:(id)sender;  

@end  

//  TestModalDialogAppDelegate.m  
//  TestModalDialog  

#import "TestModalDialogAppDelegate.h"  
#import "TheDialogController.h"  

@implementation TestModalDialogAppDelegate  

@synthesize window;  

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification  
{  
  theDialogController= [[TheDialogController alloc] init];  
}  

- (void)dealloc  
{
  if(nil != theDialogController)   
    [theDialogController release];  

  [super dealloc];  
}  

- (IBAction)showDialog:(id)sender  
{  
  if(nil == theDialogController)  
  {  
    NSAlert* alert= [NSAlert alertWithMessageText:@"Dialog Error" defaultButton:nil alternateButton:nil otherButton:nil informativeTextWithFormat:@"The dialog controller was not allocated."];  
    [alert runModal];  
    return;  
  }

  NSInteger result= [NSApp runModalForWindow:[theDialogController window]]; 
  // Do something with result.... 
}  
@end  

//  TheDialogController.h  
//  TestModalDialog  

#import <Cocoa/Cocoa.h>  

@interface TheDialogController : NSWindowController  
{  
  // BOOL userClickedCloseOrOk; // Removed based on answer.  
  // Should declare a common define - just being lazy.  
  NSInteger userClickedOk;  // Added based on answer.  
  UInt16 timesShown;   
}  

- (IBAction)showWindow:(id)sender;  
- (IBAction)closeDialog:(id)sender;  
- (IBAction)okDialog:(id)sender;  
//- (BOOL)windowShouldClose:(id)sender;   // Removed based on answer.  
- (void)windowWillClose:(NSNotification*)notification;  // Added based on answer.   
- (void)windowDidBecomeKey:(NSNotification*)notification;  // To set title when modal.  
@end  

//  TheDialogController.m  
//  TestModalDialog  

#import "TheDialogController.h"  

@implementation TheDialogController  

- (id)init  
{  
  self = [super initWithWindowNibName:@"TheDialog"];  

  userClickedOk= 0;  // Added based on answer.  
  // userClickedCloseOrOk= FALSE;  // Removed based on answer.  

  return self;  
}  

-(void)dealloc  
{  
  // Do member cleanup if needed.
  [super dealloc];  
}  

- (void)windowDidLoad  
{  
  [super windowDidLoad];  

  // Initialize as needed....  
  [[self window] center];  // Center the window.  
}  

// Does not show with runModalForWindow.  
- (IBAction)showWindow:(id)sender  
{  
  // Just playing with the window title....  
  ++timesShown;  
  NSString* newTitle= [NSString stringWithFormat:@"Shown %d Times", timesShown];  
  [[self window] setTitle:newTitle];  
  return [super showWindow:sender];  
}  

// This method no longer used for this solution based on the answer.  
//- (BOOL)windowShouldClose:(id)sender  
//{  
//  if(!userClickedCloseOrOk)  // The user did not click one of our buttons.  
//    [NSApp abortModal];  
//  else  
//    userClickedCloseOrOk= FALSE;  // Clear for next time.  
//  
//  return TRUE;  
//}  

// Added based on answer.  
- (void)windowWillClose:(NSNotification*)notification  
{  
  [NSApp stopModalWithCode:userClickedOk];  
  userClickedOk= 0;  // Reset for next time.  
}  

// Note - the title will update every time the window becomes key. To do the  
// update only once per modal session, a flag can be added. There might be a better  
// notification to catch.  
- (void)windowDidBecomeKey:(NSNotification*)notification  
{  
  ++timesShown;  
  NSString* newTitle= [NSString stringWithFormat:@"Shown %d Times", timesShown];  
  [[self window] setTitle:newTitle];  
}  

- (IBAction)closeDialog:(id)sender  
{  
  //userClickedCloseOrOk= TRUE;  // Removed based on answer.  
  //[NSApp abortModal];  // Removed based on answer.  
  //[[self window] performClose:self];  // Removed based on answer.  
  [[self window] close];  // Know we want to close - based on answer.  
}  

- (IBAction)okDialog:(id)sender  
{  
  userClickedOk= 1;  // Added based on answer.  
  //userClickedCloseOrOk= TRUE;  // Removed based on answer.  
  //[NSApp stopModal];  // Removed based on answer.  
  //[[self window] performClose:self];  // Removed based on answer.  
  [[self window] close];  // Know we want to close - based on answer.  
}    

@end  

我遇到了模态问题 - 在我输入 userClickedCloseOrOk 和测试之前,如果用户点击关闭按钮(左上角红点),对话框将关闭,但模态会话仍在运行。

我意识到我可以从对话框中离开关闭按钮开始,但是有了它,我已经展示了捕捉这种情况的好方法,还是有更好的方法?或者,我一开始是不是做错了什么,这给我带来了这个问题?

任何意见,将不胜感激。

注意- 原始示例中的代码已注释掉并替换为基于答案的代码。还添加了一个新的通知处理程序。

4

2 回答 2

2

okDialog:andcloseDialog:方法中调用close而不是performClose:避免窗口调用windowShouldClose:委托方法。这样你就不需要了userClickedCloseOrOk

另外我认为你想打电话stopModalWithCode:而不是stopModal因为在应用程序委托中你似乎对结果感兴趣。你可以调用stopModalorstopModalWithCode:而不是,abortModal因为当你调用它时你总是在 runloop 中(abort 是当你在模态 runloop 之外时,比如在另一个线程或计时器的 runloop 中)。

当您只应回答“此窗口是否应关闭”的问题时,windowShouldClose:您正在执行操作 ( )。abortModal如果需要,windowWillClose:委托方法是您应该执行操作的地方。

当只有一个窗口时,表格很有用,它告诉用户在完成表格中的任何内容之前,他们不能对它进行任何操作。当您有多个窗口时,应用程序模式窗口很有用,用户在完成模式窗口中的任何内容之前无法与之交互,或者存在涉及整个应用程序但与一个窗口的内容无关的错误。在他们的 HIG 中,Apple 建议尽可能避免使用应用程序模式窗口。

于 2012-02-09T23:06:10.863 回答
1

我实际上一直在努力解决同样的问题并找到了这个链接:

关闭窗口时停止模式(可可)

于 2012-02-09T21:37:26.710 回答