AppKitでのボタンの作り方(ターゲットとアクションについて) | macOSアプリの作り方

アプリ内でボタンは頻繁に使用する要素の一つです。今回はCocoa版Hello Worldに終了ボタンを追加して、ボタンからも終了できるようにします。

この記事では前回の記事で作成したCocoa版Hello Worldの続きから行います。前回の記事に沿って作成している場合はそれを使用してください。作成されていない場合は、前回の記事の末尾からサンプルコードをダウンロードしてご利用ください。

関連記事

Cocoa版Hello World作成の続きです。今回はウインドウを閉じたときにアプリを終了させる処理を追加します。 この記事では前回の記事で作成したCocoa版Hello Worldの続きから行います。前回の記事に沿って作成して[…]

スポンサーリンク

アクションとターゲット

AppKitでボタンを作るときには「アクション」と「ターゲット」を使用します。AppKitではボタン自体はビューの一つです。ボタンがクリックされると、ボタンに設定されたアクションが実行されます。アクションを実行するのはターゲットです。

ボタンクリック時の動作
ボタンクリック時の動作

ターゲットの実体について

アクションを実行するターゲットの実体は、NSResponderクラスを継承したクラスのサブクラスのインスタンスです。アプリ独自の処理は、アプリ側でクラスを実装します。AppKitにもNSResponderクラスの継承クラスは沢山あります。例えば、ウインドウを実装したNSWindowクラスやNSWindowControllerクラスもNSResponderクラスを継承しているので、ターゲットになります。

アクションの実体について

アクションの実体はセレクタです。セレクタはObjective-Cのメソッドの内部表現です。アプリ開発をする上では、セレクタを設定するということは、メソッドを設定することだと考えて頂ければ大丈夫です。

例えば、Objective-Cの次のようなメソッドがあるとします。

@implementation TestObj

- (void)doSomething:(id)sender
{
}

@end

このdoSomethingメソッドに対するセレクタは次のように書きます。

SEL theSelector = @selector(doSomething:);

Objective-Cと書きましたが、Swiftではどうなるのでしょうか?Swiftでは、このObjective-Cのクラスのメソッドに対するセレクタは次のように書きます。

let theSelector = #selector(TestObj.doSomething(_:))

Swiftで書かれたクラスのメソッドに対しても同様にセレクタを取得できます。但し、Swift側のコードで次のようにします。

  • NSObjectクラスを継承する
  • @objcアノテーションを付けてメソッド定義する

例えば、次のようなコードです。

class TestSwiftObj: NSObject {

    @objc func doSomething(_ sender: AnyObject?) {

    }
    
}
スポンサーリンク

終了ボタンを追加する

終了ボタンを作っていきます。AppKitではボタンにターゲットとアクションを設定します。ターゲットですが、Cocoa版HelloWorldはとても小さなアプリなので、ViewControllerをターゲットにします。

アクションの実装

ViewControllerをターゲットにするので、アクションとなるメソッドもViewControllerに追加します。次のようにViewController.swiftにコードを追加します。

import Cocoa

class ViewController: NSViewController {
    // 省略
    
    @IBAction func terminateApp(_ sender: Any?) {
        NSApplication.shared.terminate(sender)
    }
}

アクションとして定義する

アクションにするメソッドは次のような形式のコードで実装します。

@IBAction func methodName(_ sender: Any?) {
}

@objcではなく@IBActionを使用します。@IBActionはXcodeからアクションとしてメソッドを認識させるために必要なアトリビュートです。@IBActionも、メソッドをObjective-Cのセレクタと互換性のある形でエクスポートするので、@objcが不要になります。(@objcの処理を内包します)

終了ボタンをビューに追加する

次のように操作して、終了ボタンをビューに追加します。

(1) Main.storyboardを開きます。

(2) View Controller Sceneを選択します。

(3) ツールバーの「+」ボタン(「Library」ボタン)をクリックします。

「Library」ボタンをクリックする
「Library」ボタンをクリックする

(4) ライブラリウインドウから「Push Button」をビューの「Hello World」の少し下にドラッグ&ドロップします。ちょうど良いくらいの場所でガイドが表示されます。

