にけのて
Nike+iPod と JogNote を使ってジョギング。で、Mac から Nike+ のデータをあれこれ見たくなったので、ちょこちょこっと作ってみた。
スポンサーサイト
上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

にけのて for Windows を Visual Studio で作ってみた
先日 Visual Studio 2008 の DVD が手元にやってきた。というわけで、GW 中に Visual Studio 2008 を使って「にけのて」の Windows バージョンを作ってみたので、その簡単なメモ。

nikeNoteWin06


C# とインテリセンス
言語は C# を選択。なんか MS 一押しなんでしょ? せっかくだから C# でトライ。で、今回の驚きは噂には聞いていたけれどインテリセンスって凄いな~って事。C# のドットで繋げる記述とインテリセンスの組み合わせでさくさくとコードの入力ができる。API 全然知らない自分でも出てくる候補でなんとなく先に進める。簡単なリファレンスガイドにもなってくれたりして、こりゃ凄いな~。Xcode で Objective-C の時にも候補を出したりできるけど、こんなに使い勝手が良いとは言えないし。
その代わり? デザインの編集は InterfaceBuilder の方が全然使いやすい気がする。IB ならわからなくてもアレコレいぢってるとなんとかなるし。ま、自分の場合はWindows での作り方を良く知らないから使えないってのかもしれないけど、凄く一生懸命プロパティ見たりしてもなんだかどうにもわからないんだよな。結局、ウィンドウサイズを大きくしたら中のグラフが大きくなるってのはできなかった…。ばねと突っ張り棒の変更が見つからないんだよ~!

情報量が桁違い!
やっぱり Windows 環境は凄い! ググったら物凄い量の情報が出てくる! 少ない情報を、しかも英語で読むって必要が全くなかった。この辺りは Mac と全然違うな~。今回、XML をいぢる辺りで色々と勉強になった。Cocoa でももっと簡単にワークアウトのデータをあれこれできたんだな~。後で作り替えよう!

勉強不足は否めない
でも、結局やり残している事はたくさん。ListView での Binding やウィンドウのサイズに合わせてグラフ(PictureBox)のサイズも自動的に変わるとか、Xcode と IB ならサクっとできるんだけど VisualStudio だと見つからないってのが結構ある。ちゃんと勉強すれば良いのだろうけど、今回はちょこっと触ってみたって範囲でやってみようと思ったのでこんなもん。
でも、おかげで色々と新しいことを知ったりもしたので、ちょっと Mac の方もアップデートしてみようと思った。Objective-C 2.0 でプロパティや Fast Enumerator をガンガン使うと結構コード書くのが早くなりそうだし。せっかくなのでガベージコレクション様に全てを任せて最初からのびのびと?書いてみよう!



テーマ:プログラミング - ジャンル:コンピュータ

SDL のデモを Mac の Xcode でビルドしてみた
とりあえず選んだデモコレ、Bouncing Penguin。デモを上から見ていって MacOS X のマークが付いてるのがなかなか出てこなくて…。Boom と Bouncing Penguin でどちらにしようか迷って、ペンギンなのでこっちにした。
ダウンロードした bouncing.zip を展開すると…macosx フォルダに Xcode のプロジェクトファイルがあるわけじゃなく…。README には make してね!とあるけど、今回は Xcode で SDL のテンプレートを使ってビルドしたいので make はしない。

bouncing.c を眺めてみるとどうやら SDL_mixer の Framework が必要らしい。ググってさっくりバイナリをダウンロード。マウントして SDL_mixer.framework を /ライブラリ/Frameworks/ へコピー。これで準備は OK。
SDL_mixer


まずは Xcode を起動して SDL Application のプロジェクトを作る。
SDL-Application

名前は myBouncing にする。
SDLprojectName

出来上がったプロジェクトに Framework を加える。/ライブラリ/Frameworks/ から SDL.framework と SDL_mixer.framework を Frameworks グループへドラッグ&ドロップ。
SDLaddFramework

