データパスから表示パスを作る
ベジエパスの変形にはアフィン変換を使います。アフィン変換を使うと図形の平行移動、拡大・縮小、そして回転操作をする事ができます(ちなみに反転操作は-1倍の拡大と考えれば実現できます)。
NSAffineTransformクラスのオブジェクトに変換操作を登録し、全て登録したらtransformUsingAffineTransform:メソッドを使って、ベジエパスに変換を適用します。ここで注意すべきは変換操作の登録は逆順に登録しなければいけないという事です。
最後にsetNeedsDisplay:メソッドでビュー全体の更新が必要であるという印を付けておきます。これでビューが再描画されて、今作った表示パスが画面に表示される事になります。
//
// OscillatorView.m
//
#define AMPLITUDE_MAX 100
#pragma mark -
#pragma mark Path
- (void)updateDisplayPath
{
NSAffineTransform *at = [NSAffineTransform transform];
[displayPath release];
displayPath = [dataPath copy];
// 変換操作を逆順で登録する
// ベジエパスの中心をフレームの中心に移動
[at translateXBy:[self bounds].size.width/2
yBy:[self bounds].size.height/2];
// サイズをフィットさせる
[at scaleXBy:([self bounds].size.width-5)/[displayPath bounds].size.width
yBy:([self bounds].size.height-5)/(AMPLITUDE_MAX*2.0)];
// ベジエパスの中心を原点に移動
[at translateXBy:-NSMidX([displayPath bounds])
yBy:-NSMidY([displayPath bounds])];
[displayPath transformUsingAffineTransform:at];
[self setNeedsDisplay:YES];
}
イベントに応答する
ここではまずビューの外枠を表示します。そして表示パスを描画するのですが、リサイズ中は描画を抑制します。これは処理を軽くするためです。
さて、再描画が必要になるのは
1.データパスが変更された時
2.ビューのサイズが変わったとき
の二つのケースが考えられます。データパスが変更された時の処理は、既にアクセサメソッドで説明しました。ビューのサイズが変わった時はイニシャライザで説明した様に通知を受け取って対応します。通知を受け取るメソッドはframeDidChange:です。
frameDidChange:が呼ばれる時はビューのサイズが変わっているのでupdateDisplayPathメソッドを呼んで表示パスを更新します。これで再描画まで実行されます。ただしリサイズ中は表示パスの更新を抑制します。
これだけだとリサイズが終わった時に原図が描画されません。これに対処するにはviewDidEndLiveResizeというメッセージを受けた時にupdateDisplayPathを呼び出せばOKです。
//
// OscillatorView.m
//
#pragma mark -
#pragma mark Event Handler
- (void)drawRect:(NSRect)rect
{
[[NSBezierPath bezierPathWithRect:[self bounds]] stroke];
if(![self inLiveResize])
[displayPath stroke];
}
- (void)viewDidEndLiveResize
{
[self updateDisplayPath];
[super viewDidEndLiveResize];
}
- (void)frameDidChange:(NSNotification *)aNotification
{
if(![self inLiveResize])
[self updateDisplayPath];
}

ホーム
前へ