NSPopUpButton を使ってみる

Swift プログラミング

OSX アプリで選択肢の中からどれかを選ばせる UI を使わせたくて、NSPopUpButton を使ってみることにしました。


OSX アプリで選択肢の中からどれかを選ばせる UI を提供したくて、NSPopUpButton を使ってみることにしました。

Pop Up Button を配置する

NSPopUpButton は Interface Builder を使って簡単に設置できました。オブジェクトライブラリにある Pop Up Button を普段どおりドラッグアンドドロップするだけです。

Pop Up Button のスタイル

ところで NSPopUpButton を設置してみると、ボタンのスタイルを属性インスペクターで設定できるようになっていました。

ここでは次の 2 種類を指定できる様子です。

Type イメージ
Pop Up
Pull Down

見た感じの違いとしては、Pop Up の方はボタンにメニューをかぶせる形で全ての項目を列挙するのに対し、Pull Down の方は最初の項目がボタン内に表示されてそれが見えている状態で残りの項目が列挙する、そんな挙動の違いに見えます。

今回は Pull Down 的な見た目にしたかったので、そのスタイルを選んでみました。

Pop Up Button を Pull Down スタイルで使用する

スタイルの違いは単なる動きの違いではなく、内側的にも動きがけっこう異なるみたいでした。

Pop Up は見たとおりに候補全体から選ぶシンプルな作りみたいですけど、Pull Down ではボタン内に表示されている項目はメニューのヘッダー的な意味合いで、そのサブメニューとして残りの項目が表示され、選択できる状態にある様子です。

それに伴ってなのか、制御の仕方も変わってくるようでした。今回は Pull Down スタイルのボタンを使おうと思うので、それを前提にコードを組み進めます。

アウトレットを準備する

今回は NSPopUpButton で扱うデータを、プログラム内のデータで用意して、それを実行時に設定する方法をとってみます。

そのため、プログラム内からアクセスできるように、Storyboard 内に設置した NSPopUpButton と連結できるアウトレットを用意しておきます。今回は popUpButton という名前の変数で用意しました。

@IBOutlet weak var popupButton:NSPopUpButton!

メニュー項目を設定する

アウトレットの準備ができたら、そこに項目を設定します。

今回は、あらかじめ用意しておいた配列の内容を使って項目を 1 度設定してしまえば、その後は項目が動的に変わることはない場面だったので、先ほど定義したプロパティに didSet を追加して、アウトレットに NSPopUpButton が設定され次第、項目が設定されるようにしてみます。

ヘッダー項目

Pull Down 方式の NSPopUpButton の場合、最初の項目はヘッダー的なメニュー項目になるようです。

各項目は NSMenuItem で設定することになっていて、選択したときの動作をそれに登録できるようになっていますけど、最初の項目は表示のためにしか使われない様子なので、今回は NSPopUpButton に用意されている addItemWithTitle:メソッド を使って、テキストデータで設定することにしました。

self.popupButton.addItemWithTitle(buttonTitle)

これで、例えば上の例では、NSPopUpButton の最初の項目として、変数buttonTitle に設定されている文字列が登録されます。引数には文字列を渡しますが、実際にはこれをタイトルに持つ NSMenuItem が登録される様子です。

リストアップする項目

そして、ボタンを選択したときに表示される項目を設定します。先ほどのヘッダー項目の設定に続いて、ボタンに追加していったアイテムが表示項目として登録される様子です。

ここでも addItemWithTitle:メソッド を使ってテキストデータで項目を追加することもできますが、今回はメニューを選択したときに独自の処理をしたいので、自分で NSMenuItem を作って登録することにします。

というのも、Pull Down 式の NSPopUpButton の場合、何も実装していないと、既定ではメニュー項目を選択しても、選択したメニューの項目がヘッダーの項目に表示されるみたいな動きをしてくれないためです。


今回はメニューを選択したときに選択した項目のタイトルをヘッダー項目に表示したいので「選択中の項目のタイトルをヘッダー項目に設定する」メソッドを自分自身に実装して、そのセレクターを 変数selector に格納してあるものとして、メニュー項目を作成して行きます。

for title in self.titles {

	let menu
	
	menu = NSMenuItem(title: title, action: selector, keyEquivalent: "")
	menu.target = self
	
	self.popupButton.menu!.addItem(menu)
}

ここまでのまとめ

これで、最初に表示されるヘッダー項目と、選択候補の一覧を準備することができました。ここまでをまとめると、次のような実装になります。

// コードから項目を設定できるようにアウトレットを定義します。
@IBOutlet weak var popupButton:NSPopUpButton! {
	
	// 今回はアウトレットが設定されたときに項目を初期化します。
	didSet {

		// ヘッダー項目を設定します。選択時のアクション等は不要なので、テキストだけで設定しています。
		self.popupButton.addItemWithTitle(buttonTitle)
	
		// ボタンを押したときの選択肢は self.titles に入っている情報を設定します。
		for title in self.titles {

			let menu

			// 選択時に選択内容を画面に反映させたいので、その機能をセレクターに指定したメニュー項目を作って登録します。			
			menu = NSMenuItem(title: title, action: selector, keyEquivalent: "")
			menu.target = self
			
			self.popupButton.menu!.addItem(menu)
		}
	}
}

メニュー項目が選択されたときの動作を実装する

メニューが選択されたときの動作を、先ほど NSMenuItem を作るときにセレクターで指定しましたが、その内容は次のような感じにしました。

func popupSelected(item:NSMenuItem) {

	self.popupButton.title = item.title
}

ヘッダー項目として表示されるテキストは NSPopUpButtontitleプロパティ でアクセスできるようなので、そこに、セレクターに渡されてきた選択した NSMenuItem のタイトルを設定しています。

この例ではタイトルを書き換えるだけですが、その他の更新を行いたいときもここで行えば大丈夫そうです。

おしまい

これで、プログラムから表示項目を用意して、選択するとその内容がヘッダー項目に反映される NSPopUpButton を実装できました。

Pop Up 方式と Pull Down 方式とで実装方法に少し違いが見られたりして、最初は不慣れで戸惑いましたけど、わかってみるとけっこう簡単に作れて便利な印象でした。