ダイアログには特に何もせずに[追加]をクリック。
SDLaddFrameworkDialog

次にデモの bouncing フォルダから画像データ(bouncing.bmp)と音データ(bouncing.wav)を Resources グループへドラッグ&ドロップ。これもダイアログには何もせずに [追加] をクリック。
SDLprojectAll


ソースコードは bouncing.c をそのまま main.c にコピーして、コピーした main.c の int main をオリジナルのもの

int main(int argc, char *argv[])


にしておく。

これでビルドすれば OK!と思ったのだけど、エラーが出た。

/Users/paraches/myBouncing/main.c:12:23: error: SDL_mixer.h: No such file or directory


だそうだ。う~ん、ヘッダファイルが見つかってない???
というわけで、ターゲットを選択して command+I で情報を見る。ビルドタブ?の下の方、検索パスのヘッダ検索パスに /ライブラリ/Frameworks/SDL_mixer.framework/Headers/ を加えた。
SDLaddHeader

再度ビルドすると今度は無事ビルド終了。
早速実行すると…GDB が起動。コンソールを見ると

Error: 'bouncing.bmp' could not be open: Couldn't open bouncing.bmp


だそうだ。

どうやら

s_surface = SDL_LoadBMP("bouncing.bmp");


ここで bouncing.bmp が読み込めてないらしい。リソースはどうやって読むのよ?と思ったら、どうもファイルを読むのはアプリケーションと同じフォルダにあれば読めるらしい。それじゃデータをアプリの中に入れられないじゃん?と思ったらこんな事をして読み込むんだそうな。

s_surface = SDL_LoadBMP("myBouncing.app/Contents/Resources/bouncing.bmp");


なんか格好悪い。アプリの名前をコロコロ変える事はないだろうけど、それをソース内に書いちゃうのはなぁ~。
で、SDLMain.m の方を見ると

- (void) setupWorkingDirectory:(BOOL)shouldChdir


なんてものが。アプリケーションの起動が終わった時に呼ばれてる。ここでカレント?フォルダをアプリケーションのあるフォルダにしているので、そうでなくて Contents/Resources フォルダをカレントフォルダにしてしまえば良いんじゃない?
というわけで

[[NSFileManager defaultManager] changeCurrentDirectoryPath:[[NSBundle mainBundle] resourcePath]];


を - (void) setupWorkingDirectory:(BOOL)shouldChdir の最後に入れておいた。これで必ずカレント?フォルダを Contents/Resources に変更できる。

というわけで、再度ビルドして起動!
無事エラーも出さずに bouncing penguin が起動した!

それにしても、Xcode の使い方あんまりわかってないな~。

テーマ:Mac - ジャンル:コンピュータ

Mac の Xcode で SDL Framework を使ってみる
SDL を使ってみることにしたのでその記録。
環境は MacOS X 10.5.2 で Xcode 3.0。

インストール
本家から SDL-1.2.13.dmgSDL-devel-1.2.13-extras.dmg をダウンロード。
SDL-1.2.13.dmg をマウントして SDL.Framework を /ライブラリ/Frameworks へコピー。(コピー先のフォルダ名を間違えていたので修正!)
SDL

SDL-devel-1.2.13-extras をマウントして TemplatesForXcode に入っている4つのフォルダを /ライブラリ/Application Support/Developer/Shared/Xcode/Project Templates/Application にコピー。Application Support 以下に Developer フォルダが無かったので、そこから下のフォルダを自分で作って入れた。
SDL-extra

これで Xcode を起動して新規プロジェクト…で Application の下にさっきコピーした4つのプロジェクトが出てくれば OK。
SDL-Application


テーマ:Mac - ジャンル:コンピュータ

NSImageView からの Action はどこから出てくるのか?
何が言いたいのかわからないタイトルだな。

