μ-Blog

μFactory管理人が、誰かに役に立つかもしれない情報をまとめたブログです

NSScrollViewとNSAffineTransform

 現在、実験的に作っているプログラムで、NSScrollViewの中のカスタムビュー上にNSImageを拡大縮小して描画します。拡大縮小といえば、NSAffineTransformです。

// - (void)drawRect:(NSRect)rect内
NSAffineTransform *transform = [NSAffineTransform transform];
[transform scaleBy:2.0f];
[transform set];
// ここ以下でdrawAtPoint でNSImageを描画

しかし、これでは期待の動作をしません。問題点としては、たとえば...

  • NSView類のisFlippedによってはY軸方向に画像が反転する
  • NSScrollViewを操作しても画像がスクロールしない!(スクローラーは移動する)

解決策を先に述べると、次の通りです。

// - (void)drawRect:(NSRect)rect内
// 正解
NSAffineTransform *transform = [NSAffineTransform transform];
[transform scaleBy:2.0f];
[transform concat];
// ここ以下でdrawAtPoint でNSImageを描画

解決の糸口を与えてくれた参考資料:NSAffineTransform Additions Referenceには、こうあります

If this method is invoked from within an NSView drawRect: method, then the current transformation matrix is an accumulation of the screen, window, and any superview’s transformation matrices. Invoking this method defines a new user coordinate system whose coordinates are mapped into the former coordinate system according to the receiver’s transformation matrix. To undo the concatenation, you must invert the receiver’s matrix and invoke this method again.

要するに、

  • NSAffineTransformによるAffine Transformはユーザーが明示している以外にも使われていることがあり、ユーザーが設定する前の初期値は所謂「1」ではない
  • setを使用すると、それらを完全にユーザーが上書きしてしまうので、予期しないことが発生する可能性があるので慎重に利用すべし
  • concatを使用すると、現行のAffineTransformに対して重ね合わせ演算をした値がセットされるので基本こちらを使うべし

(ちなみに、ハマった理由は、NSAffineTransform Class Referenceのみを一所懸命読んでいたからです)。