カスタム値変換を使うための三つのステップ
カスタムの値変換を使うには、以下の三つのステップが必要です。
- NSValueTransformerのサブクラスを作る
- そのサブクラスのインスタンスを生成して名前付きで登録する
- バインディングを設定してValue Transformerに登録した名前を入力する
1. NSValueTransformerのサブクラスを作る
どのような変換を行うのかを決めます。具体的には、サブクラスが必ず実装しなければならないメソッドが決まっているので、それを実装するという事です。
2. そのサブクラスのインスタンスを生成して名前付きで登録する
作った値変換を登録します。登録にはNSValueTransformerのクラスメソッドsetValueTransformer:forName:を使います。ここで登録するのはインスタンスなので、同じクラスから複数のインスタンスを生成して違う名前で登録する事ができます。
例えば今回はNSBezierPathからNSImageに変換するわけですが、変換するサイズが異なる値変換を登録したりできるわけです。まず一つインスタンスを生成してサイズを100×100に設定し、RMGPathToImage100という名前で登録します。次に新たなインスタンスを生成してサイズを200×200に設定し、RMGPathToImage200という名前で登録します。こうしておけば一つのクラスで内容の異なる二つの値変換を使えます。
いつ登録するのかですが、なるべく早い段階がよいと考えAppControllerのinitializeメソッドで登録する事にしました。AppControllerはアプリケーション全体の面倒を見るコントローラで、今回新たに作成します。
3. バインディングを設定してValue Transformerに登録した名前を入力する
使う値変換を指定します。指定には登録名を使います。バインディングの設定でValue Transformerを指定する場所があるので、ここに登録名を入力します。
NSValueTransformerのサブクラスを作る
Xcodeのファイルメニューから新規ファイル…を実行します。Xcode3.1にバージョンアップしたら、現れるウィンドウが変化しました。リストの項目が多すぎるので、グループ分けして整理する必要が生じたのでしょうね。
CocoaグループのObjective-C classを選んで「次へ」をクリックします。

クラス名を入力します。NSBezierPathからNSImageへ変換するので、RMGPathToImageTransformerとしました。RMGはRepeating Motif Generatorの頭文字です。固有の接頭詞をつける事で名前の重複を避けています。

インターフェイスファイルの変更点ですが、まずスーパークラスをNSValueTransformerに変更します。インスタンス変数は追加しません。
説明の時に例として挙げた様に、イメージサイズを変更できる様にするなら、サイズを保持するインスタンス変数を追加する所でしょう。今回はそこまで汎用性を高めなくてもよいと考えました。
サブクラスで実装する事が必須とされている三つのメソッドの宣言を追加します。
//
// RMGPathToImageTransformer.h
// RepeatingMotifGenerator
//
// Copyright NovemberKou 2008 . All rights reserved.
//
#import <Cocoa/Cocoa.h>
@interface RMGPathToImageTransformer : NSValueTransformer
{
}
+ (Class)transformedValueClass;
+ (BOOL)allowsReverseTransformation;
- (id)transformedValue:(id)value;
@end
transformedValueClassは変換されたオブジェクトのクラスを指定するメソッドです。NSImageに変換して返すので[NSImage class]を返します。
allowsReverseTransformationで逆変換ができるかどうかを表します。NSImageからNSBezierPathに変換する事はできないのでNOを返します。
transformedValue:が変換を行うメソッドです。引数で渡されたNSBezierPathをアフィン変換を使ってイメージサイズに合わせる様に変形します。この辺りはOscillatorViewで説明したので、詳細説明は省略します。
変形してしまうのでコピーを作って、それを操作しています。
//
// RMGPathToImageTransformer.m
// RepeatingMotifGenerator
//
// Copyright NovemberKou 2008 . All rights reserved.
//
#import "RMGPathToImageTransformer.h"
@implementation RMGPathToImageTransformer
+ (Class)transformedValueClass {return [NSImage class];}
+ (BOOL)allowsReverseTransformation {return NO;}
- (id)transformedValue:(id)value
{
NSSize imageSize = NSMakeSize(100,100);
NSImage *image = [[[NSImage alloc] initWithSize:imageSize] autorelease];
NSBezierPath *bezierPath = [value copy];
NSAffineTransform *at = [NSAffineTransform transform];
if(value == nil)
return nil;
// 変換操作を逆順で登録する
// ベジエパスの中心をイメージの中心に移動
[at translateXBy:imageSize.width/2
yBy:imageSize.height/2];
// サイズをフィットさせる
[at scaleXBy:(imageSize.width-5)/[bezierPath bounds].size.width
yBy:(imageSize.height-5)/[bezierPath bounds].size.height];
// ベジエパスの中心を原点に移動
[at translateXBy:-NSMidX([bezierPath bounds])
yBy:-NSMidY([bezierPath bounds])];
[bezierPath transformUsingAffineTransform:at];
[image lockFocus];
[bezierPath stroke];
[image unlockFocus];
[bezierPath release];
return image;
}
@end

ホーム
前へ