NSImageView を使うと特に何もしなくてもドラッグ&ドロップを受け付けてくれる。楽チン。IBNSImageView から自前のコントローラへ Action: を繋げれば、イメージが変わったときに(ドロップされたときに)メッセージが飛んでくる。(言葉はこれで良いのかな?)
でも、 NSImageView から得られるのは NSImage。そうじゃなくてドロップされたイメージの(オリジナルの?)NSURL が欲しいんだよな~。どうにかならないのかな?

というわけで、NSImageView のサブクラス MyImageView を作ってドラッグ&ドロップをやってみた。
ドラッグ&ドロップは資料を見ればなんとかなる。面倒ではあるけど難しくはない。とりあえずは受け取る側だから registerForDraggedTypes: で受け取る Type を登録して

- (id)initWithFrame:(NSRect)frameRect
{
[super initWithFrame:frameRect];
[self setImageFrameStyle:NSImageFrameGrayBezel];
[self registerForDraggedTypes:[NSArray arrayWithObjects:NSURLPboardType, nil]];
return self;
}


後はNSDraggingDestination protocol に対応?すれば良い。全部で8つ。

Managing a Dragging Session Before an Image is Released
– draggingEntered:
– wantsPeriodicDraggingUpdates
– draggingUpdated:
– draggingEnded:
– draggingExited:
Managing a Dragging Session After an Image is Released
– prepareForDragOperation:
– performDragOperation:
– concludeDragOperation:

でも、draggingEnded: はまだないらしいので実質7つ。
で、ドラッグ&ドロップでイメージを受け取るときの流れはこんな感じ。

・イメージが MyImageView の上に入って来たら最初に draggingEntered: がくる。で、[sender draggingPasteboard] から何が来てるのかを確認して、自分が受け取れるなら Dragging operations の中から返事を返す。受け取れるなら NSDragOperationCopy で良いんじゃない? Move や Delete だとオリジナルが無くなっちゃうし。で、ここで MyImageView を暗くしたりしてドラッグ&ドロップできるよ!って表示にする。
今回は NSURL が欲しかったから、それがあるかどうかを確認してみる。

NSPasteboard *pb = [sender draggingPasteboard];
NSArray *supportedTypes = [NSArray arrayWithObjects: NSURLPboardType, nil];
NSString *bestType = [pb availableTypeFromArray:supportedTypes];
if (bestType) {
[self setImageFrameStyle:NSImageFrameGroove];
return NSDragOperationCopy;
}
else
return NSDragOperationNone;


・次にイメージが NSImageView の上にあり続ける?場合、延々と draggingUpdated: が送られてくる。その度に Dragging operations の中から返事を返す。今回は常に draggingEntered: で返した返事と同じものを返してる。場所によって処理を変えたりしたい場合はここで毎回チェックして返事を変えたりするのかな?

・もし「やっぱりや~めた」とかでイメージが MyImageView の上から外れたら、draggingExited: が送られてくる。ここで FrameRect を暗くしてたら元に戻さないと。更にその後でまた NSImageView の上に来たら、最初の draggingEntered: から始まる。

[self setImageFrameStyle:NSImageFrameGrayBezel];


・MyImageView 上でイメージがリリースされたら(ボタンがはなされたら)、直前の draggingEntered: メッセージか draggingUpdated: メッセージの返り値によってイメージが元の場所に戻るか prepareForDragOperation: メッセージがくるかのどちらかになる。自分が対応していない場合は MyImageView の見た目は変えないから、そのままイメージが戻って終わり。対応している場合は次へ行く。
用意しろって言われても、特にする事ないしな~。YES だけ返しとく。

・もし、prepareForDragOperation: メッセージで YES が返された場合は、perFormDragOperation: メッセージが来る。ここでドラッグされた側のデータのコピーやら何やらの作業をする。ここで NSURLNSPasteboard からゲットできる。

