まずは、常駐型アプリとは?っていうところを軽く復習。常駐型アプリというのは、常時システムを監視する必要があるなど、他のアプリケーションで何らかの処理が行われている間も裏で動いているようなアプリのことで、macでいうと起動中もドックやコマンド+タブキーで表示されるアプリ切り替えパネル、強制終了パネル等に表示されないものである。アプリが自身を終了するための何らかの手段を提供していない場合は、アクティビティモニタなどを用いてしか終了できない。以前紹介したのは、他のアプリケーションで表示されるテキストを編集する目的で、他のアプリケーションがアクティブな時でも常に最前面にウインドウを表示するものだった。今回作ったのは、起動中はメニューバーの右側のステータスバーに常駐しているタイプのもの。他のアプリケーションがアクティブな時でもステータスバーから操作ができる。では作り方に進む。
@ターゲッドのinfoのキーにApplication is agent (UIElement)を追加し、値をYESにする。
このへんは以前投稿した記事と同じ内容なのだがあちこちに情報が散っているというのもなんなので、再度。プロジェクト・ナビゲータでプロジェクトを選択し(上図@)、ターゲット(上図A)のinfo(上図B)のCustom macOS Application Target Propertiesで、どれでもいいのでkeyの項目にマウスアップすると現れる[+]ボタンをクリックして、Application is agent (UIElement)を追加し、値にはYESを設定する。これだけでもう常駐アプリになっているので、アプリを走らせてもドック等には表示されなくなっている。
Aステータスバーに表示するメニューのインターフェイスを作成する。
文字だけのメニューでもアイコンだけのメニューでも用途に合わせて作れるが、今回のデモはどちらも含むタイプにした。まずは、インターフェイスの作成から。XIBファイルを表示して、オブジェクト・ライブラリからNSMenuを追加、必要なメニュー項目を追加する。
デモでは、[ウインドウ表示]と[アプリケーション終了]の機能を追加した。それぞれにアクションを紐付けする。[アプリケーション終了]はControlキーを押しながら、PlaceholdersのFirst Responderに向かって、メニュー項目からコネクタを引っ張り、表示されたアクションリストから、terminate:を選択するだけ。
[ウインドウ表示]の方は、メニュー項目からAppDelegate.mの@implementationの任意の場所に向かってコネクタを引っ張り、アクションメソッドを追加する。メソッドの内容は下の実装ファイルを参照。
デモでは、[ウインドウ表示]と[アプリケーション終了]の機能を追加した。それぞれにアクションを紐付けする。[アプリケーション終了]はControlキーを押しながら、PlaceholdersのFirst Responderに向かって、メニュー項目からコネクタを引っ張り、表示されたアクションリストから、terminate:を選択するだけ。
[ウインドウ表示]の方は、メニュー項目からAppDelegate.mの@implementationの任意の場所に向かってコネクタを引っ張り、アクションメソッドを追加する。メソッドの内容は下の実装ファイルを参照。
Bステータスメニューの実装。
下準備として、作成したNSMenuをアウトレット接続する。Controlキーを押しつつ、AppDelegate.mの@interfaceに向かってコネクタを引っ張り、weakで接続する(実装ファイル4行目)。
次にステータス・アイテム保持のためのインスタンス変数を宣言する(実装ファイル11行目)。メニューアイコン用の画像も用意する。アイコンサイズの上限は縦が20px(20pxのギリギリまで使うとメニューの端にきて見栄えがよろしくないので上下2px以上は開けた方がよいかと)、横は空いているメニューバーのスペースの大きさに依存する。場所さえ空いていれば、結構な大きさまで可能。300pxまでは試した(まあ実際そこまで大きくすることはないだろうが)。デモでは横22px×縦18pxサイズの画像を用意し、実際の絵柄は中央に16px四方の大きさで描いている。横サイズの余白を大きくしているのは隣のメニューや、メニュー・タイトルの文字との空きを取るためだ。デモの場合、上記サイズで白黒画像をひとつ用意し、"stIconTemplate.png" という名前でAdd Filesメニューでそのままプロジェクトに追加して使用した。ファイル名の末尾に "Template" と入れることにより、highlightModeがYESの時に、ハイライト時の白黒反転を自動で行ってくれる。
では、いよいよ実装に入る。実際のプログラムでは、ステータス・アイテムのセットアップを行うカスタム・メソッドsetUpStMenuを作成し、これをapplicationDidFinishLaunchingで呼び出している。setUpStMenuの中身を順に追っていくと、
まずNSStatusBarのクラスメソッド+ systemStatusBarでステータスバーを取得(20行目)。続いて下記メソッドで、取得したステータスバーに新しいNSStatusItemを作成する。
あとは用途に応じてステータスアイテムのプロパティを指定するだけだ。主に使いそうな項目には次のようなものがある。
次にステータス・アイテム保持のためのインスタンス変数を宣言する(実装ファイル11行目)。メニューアイコン用の画像も用意する。アイコンサイズの上限は縦が20px(20pxのギリギリまで使うとメニューの端にきて見栄えがよろしくないので上下2px以上は開けた方がよいかと)、横は空いているメニューバーのスペースの大きさに依存する。場所さえ空いていれば、結構な大きさまで可能。300pxまでは試した(まあ実際そこまで大きくすることはないだろうが)。デモでは横22px×縦18pxサイズの画像を用意し、実際の絵柄は中央に16px四方の大きさで描いている。横サイズの余白を大きくしているのは隣のメニューや、メニュー・タイトルの文字との空きを取るためだ。デモの場合、上記サイズで白黒画像をひとつ用意し、"stIconTemplate.png" という名前でAdd Filesメニューでそのままプロジェクトに追加して使用した。ファイル名の末尾に "Template" と入れることにより、highlightModeがYESの時に、ハイライト時の白黒反転を自動で行ってくれる。
では、いよいよ実装に入る。実際のプログラムでは、ステータス・アイテムのセットアップを行うカスタム・メソッドsetUpStMenuを作成し、これをapplicationDidFinishLaunchingで呼び出している。setUpStMenuの中身を順に追っていくと、
まずNSStatusBarのクラスメソッド+ systemStatusBarでステータスバーを取得(20行目)。続いて下記メソッドで、取得したステータスバーに新しいNSStatusItemを作成する。
- (NSStatusItem *) statusItemWithLength:(CGFloat)length
lengthとして数値(ピクセル数)か定数を渡し幅を指定して新しいステータスアイテムを作成する。用意されている定数は以下の2つ。・NSVariableStatusItemLength:ステータスバーの高さと同じだけの幅を確保する。一般的なアイコンのみのステータスアイテムにちょうどよい。
・NSVariableStatusItemLength:ステータスアイテムの内容に合わせた幅を確保する。
あとは用途に応じてステータスアイテムのプロパティを指定するだけだ。主に使いそうな項目には次のようなものがある。
・action (Selector):ステータスアイテムをクリックした時のアクションを指定。
・image (NSImage):ステータスアイテムのアイコンを指定。
・alternateImage (NSImage):ステータスアイテムのハイライト時のアイコンを指定。自動作成の白黒反転イメージではなく画像データで指定したい場合は使用。この項目を指定した場合は、タイトル文字の自動反転が行われなくなるため、アイコンのみのステータスアイテムでないのなら、viewにカスタムビューを指定してハイライト時の振る舞いをカスタマイズした方がいいかもしれない。
・title (NSString):ステータスアイテムのタイトル文字列を指定。
・attributedTitle (NSAttributedString):ステータスアイテムの属性付きタイトル文字列を指定。
・highlightMode (BOOL):YESを渡すとハイライト時の反転表示を行う。
・toolTip (NSString):ツールチップを指定する。
・menu (NSMenu):メニュー項目を指定する。デモではアウトレット接続しておいたNSMenuを渡している。
・view (NSView):ステータスアイテムにカスタムビューを表示したい場合に指定する。振る舞いを細かく指定したい場合に使用。
以下、実装ファイルの内容。(すごいシンプルだけど)デモはGitHubにあり。
スポンサーリンク
タグ:NSStatusItem