概要
-
エラーを表示する汎用的なウィンドウを作成したいということで、使い回せるような
NSWindowController
を作成する -
表示の仕方はシート表示とモーダルウィンドウ表示
モーダルウィンドウとはウィンドウ内で指定された操作を完了、またはキャンセルするまで他のウィンドウを開くことができないウィンドウのことです。
UI
- メイン画面
-
<Result>
の部分に下記のウィンドウからの返り値を表示する
-
- シート表示
- モーダルウィンドウを表示
GitHub
実装
AppDelegate
- 最小限の処理のみ
AppDelagete
に書いて、UIの処理は別に書く。
# import "AppDelegate.h"
# import "MainWindowController.h"
@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@property (strong) MainWindowController *mainWindowController;
@end
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
_mainWindowController = [[MainWindowController alloc] initWithWindowNibName: MainWindowController.className];
[_mainWindowController showWindow:self];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
@end
- 今回は
MainWindowController
を呼び出すだけ。具体的な処理はそこで行う。
MainWindowController
- コード全体
# import "MainWindowController.h"
# import "SheetWindowController.h"
# import "ModalWindowController.h"
@interface MainWindowController ()
@property (weak) IBOutlet NSTextField *resultLabel;
@property SheetWindowController *sheetWindowController;
@property ModalWindowController *modalWindowController;
@end
@implementation MainWindowController
- (void)windowDidLoad {
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
/**
@brief シートを開く
*/
- (IBAction)openSheet:(id)sender {
SheetWindowController *sheetWindowController = [[SheetWindowController alloc] init];
_sheetWindowController = sheetWindowController;
[self.window beginSheet:_sheetWindowController.window completionHandler:^(NSModalResponse returnCode) {
NSMutableString *resultMessage = [NSMutableString stringWithString: @"SheetResponse: "];
switch (returnCode) {
case NSModalResponseOK:
[resultMessage appendString:@"OK"];
break;
case NSModalResponseCancel:
[resultMessage appendString:@"Cancel"];
break;
default:
break;
}
self->_resultLabel.stringValue = resultMessage;
}];
}
/**
@brief モーダルウィンドウを開く
*/
- (IBAction)openModalWindow:(id)sender {
ModalWindowController *modalWindowController = [[ModalWindowController alloc] init];
_modalWindowController = modalWindowController;
NSModalResponse result = [NSApp runModalForWindow:_modalWindowController.window];
NSMutableString *resultMessage = [NSMutableString stringWithString: @"ModalWindowResponse: "];
if (result == NSModalResponseOK) {
[resultMessage appendString:@"OK"];
} else if (result == NSModalResponseCancel) {
[resultMessage appendString:@"Cancel"];
}
_resultLabel.stringValue = resultMessage;
}
@end
- シートを開いている
(IBAction)openSheet:(id)sender
を見る。
SheetWindowController *sheetWindowController = [[SheetWindowController alloc] init];
_sheetWindowController = sheetWindowController;
-
シートの
WindowController
クラスを作成しプロパティへ保存しているだけ。 -
シートの呼び出しは以下の通り。
[self.window beginSheet:_sheetWindowController.window completionHandler:^(NSModalResponse returnCode) {
NSMutableString *resultMessage = [NSMutableString stringWithString: @"SheetResponse: "];
switch (returnCode) {
case NSModalResponseOK:
[resultMessage appendString:@"OK"];
break;
case NSModalResponseCancel:
[resultMessage appendString:@"Cancel"];
break;
default:
break;
}
self->_resultLabel.stringValue = resultMessage;
}];
-
beginSheet
でシートを呼び出す。 -
completionHandler
のクロージャに、シートを閉じた後の処理を書く。 -
引数はシートで押されたボタンの情報で、OKやCancelをシート側で返すようにしておく
-
次はモーダルウィンドウを呼び出している
(IBAction)openModalWindow:(id)sender
を見る
ModalWindowController *modalWindowController = [[ModalWindowController alloc] init];
_modalWindowController = modalWindowController;
-
ModalWindowController
のオブジェクトを作成しプロパティへ保存
NSModalResponse result = [NSApp runModalForWindow:_modalWindowController.window];
-
runModalForWindow
を呼び出してWindowController
のWindow
をモーダル表示する。 - これの返り値を変数で受け取り、その後任意の処理を行う。
-
esc
でウィンドウを閉じた場合はNSModalResponseCancel
が返される
SheetWindowController
- Xibの画面で、
Visible At Launch
をオフにすることに注意
- コード全体は以下の通り。
# import "SheetWindowController.h"
@interface SheetWindowController ()
@end
@implementation SheetWindowController
- (id)init {
if (self = [super initWithWindowNibName:[self className] owner:self]) {
}
return self;
}
- (void)windowDidLoad {
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
- (IBAction)okButtonPush:(id)sender {
[self.window.sheetParent endSheet:self.window returnCode:NSModalResponseOK];
}
- (IBAction)cancelButtonPush:(id)sender {
[self.window.sheetParent endSheet:self.window returnCode:NSModalResponseCancel];
}
@end
- クラスの
init
でxib
をロードする場合、上記の通りoverrideすることを忘れないように。 - シートのParentに対して
endSheet
を呼び出してやる。このときにボタンの情報をreturnCode
で返す。
ModalWindowController
# import "ModalWindowController.h"
@interface ModalWindowController ()
@end
@implementation ModalWindowController
- (id)init {
if (self = [super initWithWindowNibName:[self className] owner:self]) {
}
return self;
}
- (void)windowDidLoad {
[super windowDidLoad];
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
}
- (IBAction)okButtonPush:(id)sender {
[NSApp stopModalWithCode:NSModalResponseOK];
[[sender window] orderOut:self];
}
- (IBAction)cancelButtonPush:(id)sender {
[NSApp stopModalWithCode:NSModalResponseCancel];
[[sender window] orderOut:self];
}
@end
- 呼び出し元の
runModalForWindow
に対して、下記を呼んでいる。 -
stopModalWithCode
はモーダルを解除するだけ(呼び出し元のウィンドウ操作を可能にする)で、ウィンドウのクローズは別に行う必要がある。 - ちなみに
orderOut
は非表示にするだけで、Windowのリリースはしていない。- リリースをするのは
close
である - Cocoa API解説(macOS/iOS)
- リリースをするのは
[NSApp stopModalWithCode:NSModalResponseOK];
[[sender window] orderOut:self];
参考
-
シート
-
モーダルウィンドウ
- ヒレガス本のP407辺り
- Cocoa API解説(macOS/iOS)
- How Modal Windows Work