NSPasteboard *pb = [sender draggingPasteboard];
NSString *bestType = [pb availableTypeFromArray:[NSArray arrayWithObjects: NSURLPboardType, nil]];
if (bestType) {
_myURL = [[NSURL URLFromPasteboard:pb] retain];
[self setImage:[[NSImage alloc] initWithPasteboard:pb]];
return YES;
}


・最後に perFormDragOperation: メッセージが YES を返したら、concludeDragOperation: メッセージが来る。後始末とか?する。
とりあえず MyImageView の見てくれを元に戻そう。

[self setImageFrameStyle:NSImageFrameGrayBezel];


wantsPeriodicDraggingUpdates: が出てこないけど、これは draggingUpdated: が送られてくるタイミングについて YES/NO で値を返すだけ。別に何もしなくても大丈夫みたい。

というわけで、あれこれ試行錯誤しながらなんとかドラッグ&ドロップはできたのだけど、最後に Action: が送られてこない!

ということから「NSImageView からの Action はどこから出てくるのか?」というタイトルになったのだけど、どうなんだろう? MyImageView の Action: の情報をゲットして(どうやって?)、その情報から送り先と selector をゲットしてメッセージを送るって感じ? 良く解らん!

ので、結局は最後の後始末 concludeDragOperation で super さんにそのまま任せてみた。そしたら Action: が飛んでったので結果オーライということで。良いのか?そんな事で!

ん~タブって消えるんだ。リストが見難いな。サンプルのコードを適当にいぢっただけだから、かなり怪しい部分があると思うけど…

テーマ:プログラミング - ジャンル:コンピュータ

片方向の Binding
NSArrayController を使ってテーブルとその詳細を表示するということをやるのはとても簡単。Binding でパッパと繋げば、テーブルで選択されている部分が変わると詳細で表示されている内容も変わる。更に詳細の部分でデータを変更すると、テーブルの中のデータも変更される。Binding 万歳!

でも、今回は詳細の部分はテーブルに合わせて変わってほしいのだけど、詳細部分でデータを変更してもそのデータはテーブルに(オリジナルデータに)反映されたくなかった。そんな場合はどうしたものか? Interface Builder で Binding してしまうと両方向?に変化が伝わる。でも、今回は詳細部分がテーブルの変化を知りたいだけで逆方向は必要ない。そんなの Interface Builder で設定できるの?

結局、悩んでも仕方がないので Interface Builder での Binding を止めて自分で Binding してみた。具体的には NSArrayController に Selection が変わったら教えてくれるよう自分を登録するだけ。

[myArrayController addObserver:self forKeyPath:@"selection" options:NSKeyValueObservingOptionNew context:nil];


これで NSArrayController は選択している部分(Selection)が変わったら、自分の中のメソッド

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

を呼んでくれる。

呼ばれたら NSArrayController から選択されている部分のデータを取り出して、それを詳細部分にセット。これで片方向の Binding?のできあがり。
片方向の Binding が必要になるなんて UI の設計がいけないのだろうけど、ま、手でやればなんとかなったので OK としよう。

ところで、NSArrayController が -(void)observeValueForKeyPath:... を呼んでくれるときに ofObject:(id)object が引数として渡されるのだけど、この objectって NSArrayController の選択されている部分の(selection な)データじゃないの? 単純に NSDictionary をセットしてやってみたんだけど、this class is not key value coding-compliantって怒られた…。
ん?そっか、selection の元?の object が来るのね。[object selectedObjects] で選択されてる objects が取れた。


テーマ:プログラミング - ジャンル:コンピュータ




プロフィール

Author:paraches
Nike+iPod で走ってお腹を…

にけのて ダウンロード

Nike+iPod

温泉旅行

宿・ホテル予約ならじゃらんnet

最近の記事

Zenback

ランキング

人気ブログランキングへ

アクセストレード

バリューコマース

最近のコメント

月別アーカイブ

RSSフィード

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。