ボタンをビューにドラッグ&ドロップで追加する
ボタンをビューにドラッグ&ドロップで追加する

(5) 配置したボタンをダブルクリックします。タイトルを編集可能になるので、「Quit」と入力して「Return」キーを押します。

ボタンのタイトルを設定する
ボタンのタイトルを設定する

オートレイアウトの設定

次にオートレイアウトを設定します。「Hello World」というラベルは中央に表示されるようになっています。「Quit」ボタンはその下に表示されるように設定します。次の様に操作します。

(1) 「Quit」ボタンが選択されていなかったら選択します。

(2) 「Add New Constraints」ボタンをクリックします。

「Add New Constraints」をクリックする
「Add New Constraints」をクリックする

(3) 「Width」と「Height」をチェックし、「Add 2 Constraints」をクリックします。これにより、幅と高さが固定されます。

「Width」と「Height」をチェック後、Constraintsを追加する
「Width」と「Height」をチェック後、Constraintsを追加する

(4) もう一度「Add New Constraints」をクリックし、上側の余白欄のポップアップアイコン(下向きの三角)をクリックし、「Hello World (current distance = 8)」を選択します。これにより、「Hello World」というラベルの下に8pxの位置にY座標が設定されます。

上側の余白を設定する
上側の余白を設定する

(5) 「Align」をクリックします。

「Align」をクリックする
「Align」をクリックする

(6) 「Horizontally in Container」をチェックし、「Add 1 Constraint」をクリックします。

水平方向に中央配置する
水平方向に中央配置する

ボタンにアクションを設定する

最後に「Quit」ボタンのアクションにterminateAppメソッドを設定します。次のように操作します。

(1) 「Quit」ボタンを右クリックドラッグ、または、「Control」キーを押しながらドラッグします。青い線が現れるので、「View Controller Scene」の「View Controller」にドロップします。

ボタンからViewControllerにコネクションを張る
ボタンからViewControllerにコネクションを張る

(2) terminateApp:を選択します。これで、ボタンのアクションにterminateAppメソッドが設定されます。

アクションを選択する
アクションを選択する

ガイド線について

ボタンを追加するときに表示された水平方向のガイド線ですが、Human Interface Guidelinesに従って空けるべき余白のところで表示されます。また、垂直方向のガイド線は、ちょうどビューの中央を示すものとして表示されています。

ガイド線に従って配置すると、ある程度、良い感じにレイアウトすることができます。

Human Interface Guidelinesはデベロッパーサイトで公開されています。

Fat View ControllerとFat Window Controller

ここではViewControllerにビジネスロジックである終了機能を実装しました。その際、「小規模である」ということを強調しました。AppKitは元々MVCで設計されています。

ビューコントローラやウインドウコントローラはコントローラです。コントローラは入力をモデルに伝えることです。終了するという処理はロジックです。ビジネスロジックはモデル側で行うべきであり、コントローラでは行うべきでありません。

しかし、Cocoa版Hello Worldはとても小規模です。このくらいの小規模なアプリで厳密に分割していくのはかえってオーバースペックと考えられました。そのため、ここではViewControllerに直接実装しました。

なお、何でもかんでもコントローラに実装してしまい、大きく膨れ上がってしまったビューコントローラやウインドウコントローラを「Fat View Controller」や「Fat Window Controller」などと呼びます。

コードの見通しの良さや保守性などの観点からそのような状態になるのは避けた方が良いでしょう。現実には何度も、そのようなコードを書いてしまったことがありますが。これらのコードもいつかは改善したいですね。

動作テスト

アプリをビルドして実行してみましょう。表示されたウインドウをリサイズして、「Quit」ボタンの位置がおかしくならないことを確認します。

次に「Quit」ボタンをクリックして、アプリが終了するか確認してみましょう。

HelloWorldの動作テスト
HelloWorldの動作テスト

サンプルコードのダウンロード

今回の記事で作成したサンプルコードはこちらからダウンロードできます。

005_CocoaHelloWorld.zip

スポンサーリンク
最新情報をチェックしよう!