ページ

2009年12月15日火曜日

NSMatrix を使いカスタムボタンパレットを実装する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

カスタムボタンパレット

NSMatrix を使ってカスタムボタンを並べたパレット(バー)を作った。SimpleCap で使うつもりなので、用途を特化して縦一列でアプリケーションのアイコンだけを表示する仕様にした。

できあがりはこんな感じ。


開発時に確認がしやすいようにアイコンのサイズは大きくしてある。

マウスをボタンの上に置くと背景を灰色にする。


ボタンを押すと画像を暗くする。





クラス構成

3つのクラスからなる。
ApplicationButtonPallette ... パレットを利用するためのメソッドを提供する。
ApplicationButtonMatrix   ... NSMatrix のサブクラス。マウスイベントやセルを管理する。
ApplicationButtonCell     ... NSCell のサブクラス。ボタンの描画を行う。

クライアントは ApplicationButtonPallete のメソッドを使ってパレットを操作する。

クライアントからはこんな感じで利用する(サンプルにソースコードあり)。
MatrixSample_AppDelegate.m

- (void)awakeFromNib {
// Insert code here to initialize your application

pallete = [[ApplicationButtonPallete alloc] init];
pallete.action = @selector(clickAtRow:);
pallete.target = self;

[pallete setOrigin:NSMakePoint(50, 20)];
[pallete addToView:[window contentView]];


[pallete addButtonWithPath:@"/Applications/Mail.app"];
[pallete addButtonWithPath:@"/Applications/Preview.app"];
[pallete addButtonWithPath:@"/Applications/Address Book.app"];
[pallete addButtonWithPath:@"/Applications/iTunes.app"];

}

.ApplicationButtonPallete へアプリのパスを指定して追加するだけ。ボタンが押されると指定した target へ action指定のメッセージが送られる。


詳細はソースコードを見てもらうとしてポイントだけ解説する。

マウストラッキング

NSCell でも多少できるのだがマウスオーバーが扱えない。NSButtonCell のサブクラスで試したところ、こちらはできた。ただしマウス移動の検出間隔が荒かったりして実用上問題あり。結局 NSMatrix をサブクラス化して自前でマウストラッキングをすることにした。Mac OS X v10.5 からは NSTrackingArea が使えるようになったのでマウストラッキングの扱いがかなり楽になった。

Mac Dev Center: NSTrackingArea Class Reference

(参考)Cocoaの日々: NSTrackingArea


今回は NSTrackingArea をビューへ設定するメソッドを用意して、これをリサイズ時に呼んでいる。

ApplicationButtonMatrix.m
- (void)updateTrackingArea
{
if (self.trackingArea) {
 [self removeTrackingArea:self.trackingArea];
}
 self.trackingArea = [[[NSTrackingArea alloc]
 initWithRect:[self bounds]
 options:(NSTrackingMouseEnteredAndExited |
 NSTrackingMouseMoved |NSTrackingActiveAlways )
 owner:self
 userInfo:nil] autorelease];
 [self addTrackingArea:self.trackingArea];
}


セル

NSCell のサブクラスとして描画を自前で行った。

ApplicationButtonCell.m
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
 :
}


セルは状態を持っていてそれによって表示を描き分ける。

enum {
CELL_STATE_OFF,
CELL_STATE_ON,
CELL_STATE_OVER
};



ソースコード

GitHub からどうぞ
MatrixSample at 20091213 from xcatsan's SampleCode - GitHub

- - - -
前にも似たようなクラスを作ったことがある(SimpleCapのボタン列表示で使っている)。


Cocoaの日々: ThinButton (その1)ThinButton(その8)ボタンの部品化(クライアント)

今回は NSMatrix の使い方を覚える意味で試してみた。自前で全部作るのに比べて最初からセルの管理メソッドが揃っているところは便利だと思った。また NSMatrix, NSCell といった Cocoa標準の仕組みに沿って書けることは何かと応用がきく。その反面融通がきかなかったり、描画はどのみち自分でやる必要があるが。