「Programming」カテゴリーアーカイブ

MotionEditor 開発状況

書いても書いても終わりません。当初は USB アダプターと RCB-3HV との通信に時間が掛かるだろうと予想していたのですが、何のことはなく設定画面が沢山有るし、サーボの数が24個有るので大変です。こういう時 IB の GUI で画面を作成するのは面倒ですねぇ。プログラムだと基本の1個を書いておけばループを回すだけなので。
モーションのオブジェクトで有る POS , SET , CMP , MIX ですが、現在は POS のみ出来てます。配置、ドラッグ、削除、はまぁ出来たのですが結線自体は出来ているのですが破線の描画が変です。今回はベジェを使って描画していますがベジェって開始と終わりの位置が異なる場合勝手に線を描画するのでしょうか?なんかそんな感じなんです。破線が破線にならない、オブジェクトを移動すると破線に見える時もある、調査は後回し。
元の HeartToHeart が Windows のアプリっぽいのでマック作法に出来る限り変換。パラメータ等の値を設定するウインドウでウインドウを閉じると設定されるってどうよ、って感じなので。キャンセルしたい時は無いのか、と聞きたい。OK キャンセルボタンが有るウインドウも有るのですが。
現在はこんな感じです。出来てない機能も有る、アイコンは未だ作成していないので文字だけ。

MotionEditor開発状況

今まで開発したプログラムはシステムで用意された部品を少しモディファイするくらいだったのですが、今回のプログラムはモーションの編集ビューにその時々のポジション情報であるオブジェクトを置いたり、移動したり、線で繋いだり、と大変です。繋ぐ線も途中の真ん中で矢印を書かないといけないし、もー色々調べて疲れます。完成した時はかなりプログラミング技術が向上するのではないだろうか。でもなぁ、すぐに忘れてしまうしなぁ。。。。。
で、ドキュメントベースで再作成してます。前回の下地も有るので、少し楽です。モーションファイルを読み込んで編集ビューに表示する所です、と言っても表示するオブジェクトは数種類有るがまだ1種類だけ。

こんな感じです。

Mac OS X での印刷処理

これはドキュメントタイプでは無いアプリケーションで印刷を行おうと戦った結果です。間違っている所は多々あると思いますが、参考になれば幸いです。
まず、Mac OS X での印刷は印刷するビューを作成してそれを NSPrintOperation で指定すれば可能です。言い換えれば印刷するビューを作成しないと印刷出来ない、と言う事になります。
プログラムでは NSView のサブクラスを作成します。「Print」アクションを受け取るとまず現在設定されている用紙の情報を取得します。
NSPrintInfo *pinfo = [NSPrintInfo sharedPrintInfo];
NSSize paperSize = [pinfo paperSize];
で、印刷するビューを作成します。
PrintView *view;
vew = [[PrintView allocWithZone:[self zone]]
initWithFrame:NSMakeRect(
0.0, 0.0, paperSize.width, paperSize.height)
memos:item];
私はメモを印刷するのでここでメモの情報をセットしています。別に後でも良いかも。
印刷するフォントを設定します。
[view setFont:mTextFont];
印刷する対象が既にフォーマットに関する情報を持っているのなら不要だと思います。私の場合素のテキストなので既定のフォントをセットしています。
NSPrintOperation *op = [NSPrintOperation
printOperationWithView:view
printInfo:pinfo];
[op setShowPanels:YES];
[op runOperation];
これで印刷パネルが表示されます。
その後ビューをリリースします。
[view release];
これで本体側の処理は終わりです。

次に印刷されるビューに関して。
最初は生成時に呼ばれる initWithFrame です。
– (id)initWithFrame:(NSRect)frame memos:(ListItem*)ListItem;
ここでは、まず NSView のフレームのセットと印刷する内容を保持する NSTextStorage レイアウトを担当する NSLayoutManager 実際の表示を担当する NSTextContainer をそれぞれ初期化します。
self = [super initWithFrame:frame];
まず NSView のフレームをセットします。 NSView のサブクラスなので親に対してセットします。
次にNSTextStorage を生成します。
mTextStorage = [[NSTextStorage alloc] init];
NSLayoutManager *layoutManager = [[NSLayoutManager alloc] init];
NSLayoutManager を生成します。
[layoutManager setDelegate:self];
NSLayoutManager のデリゲートに自分をセットします。
NSTextContainer *textContainer = [[NSTextContainer alloc] init];
NSTextContainer を生成します。
NSSize tcSize;
tcSize.width = frame.size.width;
tcSize.height = frame.size.height;
NSTextContainer は最初どんな大きさでも表示出来るように可能な最大の大きさを持っていますので、ここでは印刷する1ページの大きさをセットします。
[textContainer setContainerSize:tcSize];
[layoutManager addTextContainer:textContainer];
[textContainer release];
NSTextContainer を NSLayoutManager にセットしリリースします。
[mTextStorage addLayoutManager:layoutManager];
[layoutManager release];
NSLayoutManager を NSTextStorage にセットしてリリースします。
[mTextStorage retain];
NSTextStorage は retain します。drawRect とかで使用するので。

ここで NSTextStorage に印刷するメモの内容をセットしても良いのですが(最初はここでセットしていた)私の場合フォントをセットするので、そのメソッドで行いました。
でもメモのオブジェクトが有るので、それをクラス変数にセットして retain しています。

