SSブログ

曲がった迷路その28 - 実装上の注意点 [曲がった壁を持つ迷路の生成]

昨夜一晩で迷路生成の基本的な部分のコーディングは一段落した。ここまできたらいっきにいく。というか、実装はいっきにやらないとすぐわからなくなる。三日ほどで「このへたくそなコード、誰が書いた?見通し悪いなあ、読む気がせんわ」状態やし。

ドキュメントスタイルアプリの実装上の注意

ドキュメントスタイルのアプリはもう何年も作ってない。すっかり忘れてる。

NSDocumentControllerのサブクラス化

「New」メニューでドキュメントをすぐ開くのではなく、一旦ダイアログを表示するためにはNSDocumentControllerをサブクラス化する必要がある。

やりかたはいくつかあるみたいだけど、一番簡単なのは
- (IBAction)newDocument:(id)sender
を上書きして、ここにダイアログを表示するコードを書けばいい。

また、アプリが立ち上がったときやほかのアプリから切り替わったときに、開いている書類がなかったら空の新規書類が開くが、これはこのnewDocument:メソッドは経由しない。この動作をやめるためにはNSAppのデリゲートに
- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
を実装して、NOを返すようにしておく。これもすっかり忘れていてずいぶん探しまわった。

WindowControllerをサブクラス化するかどうかは微妙だけど、たいていの場合あとから必要が出てきてしまうことが多いので作っておいてNSDocumentのサブクラスと動作を分担しておく。

Cocoa Bindingの使用

パラメータを表示するパネルには最前面になっているウィンドウに問い合わせる必要がある。これを実装するのは結構大変だけど、10.3以降で使えるCocoaBindingを使えば、インターフェイスビルダの上だけでできてしまう。
  1. パラメータのスライダなどのコントロールのBindingsパネルに
    • Bindにチェックを入れる
    • to:にApplicationを選ぶ
    とする
  2. Model Key Pathに以下をドットでつないで書く
    • mainWindow (これは最前面のドキュメントウィンドウになる)
    • delegate (これはたいていNibファイルでFile's Ownerになっている。普通はwindowController)
    • もしwindowControllerにアクセサメソッドを書いていればここにそのメソッドあるいはインスタンス名
    • NSDocumentのサブクラスに書いてあればさらにdocument(windowControllerのインスタンス)入れてそのメソッドあるいはインスタンス名
とするだけでいい。これをCocoa Bindingを使わずにやろうと思うと、インスタンスをたぐって読み書きするコードを書かなければいけない。これは難しくはないけどかなり面倒。

とくにユーザが行った変更をすぐに反映させようとすると微妙なタイミングに気をつける必要が出たりするが、Bindingを使うとそういった配慮はかなり減らせて精神衛生上非常に良い。

しかし、Cocoa Bindingは一つのメソッドなり変数なりにアクセスするための方法がいろいろ用意されていて、場合によっては何通りにも指定のしかたができてしまう。自分なりにこういうときにはこれを使う、とパターンを決めておかないとあとになってどうやって指定しているのかわからなくなって探しまわるということもある。というか、今まで何度もそう言うことがあった。まだ使い慣れてない、と言う感じ。

迷路の表示

ウィンドウに表示するためにはNSViewのサブクラスを貼付けておかなければいけない。
@interface SMCMazeViewer : NSView {
    SMCWallField        *field;
    NSAffineTransform   *transf;
    float               scalingFactor;
    float               *displaymap;
    BOOL                showPotential;
    BOOL                showProcess;
    BOOL                showWallColor;
}
壁の表示にはfield変数に問い合わせて端点位置の配列を作ってそれをBezier pathにする。 その他に細かな表示用のパラメータをいくつか持たせる。

showPotentialは壁の描画の下書きにスペックルポテンシャルをグレー表示するかどうかを指定する。

showProcessは壁を作っている最中もその過程を表示するかどうか、showWallColorは壁を二つに塗り分けて解をわかりやすくする、などである。

これらのパラメータもパラメータパネルからCocoa Bindingを使って指定できるようにしておくと、簡単にできる。

PDFの出力

NSViewはpdfを出力できる。NSViewのメソッド
- (NSData *)dataWithPDFInsideRect:(NSRect)aRect;
はaRectの中のオブジェクトをpdf形式にしてNSDataに詰めて返す。

従って例えば、さっきのSMCMazeViewerに対してdrawRect:の外(focusの当たってないとき)でdataWithPDFInsideRect:を呼んでやり、NSDataをファイルに書けばいい。例えば、NSDocumentのファイルに書き出すときに呼ばれるメソッドを上書きして
- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
{
    NSView  *viewer = [[[self windowControllers] lastObject] mazeViewer];
    NSRect  viewrect = [viewer frame];
    NSMutableData  *pdfdata = [viewer dataWithPDFInsideRect:viewrect];
    [[[self windowControllers] lastObject] setDocumentEdited:NO];
    *outError = nil;
    return pdfdata;
}
とすればウィンドウに書いたものがそのままpdfになる。ただしviewerはウィンドウに貼ったNSViewをさしているとする。BezierPathを使っているのでできたpdfも迷路の壁はストロークになって、例えばIllustratorなどで編集可能である。

ユーザデフォルト

Cocoa Bindingを使えばいいとかいいながら、つい使えるところでも忘れてしまってちまちまコードを書いてしまった。たとえばUserDefaultsはBindingを使えば何も書かなくてもいいのに、昔からユーザ設定可能なパラメータを読み書きするところにはNSUserDefaultsにも同時に書いておくのが癖になっていた。昔はこれは非常にいい癖だった。

しかしCocoa Bindingを使えばnibファイルにNSUserDefaultsControllerを乗せてそこにバインドするだけでいい。

やっぱり普段書いてないとすぐ忘れる。

nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。