LoginSignup
3
4

More than 3 years have passed since last update.

NSWindowControllerを使って、シートとモーダルウィンドウを作成する

Last updated at Posted at 2019-06-03

概要

  • エラーを表示する汎用的なウィンドウを作成したいということで、使い回せるようなNSWindowControllerを作成する
  • 表示の仕方はシート表示とモーダルウィンドウ表示

  • モーダルウィンドウとは

モーダルウィンドウとはウィンドウ内で指定された操作を完了、またはキャンセルするまで他のウィンドウを開くことができないウィンドウのことです。

UI

  • メイン画面
    • <Result>の部分に下記のウィンドウからの返り値を表示する

-w425

  • シート表示

-w428

  • モーダルウィンドウを表示

-w622

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を呼び出してWindowControllerWindowをモーダル表示する。
  • これの返り値を変数で受け取り、その後任意の処理を行う。
  • escでウィンドウを閉じた場合はNSModalResponseCancelが返される

SheetWindowController

-w997

  • コード全体は以下の通り。
#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
  • クラスのinitxibをロードする場合、上記の通り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のリリースはしていない。
[NSApp stopModalWithCode:NSModalResponseOK];
[[sender window] orderOut:self];

参考

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4