NSTextStorage に印刷する内容をセットするのですが、NSTextStorage を変更する場合は処理の前に
[mTextStorage beginEditing];
変更が終わった後で
[mTextStorage endEditing];
を実行する必要が有ります。
さらに NSTextStorage にセットする内容は NSAttributedString となります。
特に編集する必要が無い場合は
NSAttributedString *memoAttr = [[NSAttributedString alloc] initWithString:memo];
で大丈夫です。色々とフォントや大きさ、色、等を変更したい場合はここで行って下さい。
[mTextStorage appendAttributedString: memoAttr];
で印刷したい文字列を NSTextStorage にセットします。
ここで印刷したい内容が1ページに収まる場合は特に問題も無く、何もしなくても印刷出来ます。
1ページに収まらない場合は NSLayoutManager に Delegate をセットしたので
– (void)layoutManager:(NSLayoutManager *)aLayoutManager didCompleteLayoutForTextContainer:(NSTextContainer *)aTextContainer atEnd:(BOOL)flag
が呼び出されます。
ここで aTextContainer が nil の場合 NSTextStorage の内容を NSLayoutManager が NSTextContainer に配置していったが一杯になった、と言う事なので initWithFrame でやった様に
NSTextContainer を生成して NSLayoutManager に追加してやります。
NSTextContainer *textContainer = [[NSTextContainer alloc] init];
NSSize tcSize;
tcSize.width = paperSize.width;
tcSize.height = paperSize.height;
[textContainer setContainerSize:tcSize];
[aLayoutManager addTextContainer:textContainer];
[textContainer release];
そして印刷する範囲が広がったのでこの印刷ビューの大きさも大きくします。
NSRect frame = [self frame];
frame.size.height += paperSize.height;
[self setFrame:frame];
で、これが不思議なのですが追加した NSTextContainer のグリフの範囲を取得すると旨く動作します。
NSRange glyphRange = [aLayoutManager glyphRangeForTextContainer:textContainer];
これを実行しないと再度 NSTextContainer が一杯になった時このデリゲートが呼ばれません。
呼ばれないと印刷できない情報が残ってしまいます。
NSLayoutManager のデリゲートにはもう一つ
– (void)layoutManagerDidInvalidateLayout:(NSLayoutManager *)aLayoutManager
が有ります。レイアウトが無効になった時呼び出される、とか。
私は理解出来てませんが、この中では
int glyphNum = [aLayoutManager numberOfGlyphs];
と NSLayoutManager のグリフの数を取得すると旨く動作します。
複数ページ印刷する場合は NSLayoutManager のデリゲートが何度か呼び出されて NSTextContainer を NSLayoutManager に追加する、と言う処理を行います。

実際の1ページの印刷処理は
– (void)drawRect:(NSRect)rect
が担当します。
NSLayoutManager *layoutManager = [[mTextStorage layoutManagers] objectAtIndex:0];
で NSLayoutManager を取得します。今回は NSLayoutManager を1個しか使って無いので NSArray の最初のオブジェクトです。
次に NSTextContainer を取得しますが複数ページの場合 NSTextContainer が複数存在するので印刷対象のページの NSTextContainer を取得します。
NSTextContainer *textContainer = [[layoutManager textContainers] objectAtIndex:page];
取得した NSTextContainer で印刷可能なグリフ範囲を取得します。
NSRange glyphRange = [layoutManager
glyphRangeForTextContainer:textContainer];
で、取得したグリフ範囲を描画します。
[self lockFocus];
[layoutManager drawGlyphsForGlyphRange: glyphRange atPoint: rect.origin];
[self unlockFocus];

以上で、とりあえず印刷は可能です。
今後の課題としては
・デリゲートが追加した NSTextContainer のグリフ範囲を取得しないと続けて呼び出されないのは何故?
・今回は印刷ビューの中でレイアウト処理を行ったが、良いのか?
・先にレイアウトを行って準備出来てから印刷ビューを作成した方が良いのか?

まぁ初めての印刷処理にしては上出来かな、えっ?参考にもならない、すみません。

ログイン時に起動するプログラムの登録・削除

システム環境設定でアカウントを選択「ログイン項目」タブを選択するとログイン時に起動されるプログラムの一覧が表示されます。ここに登録するとログイン時自動的に起動されます。ここの登録・削除(まぁ変更も出来ますが)をプログラムから行いたい人はサンプルが developer.apple.com に有るので参考にしてみて下さい。
http://developer.apple.com/samplecode/LoginItemsAE/
AppleEvent を c プログラムから発行して制御しています。

欲を出して悩み中

iPod へのメモ転送は出来たが、欲を出して .Mac 同期に挑戦中です。
同期するには新規・変更・削除の情報が必要になります。iPalmMemo の場合コンジットで Palm との同期が終了しているので Palm 側での情報が無くなってしまってます。もし、その情報を得るならコンジットプログラムを修正して出力する様にしないといけません。さらに iPalmMemo は Palm との間での変更状態 .Mac との間での変更状態、と2つの状態を管理する必要が有ります。
一番良い方法はコンジットが .Mac と同期すれば一気に片付くんですが、Palm の HotSync Manager の開発環境は Code CodeWarrior となっています。すなわち Cocoa では無く Carbon での環境なんです。Carbon から Cocoa を使えるらしいのですが、その間には深くて長い川が。。。
今回の場合 SyncService と言うフレームワークを使うので Code CodeWarrior で使えるのかどうか、かなり怪しい。Mark/Space の MissingSync を使う環境で有ればコンジットが Xcode を使い Cocoa で開発出来るので可能性は十分有ります、但し MissingSync が必要になります。
まぁ、現状の HotSync Manager 環境の iPalmMemo で出来る所まではやってみようと思ってます。Entourage を使っている人は Entourage のメモとも同期する事が可能になります。

iPod への転送も私の環境では OK なのですが、iPod も色々有るので動作するのかどうか不明です。そこで、「テストしてやろう」と言う奇特な方がおられましたら私にメールして下さい。よろしくお願いいたします。