Yoshiki(DreamField)前回までで、パネルを開いた時に、メインウィンドウのイメージの横幅と縦幅を表示するようになりました。今回は、パネルを開いた後にメインウィンドウが切り替わった時の処理を実装します。パネルを表示しよう(その8)メインウィンドウが切り替わった時は、パネルに表示している内容も、そのメインウィンドウのイメージの横幅と縦幅に切り替えなければなりません。これをどうやって実現すれば良いでしょうか。今まで組んだプログラムを思い出してみましょう。MyDocument.mを見てください。メインウィンドウが切り替わった時には、windowDidBecomeMain:が呼び出されるのでした。この中では全員が共通で使うimageInfoクラスのインスタンスに情報をセットしています。このセットした情報をパネルに反映させるには、どうすれば良かったでしょうか。InfopanelController.mを見て下さい。この中の、updateImageInfoが呼び出されれば、パネルに反映されるのでした。MyDocument.mのwindowDidBecomeMain:の中で情報をセットした後に、updateImageInfoメッセージをInfopanelControllerクラスのインスタンスに投げるようにすれば良いわけです。これは可能でしょうか。メッセージを投げるためには、そのインスタンスのアドレスが分かっていなければなりません。InfoPanelControllerクラスのインスタンスを生成するのは、AppController.mの中の、showInfoPanel:でした。これを見ると、インスタンス変数であるinfoPanelControllerにそのアドレスを格納しています。AppControllerクラスのインスタンスに教えてもらえば、アドレスを取得することはできそうです。パネルは最初から表示されているわけでは無いのです。表示するまでインスタンスは生成されませんから、メッセージは送れません。これも判断するようにして・・・。何だかとても複雑になってしまいそうですね。この様な処理を単純にできる、とても便利な方法があります。それは、NSNotificationCenterを使うという方法です。NSNotificationCenterクラスのインスタンスは、通知の仲介をしてくれます。何か通知を行いたい人は、受け取る人が誰であるか気にする必要はありませんし、受け取る人が存在しているのかどうかさえ考える必要もありません。NSNotificationCenterに通知を投げるだけです。通知を受け取りたい人は、通知を投げる人のことを知る必要はありません。受け取りたい旨をNSNotificationCenterに登録しておくだけで、通知が来た時に受け取ることができます。この時、特定のメッセージだけ受けたいという指定もできますし、特定の人から来たメッセージだけ受けたいという指定も可能です。ところで、CodeWarriorでPowerPlantを使っていた方は、LBroadcasterとLListenerを思い浮かべるかもしれません。こちらは、メッセージを投げる人に投げられる人を登録し、メッセージを投げる方は誰に投げているのかを意識をしないですむという仕組みです。両者を比べると、NSNotificationCenterの方がずっと結合が粗であることが分かります(LBroadcasterとLListenerは、元々はボタンやメニュー等、コントロールの操作をメッセージのやり取りで実現するためのものですから、そもそも目的が違います。まともにオブジェクト指向で組めないC++で、まともにオブジェクト指向で組みたいがために考え出された仕組みなんですね)。それでは、NSNotificationCenterの詳しい説明はreferenceや入門書を読んでもらうこととして、ここでは実際にプログラムを組んで行きましょう。ImageInfo.mに、次のメソッドを実装してください。このメソッドは、ImageInfoの内容に変化があったことを通知します。object:self];}NSNotificationCenterクラスのインスタンスは、生成することもできますが、あらかじめタスクに一つ用意されています。通常はそれを使います。NSNotificationCenterクラスにdefaultCenterメッセージを投げると、その用意されているインスタンスを返してくれます。それに対してpostNotificationName:object:メッセージを投げることにより、通知を行っています。引数は通知の名前を示すNSStringクラスのオブジェクト、第二引数は、実は何でも良いのですが、通常は通知を行うオブジェクト(つまり自分自身)を指定します。通知の名前は直接文字列を書いていません。インプリメント部よりも上に次の一行を入れてください。@"TNVWImageInfoChangedNotification";そしてImageInfo.hのインターフェース部よりも上に、extern宣言を入れて下さい。*TNVWImageInfoChangedNotification;この様に宣言して、通知を受け取る方でもTNVWImageInfoChangedNotificationを使うようすれば、打ち間違えてもビルド時にエラーになるので、すぐに分かります。文字列を指定すると、これが分からず苦労することになります。あとは、メソッドの宣言にchangeも加えておいてください。#43このところちと忙しくてネタを仕込んでいるヒマがないので素材ムキ出し気味の話で失礼したい。Anderson氏のアドバイスで解決、目からウロコが3枚くらい落ちた。ことはあるダイアログボックスを巡るコードで起きた。InterfaceBuilder(以下IBと省略)でテキストの入力域(NSTextField)とボタン(NSButton)が1個ずつあるダイアログを作り、NSObjectをサブクラスしてこれのコントローラを作った(NSControllerを使わないのはJAGUARでも動作させたいから)。DoItButton)を定義、インスタンシエイトし、それぞれダイアログそのもの、入力域、ボタンと連結する。ソースファイルをジェネレイトして、controlTextDidChange:をオーバーライド、TextToDoの中身が空っぽだったらDoItButtonを選択不能にするコードを書いた......。ここまでは何の問題もなかった。意図した通りに動いてたのね。ところがここに「メイン・ウィンドウへ文字列をドラッグ&ドロップされたら、このダイアログを出し、その文字列をTextToDoにセットしたい」という要求が出て来たのね。メイン・ウィンドウの方にそういうコードを書き、ダイアログのコントローラに外から文字列をセットするためのメソッドを追加した。「setTextToDo:」という名前の以下のようなコード......。controlTextDidChange:nil];}これが苦闘の始まり。最初に気づいたのはもちろん、このセットが正しく行われないこと。文字列をドラッグ&ドロップするとちゃんとダイアログは出るんだが、そこで終わり、何も起こらない。次に気がついたのは、開いたダイアログのTextToDoにキーボードから文字を入力しても「DoItButton」が選択可能にならないこと......。調べるウチ、どうもTextToDoというOutletがヘンであることが判明した。このコントローラのawakeFromNib:にデバッグ文を入れてこのObjectのアドレスを確認すると、なんとこいつがゼロだったのだ。initWithCoder:(Nibファイルの中身からObjectを生成する時にCallされる)の次に送られるメッセージである。ここでこいつのアドレスがゼロなら、そりゃこのObjectに対するメッセージは全部機能しないに決まってる。試しにもう一つNSTextFieldをダイアログに追加し、そいつのアドレスもプリントするとそっちはマトモ。と今までの領域を消し、そいつを改めてコントローラのOutletに繋ぐ......と、またゼロになってしまうではないか。なっとるのだ?ここまで調べ、途方に暮れてMLに質問した。Fritzの出してくれた回答はスーパーなもんだった。呼ばれてOutletをゼロにしちゃってんだよ」と。NSLog()を入れてみると果たしてその通り。前にこいつが呼ばれてた。慌ててawakeFromNib:のドキュメントを読むとなるほどこんな意味のことが書いてある。「initWithCoderはIBで定義できる以上の特別な設定を可能にするため、Outletに連結されたインスタンスをロードする前にその名前にsetがついた「setVariable:」を探し、もしあればこれをCALLする。なければインスタンスを探す......」いや、以前一度これを読んだんだが、そんときは具体的なイメージが湧かなかったので読み流しちゃたんだよね。オレがいままでこのケースに捕まらなかったのは、(意識してなかったんだから当然ながら)偶然Outlet名そのままにsetをつけたメソッドを定義しなかったからつうことになるぢゃないか。目から湧き出るウロコをぬぐいつつ、ちと背筋が寒くなった春4月でありました。(2004_04_08)高橋真人の「プログラミング指南」第42回オブジェクト指向のとっかかり(28)こんにちは、高橋真人です。前回で一通りの説明を終えたプログラムの例ですが、それに手を加えて少しだけ実用的なものに改造していきます。「少しだけ」なのかというと、一度に大幅に変更してしまうと理解しづらくなってしまう(特に今までのものとの関連性が見えなくなってしまう)からです。オブジェクト指向で書かれた実用的なプログラムソースコードのサンプルであれば、今の時代インターネットでいくらでも入手可能ですから、ここはあえて「プログラミング指南」の原点に戻って、ゆっくりと時に冗長なぐらいに説明を展開していくという方向で行きましょう。改良したプログラムは以下のようになります。inTC->content;}例によって、解説は次回からです。ナビゲーション(2004/04/09)【開発環境】Apple社からはWWDC2004に関する色々な情報が提供されています。カンファレンスセッションに関する詳細ですが、その日本語訳が以下のサイトに登録されました。http://developer.apple.com/ja/wwdc/descriptions/私としては、ちゃんとCarbon関連のセッションもあり一安心しています(笑)。デジタルメディア」の7つに分かれています。セッションのタイトルと内容を見ていただくと理解できると思いますが、バリバリのプログラマでない方にもアピールできるようなセッションが数多く用意されています。最近のWWDCは、プログラマの祭典から、多種多様のユーザやデベロッパを対象にしたカンファレンスへと変貌したことがよく理解できます。Workshopsと名付けられた事前ワークショップが開催されます。Code」という5つのコースが用意されています。Xのプログラミング環境にチャレンジしようとされている方は、前日からこのワークショップに参加されるのが近道かもしれません。詳細については以下のサイトをご覧ください。http://developer.apple.com/wwdc/preconference.htmlまた、WWDCと同時に開催される各種イベントについても詳細が載っています。Fair」(サードパーティの展示会)についての詳細は、それぞれ以下のサイトを参照してください。http://developer.apple.com/wwdc/ada.htmlhttp://developer.apple.com/wwdc/exhibits.html今年も映画上映とApple本社でのパーティは開催されるようです(笑)。現時点では、日本からのツアーに関して公式サイトでの紹介はありませんが、こちらも近々発表されると思われます。WWDC2004の参加費用の早期割引は4月30日までですので、参加を予定されている方は忘れないように登録いたしましょう。WWDC2004に関するQ&Aの日本語訳は、以下のサイトにまとめられています。前回から4月9日の期間中、Apple社のDeveloperサイトにはドキュメントが7つ登録されました。Dialogs」のそれぞれの内容については、先週号の新居さんの記事を参照してください。Guide」http://developer.apple.com/documentation/index-rev-date.htmlまた、デベロッパ向けの読み物としてXgridについての解説が登録されています。Us」(読み物)http://developer.apple.com/hardware/hpc/xgrid_intro.html前回から4月9日の期間中、新規テクニカルノートはひとつも登録されませんでしたが、テクニカルQ&Aの方は6つ登録されました。Grabber」(映像やサウンドの取り込みに利用するコンポーネント)に関する内容が2つ含まれています。Codeサイトにはサンプルソースコードが8つ登録されました。久しぶりにサンプルソースコードの復活です(笑)。このうちの7つがOpenGLに関連したサンプルです。サンプル内容は再録に近いのですが、すべて新しく書き換えられています。Graphics」「AGL」「GLUT」という3つのライブラリのどれかを使い、CarbonやCocoaのウィンドウやユーザインターフェースと連動させる方法が解説されている良質のサンプルです。Graphics」「AGL」「GLUT」の使い分けが必要な時にはぜひ参考にしてみてください。「FSCopyObject」の方は再録で、いくつかのバグフィックスがなされているようです。前回から4月9日の期間中、Apple社のSDKサイトにはひとつもSDKが登録されませんでした。OSは米国アップルコンピュータ社の登録商標です。そのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。このメールの再配信、および掲載された記事の無断転載を禁じます。Artistsアクセスリンクについて個人情報の取り扱いについて支援のお願いお問い合せこのサイトに掲載されている文章、画像を含む一切のデータの無断転載を禁止します。