MOSA Developer News[MOSADeN=モサ伝]第277号
2007-11−27
目次
- 藤本裕之のプログラミング夜話 #127
- 高橋真人の「プログラミング指南」 第125回
- 速報 MOSA Software Meeting 2007
藤本裕之のプログラミング夜話 #127
■
これを書いているのは11月24日、つまりいまごろMSM(MOSA SoftwareMeeting)の真っ最中なんだが、ワタシは家で原稿書きをしているのである(このあと別件……プログラムには全然関係ない原稿だけど、をもう1本書かねばならないのだ)。思い起こせば今年2007年、正月からWebアプリとかファイルメーカーとか翻訳とかで、一件も「Macのプログラミング」と呼べる仕事をしてない。昨年末に作ったシェアウエアの xTrailer というののソースをいじくりまわしたりしてCocoaを使ってる他、Xcodeを起動するのはこの原稿を書くときだけだ。……なんか禁断症状が出そうである。
とはいえ承前。デフォルトでは NSDocument にしかない「printDocument:」しか送ってこないシステムのツールバーアイテム、NSToolbarPrintItemIdentifier に、NSTextView の「print:」を送らせようというタクラミの「正攻法」の方を紹介する。前回書いたようにこれはNSToolbarPrintItemIdentifier のドキュメントに書かれている方法(ちょっと説明が具体的でないので分かりづらいんだが)。
NSToolbar のデリゲート・メソッドに「toolbarWillAddItem:」というのがある。読んで字のごとく、「ツールバーにアイテムが足されるぞ」ということを知らせてくれるメソッドだ。要はこいつを使ってNSToolbarPrintItemIdentifier が追加されるところをつかまえ、その中身、具体的にはそのアクションを書き換えちまえばいい、ということである。我らが MyApplication は既に作成したツールバーのデリゲートになってる(つうか、なってないとここまでの説明は全部動かない)ので、あとは以下のようにこのデリゲート・メソッドをインプリメントする。
- (void) toolbarWillAddItem:(NSNotification*)notification {
NSToolbarItem* item = [[notification userInfo] objectForKey:@"item"];
if([[item itemIdentifier] isEqualToString:NSToolbarPrintItemIdentifier] == YES){
[item setAction:@selector(print:)];
}
}
注意しなければならないのは目当てのツールバーアイテムが notificationの object ではなく(ここには「アイテムを足される側のツールバー」が入ってくる)、userInfo の方に入ってくること。リストでは1行で書いちゃっているが、この userInfo は NSDictionary であり、@”item” というキーを使って追加されるアイテムにアクセスする。アイテムをつかまえたら、そいつのitemIdentifier が間違いなく NSToolbarPrintItemIdentifier であることを確かめて(当然だが他のアイテム、たとば最初に作った「Cat」が足されるときにもこのメッセージは飛んでくる)から、setAction: でそのアクションを書き換える。
ツールバーに足された NSToolbarPrintItemIdentifier のアイコンがアクティブにならなかったのはそのターゲットである firstResponder にprintDocument: というメソッドがなかったからなので、これでめでたくアイコンはアクティブになり印刷ができるようになるわけだ。
この仕掛けはなにもこのためだけにあるのではなく、状況に応じてアイコンの形状を変えるなどいろいろなことに使える。たとえば何か他のところの設定で「Cat」のアイコを別のネコの写真に替えるとかね(何の意味があるのかわからないが)。
ところで上のデリゲート・メソッドをインプリメントする際、MyApplication.h の方にこのメソッドの宣言をする必要はない(これは前にインプリメントした他のデリゲート・メソッドも同じ)。が、オレとしてはインプリメントしてるデリゲート・メソッドとしてないヤツをヘッダーファイルで確認できるように、書いたものはちゃんとヘッダーで宣言しておくことをお勧めしたい。でっかいアプリになるとソースを検索するよりヘッダーだけを検索する方がなんぼか速いし、他の人が見る可能性があるソースではそういう整合性がとれているほうが親切だから。
ほんぢゃ次回は、ウインドウをリサイズして小さくしたときに見えなくなってしまう「Align Text」のメニューを、それでも選べるようにする、というところを説明したい。それが終わったら、次のネタを仕込むためにオレもLeopard の新しい Xcode をいじくりまわさなくちゃ。……時間があるかなぁ。
(2007_11_24)
高橋真人の「プログラミング指南」第125回
プログラマのためのオブジェクト指向再入門(33)
〜XcodeによるPowerPlant X入門(16)〜
こんにちは、高橋真人です。
さて、PPxによるCarbonイベントのハンドリングでメニューの処理についてを一通り解説しましたので、ここからは、PPxのもう一つの主要機能であるViewについて解説します。
Carbonプログラマならおなじみのように、「モダンな」CarbonにおいてはHIViewというものを使います。HIViewは、旧来のMac OSにおけるControlを発展させた仕組みです。
HIViewを指すHIViewRefは、Controlを指すControlRefと同一視することができるようになっているため、ControlとHIViewを同じものとしてコードを書くことができるようになっています。
しかしながら、HIViewの描画モデルはCocoaのview(NSView)と共通になっており、Quartzを使って描画を行うので座標系などQuickDrawと違うところには注意が必要です。
さて、HIViewの特徴として、オブジェクト指向ライクな使い方ができるというのがあります。これはつまり既存のHIViewを「継承」して、新たなView(つまり、Custom View)を作り出すことができるということです。
しかし、Custom Viewを作り出すために必要となるコードは決して単純ではありません。アップルの解説文書によれば、以下の手順に従う必要があるとされています。
1. HIObjectのサブクラスを登録する
2. Viewに対するイベントのハンドラを作成する
3. HIObjectイベントのハンドラを作成する
4. Viewのインスタンスを作成する
1と3にあるHIObjectというのがポイントです。HIViewはオブジェクト指向的なデザインで設計されている仕組みですが、あくまでAPIはC向けであるため、C++のオブジェクト指向機能を使えません。そこで、この辺の部分を吸収するためにこのHIObjectというのが必要となっているわけです。しかし残念ながら少しバラバラ感というかまとまりを欠く印象があることは否めません。
そこでPPxでは、これらをクラスでくるむことでまとまりを持たせています。
さて、それでは実際にPPxの方を見ていくことにしましょう。
PPxでHIViewを表現するための大元になるのは、PPx::Viewというクラスです。
ところで、ちょっと横道にそれますが、このPPx::Viewという表記はもう大丈夫ですか? これは、PPxという名前空間(namespace)に存在するViewという名のクラスという意味です。自信のない方は過去の記事を確認してみてください。
で、このPPx::Viewというクラスですが、このクラス自体のインスタンスを生成するようには設計されていません。あくまでこのクラスを継承して使うのが、このクラスの正しい使い方ということです。
クラス自体のインスタンスを生成しないというと、「それは抽象クラスなのか」と思われる方もおいでと思いますので、少し説明します。
PPx::Viewのクラス定義部(PPxView.h)を見ると、どこにも純粋仮想関数は見当たりません。事実、PPx::Viewは抽象クラスではありません。では、PPxの「PPx::Viewからインスタンスは作らない」という設計方針はどのように達成されるのでしょうか?
C++では、抽象クラスとして定義する以外に、コンストラクタをpublicにしないことで、インスタンス化を防ぐことができるのです。
PPx::Viewクラスの定義を見てみますと、View()という関数がprotectedになっているのが分かると思います。これにより、PPx::Viewはそれを継承したクラスからしかコンストラクタを呼べない、つまり生成ができないということになります。
ちなみに、クラス定義の中に、View(const View&)という関数がprivateとして定義されていることに気づかれた方もいるかもしれません。これは、コンストラクタではありますが、コピーコンストラクタと呼ばれる特別なコンストラクタで、引数として同じクラスの他のインスタンスをとる形のものです。クラスの値がコピーされる時に暗黙的に呼び出されるコンストラクタであることから、ケースとなることからこの名前があります。
あと、そのすぐ下に定義されている
View& operator = ( const View& );
というのも、似たような役割を持つもので、これは代入演算子をPPx::Viewクラスに特化した形で個別に定義(演算子のオーバーロード)してあるものです。
これらのコピー機能を持った関数がprivateにされることで、PPx::Viewはコピーができないものになります。
話を本題に戻します。
PPx::Viewはサブクラス化される形で使われるものになっていますので、PPxがあらかじめ定義している様々なクラスでは、ほとんどがこのクラスを継承した形になっています。
では、皆さんが独自にViewを定義する場合にもPPx::Viewをサブクラス化して使えばいいのでしょうか?
もちろん、それも可能です。しかし、その場合、前に述べたHIViewの構築関係の関数、つまりHIObjectイベントのハンドラなども自分で面倒を見なければならなくなります。それは面倒ですよね。
そこで、PPxでは、PPx::BaseViewというクラスが用意されています。このクラスが、HIViewの複雑な部分をまとめて面倒見てくれますので、私たちはこのクラスを継承して新たなViewのクラスを起こし、必要な部分だけを書き足して行けばよい形になっているのです。
次回は、BaseViewの実際の使い方の解説に入って行きます。
速報 MOSA Software Meeting 2007
報告担当:高橋政明
11月23・24日に開催されましたMOSA Software Meeting 2007は無事終了しました。写真を含めた報告ページはMOSAのWebサイトに掲載予定ですが、速報をお届けします。
今年はこれまでと会場を変更し東京都内の大橋会館(東京都目黒区/東急田園都市線「池尻大橋」より徒歩5分)で開催しました。会場を都内に変更した事に伴いスケジュールも変更しこれまで初日は午後スタートでしたが今年は午前スタートになりました。交通の便が良いため一日だけの参加も便利になりました。
今回は一日だけ参加の方も合わせて100名以上のお申し込みをいただきました。また学生さんの参加も7名ありました(うちMozilla Japan招待学生2名)。どちらもMSM史上はじめてです。参加者の最年少はなんと高校生です。
配布された資料をご紹介すると
・配布資料バインダー
セッション別のレジュメ
Mozilla Firefoxシール、Intelロゴ付きネームタグ、インテゴロゴボールペン
CrossOver Mac(MacFan2007年8月号別刷)
IDforWebLiFE*(非売品の冊子)
セッション関連および法人会員各社カタログ資料
・電子マネーEdyとFelica技術知っておきたい31の基本(非売品の冊子)以上は参加者全員に配布されました。
セッションは予定通り滞りなく開催されました。
http://www.mosa.gr.jp/?p=1298&page=2
すっかり恒例になりました大谷さんのキーノートセッションは「ソフトウェア・アーティスト」をキーワードにテンポ良く展開され、我々受講者に発見と示唆を与えてくれるものでした。
上記セッションページには未掲載ですが、二日目のお昼休みに三社(VMware
Fusion・CrossOver Mac・Parallels Desktop for Mac)競演の仮想環境デモが実施されました。実際の動きを見ながら活発な質疑応答が繰り広げられました。
全員配布のグッズだけではなく懇親パーティのお楽しみ抽選会にもたくさんの景品をいただきました。ご提供いただいた皆様にはこの場を借りて御礼申し上げます。ありがとうございました。
講師の皆様ご協力いただきありがとうございました。参加された皆さんお疲れさまでした。おかげ様で会場を変更し例年とは少々異なったMSMでしたが成功のうちに終了しました事をお礼かたがたご報告致します。
◇「りんご味Ruby」は都合によりお休みします。◇
◇MOSAからのお知らせと編集後記は割愛します◇
配信停止 mailto:mosaden-ml@mosa.gr.jp
記事内容に関するご意見 mailto:mosaden-toukou@mosa.gr.jp
記事投稿受付 http://www.mosa.gr.jp/?page_id=850
Apple、Mac OSは米国アップル社の登録商標です。またそのほかの各製品名等
はそれぞれ各社の商標ならびに登録商標です。
このメールの再配信、および掲載された記事の無断転載を禁じます。
特定非営利活動法人MOSA http://www.mosa.gr.jp/
Copyright (C)2007 MOSA. All rights reserved.