MOSA Multi-OS Software Artists

MOSAはソフトウェア開発者を支援します

  • iPhone/iPod touch アプリ紹介
  • MOSA掲示板
  • 活動履歴
  • About MOSA(English)

MOSA Developer News[MOSADeN=モサ伝]第99号

2004-02-03

目次

  • Cocoaでいこう! Macらしく 第37回   Yoshiki(DreamField)
  • 藤本裕之のプログラミング夜話 #38
  • 高橋真人の「プログラミング指南」 第37回
  • ニュース・解説
  • MOSAからのお知らせ

Cocoaでいこう! Macらしく  第37回 Yoshiki(DreamField)

 今回は、再びTinyViewの描画に手を入れます。

無駄な描画をしないようにしよう

 実を言えば、現在のTinyViewは、場合によっては必要無い所まで描画してしまっています。第29回で行った実装を、もう一度見直してみましょう。
MyImageView.mの中の、drawRect:を見て下さい。

- (void)drawRect:(NSRect)rect {
    [ image compositeToPoint:NSZeroPoint operation:NSCompositeSourceOver];
}

 composite系で画像全体を描画しています。ウィンドウ内に画像全体が表示されている場合はこれで良いのですが、画像がウィンドウからはみ出していて、スクロールにより一部を見れる場合はどうでしょう。この場合は、はみ出している部分は描画する必要が無いことになります。しかも、スクロールさせた時には元々表示されていた部分はそのまま使われますので、新しく現れた部分だけ描画すれば良いのです(fig.01)。

[fig.01]一部だけ描画すれば良い例
http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/37/images/fig01.jpg

それなのに常に全て描画するのは無駄だと言えます。では、どの部分を描画すれば良いのでしょうか。実は、drawRect:が呼び出された時に渡って来るrectが、描画を必要とする範囲を示しています。
 rectは、今までも出て来ていましたが、矩形を表す構造体です。どの様に宣言されているのか見てみましょう。Xcodeで、NSRectと書いてある所にマウスカーソルを持って行き、コマンドキーを押しながらダブルクリックしてみて下さい(fig.02)。

[fig.02]NSRectの所で、コマンドキー+ダブルクリック
http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/37/images/fig02.gif

すると宣言されている所にジャンプしたはずです(ジャンプしなかった時は、ビルドしてからもう一度やってみて下さい。)。NSRectは次の様に宣言されています。

typedef struct _NSRect {
    NSPoint origin;
    NSSize size;
} NSRect;

originは原点。sizeは縦横のサイズです。NSPointとNSSizeの宣言はすぐ上にあります。

typedef struct _NSPoint {
    float x;
    float y;
} NSPoint;

typedef struct _NSSize {
    float width;         /* should never be negative */
    float height;        /* should never be negative */
} NSSize;


 この矩形がどの部分を表しているかと言いますと、MyImageViewの座標です。例えば、fig03の様にMyImageViewの一部がウィンドウに表示されていて、その中の赤枠の部分だけ描画が必要な場合、その部分を表すrectが渡って来ます。fig03の例で言えば、originに(628,306)、sizeに(140,457)の値が入ったrectです。

[fig.03]rectで渡って来る値
http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/37/images/fig03.jpg

ここで気をつけて欲しいのは、この座標は画像の座標では無いということです。あくまでMyImageViewの座標ですから、この部分に画像(image)のどの部分を描画すれば良いのかということになります。ですから、正しくはfig04の様になりますね。つまり、imageの赤枠の部分をMyImageViewの赤枠の部分に描画することにより、ウィンドウの赤枠の部分に表示されるわけです。

[fig.04]imageとMyImageViewの関係
http://www.remus.dti.ne.jp/~yoshiki/cocoa/ed1/37/images/fig04.jpg

これを見て気付いたと思いますが、今回はたまたまMyImageViewとimageの座標は等しいです。ですから、同じ値を使って良いことになります。それでは、必要な部分だけを描画するように修正してみましょう。

- (void)drawRect:(NSRect)rect {
    [ image compositeToPoint:rect.origin fromRect:rect operation:NSCompositeSourceOver];
}


 描画しなければならないのは、MyImageViewの中のrectで示された矩形の部分です。今回はimageの座標もMyImageViewと値が同じですから、imageの中のrectで示された部分を、そこに描画すれば良いことになります。そこで、描画先の座標をrect.origin、描画元の矩形をrectにしています。これで必要な部分だけを描画するようになりました。実際にビルドして実行してみて下さい。
 こういった座標に関することは、言葉で書くとややこしくなりますが、具体的に図で見れば単純なことだと分かります。プログラムを組んでいて混乱したら、図に書いてみると良いでしょう。
 ところで、TinyViewを使っていて、動作が奇妙に感じることはありませんか。何か動作が通常のMacのアプリとは違うような。画像を開いてウィンドウを縮めてみて下さい。中身の画像が左下固定になっているのが分かると思います。この動作は人間から見て不自然ですね。通常のMacのアプリだったら、左上が固定のはずです。と言うわけで、Macらしいアプリにするために、次回はここに手を入れて行きます。

(全てのサンプル画像は、ゆきみだいふくさんのご好意により、使用させていただいています。)

藤本裕之のプログラミング夜話 #38

 唐突だが読者の皆さんは郵便局の「転居先転送サービス」というものをご存知であろうか。郵便局に行くとこのサービス専用のハガキというのがあって,これに転居元の住所と転居先の住所,それに転居日を記入して最寄りのポストに投函すれば,そこに書いた転居の日から1年間,旧住所宛に届いた郵便物を(銀行などから来る「転送不要」と朱書きされているヤツは別)新住所に転送してもらえる,というものだ。
 数年前突如逆上してマンションを購入,次にこのサービスを利用するのはローン返済不能になって夜逃げするときくらいであろう私が言うのもナンだがこれは実に便利な制度であって,その効用たるやこれをもう一度利用するために不肖フジモトココロの奥深くでナニゴトも経験だから一回くらいは夜逃げも悪くないかなと想像したりするくらいのモノなんである(もちろん嘘です)。
 だいたい皆さんもこの原稿をメールで読んでいるくらいだから,日常的な交際・連絡などにアナログ郵便(……と呼ぶべきなのかな,「郵政省メール」と言う呼び方はもう正確ぢゃないらしいからな)を使うということは少ないと思う。私など,年賀状を除けばプライベートな郵便物,すなわち宛名や中身に少しでも手書きの文字が存在する郵便物を受け取ること自体稀である。いや,オレも今年は自分の年賀状に手書きの文字を入れられませんでした,すいません。

 とにかく,その唯一の例外と言ってよかろう(賀状に先立つ「喪中のはがき」などもこの範疇に入れていいと思う)年賀状のヤリトリは当たり前だけど年に一回である。つまりですね,「年賀状による年一回の住所通知」と「転居先転送サービスの期間が1年間」というのは,当初そういう考慮のもとに実施されたわけではないかもしれぬが相互に補完し合って「知人の間の相互連絡ネットワーク」を維持している見事なシステムなんである。
 具体的にみようか。ここに,MOSAの理事にも似た名前のヒトがいるけど全く架空の存在であるところのコイケさんというヒトがいて,昨年の6月に引っ越しをしたとする。忙しいので転居通知メールなど出せない。そこでフト,これまたこの原稿を書いているフジモトには全く関係のない架空の存在である友人フジモトが飲み会でほざいていた言を思い出し,「転居先転送サービス」の申し込みだけを行った。
 かくして今年の正月,彼のところには旧住所宛に出された年賀状が配達される。また,今年自分で出した年賀状には当然ながら新しい住所を書いてあるので,来年以降もモノゴトが円滑に進むであろうと期待できる。静かな正月,コタツでミカンなど剥きながらコイケさんはああ便利な世の中だなあと思うのである。

 まぁもちろん,コイケさんがまたしても似ている名前の理事はいるけれども金輪際無関係の架空の存在であるタナカ君とのつきあいはこれきりにしようと今年は年賀状を出さなかったり,逆にこれまた(以下略)のタカハシさんが昨年くれた年賀状の住所が変わっているのに気づかずにいて2年続けて旧住所宛に年賀状を出したりすれば,このシステムによる相互連絡は破綻するわけだが,それはまぁマニュアルに沿ってない使い方というか人為による破綻なのでしかたがない。
 そうした人為的なものは別としてこの「連絡維持システム」が崩壊する可能性というのはあるだろうかと考えたとき,ワタシはこのシステムの巧緻にほとんど絶句するくらい感動したのである。
 ……すなわち,通知サービスを申し込み,転居日から1年以内であるにも関わらず転送が行われないというという事態は,「転居したその日にその日を転居日として申し込みはがきを投函し,その申し込みはがきが集配されて局に着き処理される以前に旧住所宛の郵便物が配達に回った場合」に出来すると考えられる。
 ところが,「年に一回の住所通知」である年賀状が配達される1月1日は,おそらくは「1年中で一番引っ越しの少ない日」であるのである。ああ,すべからくシステムというのはこのように構築されるべきである。そう思いませんか?
 ところで,私がなんでこんなことに思いを巡らせたかと言えば,今年出した年賀状が実に5枚も宛先不明で戻って来たからである。MOSA関係者は一人もいないので,「これを読んでいたら連絡をくれ」と書いても虚しいが,キサマらは「転送サービス」くらい使いやがれよな,と虚空に悪態をつかせていただいてまた次回。おそまつ。
(2004_01_27)

高橋真人の「プログラミング指南」第37回

オブジェクト指向のとっかかり(23)

 こんにちは、高橋真人です。早速、続きに入りましょう。
 続いてのコードは、以下のようになっています。

ifstream ifs(targetFile.c_str());
if (not ifs) {
    abort();
}

 ifstreamというのは、ファイルからデータを読み出すためのクラスです。input file streamの略だと考えると分かりやすいでしょう。streamというのは日本語にすると「小川」とか「流れ」といった意味になりますが、ファイルのI/O(入出力)においてはデータを読み書きするために使われる仕組みです。
 ANSI Cのライブラリの例ですとfread()やfwrite()などの関数が、ある程度の分量のデータをまとめてドサッと読み書きするに対して、fgetc()やfputc()などは、小さな単位のデータを片っ端から順々に流していく形で読み書きしていきますが、これがストリーム方式です。printf()などの関数もこの分類に入れていいのでしょう。
 MacのToolboxにはストリーム方式はなく、ブロック単位での読み書きのみでしたが、PowerPlantなどのフレームワークが独自にストリーム方式を提供していたりしました。(LFileStreamなど)
 Mac OS Xの場合、Carbonには未だストリームはないようですが、Cocoaの方には辛うじてPantherから用意されたようです。(NSStreamなど)
 まあ、ファイルの読み書き程度であればストリームを使えないからといって特段不便なこともないでしょうが、ネットワークを経由してのデータの送受信ということになるとストリームを使えた方が便利になるケースも多いように思います。
 さて、CはUNIX環境から生まれた言語ですから、データのやりとりの対象を基本的にファイルとして扱います。よって、FILE構造体へのポインタとして標準の入出力(stdout、strin)も使えます。Cの拡張によって作られたC++の場合、ストリームはクラスとして実現されています。
 皆さんおなじみのHello worldですが、Cにおいては、

printf("Hello world! n");

と書きますが、C++の場合は、

cout << "Hello world n";

となります。C++ではちょっと事情があって、ストリームへのデータ書き出しのためにビットシフト演算子である << を多重定義して使っています。すなわち、output streamと任意の型とでこの演算子を挟んで記述すると、データの書き出しが行われるというわけです。何でこんな奇妙なこ演算子の使い方をするのかを知りたい方は、「プログラミング言語C++第3版」
http://www.ascii.co.jp/books/detail/4-7561/4-7561-1895-X.html 
あたりを読んでみてください。
 ちなみにCのprintf()の場合、書き出すデータの型によって、正しく%dや%sなどの変換指定子を対応させてやらないととんでもないエラーになったりしますが、C++のこの方法では演算子のオーバーロードの仕組みがちゃんと対象の型を認識してよきにはからってくれますから、この手の気づかいは必要ありません。例を上げれば、こんな感じです。

int n = 10;
char *str = "Hello world";
char c = 'a';
cout << str << n << c;

書き出す順番に、どんどん << を使ってつなげていけばいいのです。
 さて、ifstreamは、コンストラクタに文字列を与えると、それをファイルのパスと解釈してファイルをオープンしてくれます(stringは、c_str()というメンバ関数を使うと、内部に保持している文字列をC文字列として返します)。従って、ここではカレントのユーザーのデスクトップにある"text.txt" という名のファイルが開かれることになります。
 ファイルのオープンと言えば、当然次は「ちゃんと開けたかどうかの確認」に入るわけですが、いきなり不思議な表現が出てきます。
 まず、notというのはC++において別名定義された ! 記号であり、意味は全く同じです。ただ、ソースの中でとかく埋もれて見えにくくなりがちな ! よりも認識率が高いので私は常用しています。このnotで、ifsを打ち消しているわけですが、ifsを単独で記述すると、「ストリームがオープンに成功していて、書き込む準備ができているときに真を返す」ということになっていますから、通して考えれば、ファイルのオープンに失敗した場合に、if文の中身が実行されることになるわけです。
 まあ、Cにおける

FILE *fp = fopen(filename, "r");
if (!fp) {

という表現と極めて近い書き方だと思ってくだされば十分です。
 そして、ファイルのオープンが失敗した場合にabort()、すなわちプログラムを強制終了、という手順になります。

ニュース・解説

 今週の解説担当:小池邦人

Carbon ドキュメント & サンプル & SDK ナビゲーション(2003/01/30)

【開発環境】

Metrowerks CodeWarrior v9.1をMac OS X 10.3の環境で利用すると、AltiVec関連のFrameworkが正しくリンク出来ないというバグ(だと思う)が存在することは以前に紹介しました。それを改善したv9.2の登場を心待ちにしているのですが、なかなか登場しません。加えてInterface Builderにも、古いNibファイルをオープンすると、Tabコントロール内に配置したオブジェクトが少しずつ下方へ移動してしまうバグがあります。残念ながら、こちらの修正バージョンも現れません。おかげで私の知り合いは、わざわざMac OS X 10.2環境をインストールしてNibファイルの作成とプログラミング開発を続けています。

そう言えば、Xcode v1.1にチャレンジしたのだが、諸々の問題のためProject Builderへ帰っていった人もいましたね(笑)。開発環境を含め、仕事に直接利用しているアプリケーションに致命的なバグがあるのは非常に困ります。楽器演奏を仕事にしている人のバイオリンのネックが折れているようなものでして、「仕事にならない!」というのが本音でしょう(でも、何とかしているのが現実ですが...)まあ、バイオリンならば、修理に出したり買い換えたりといくつかの対策がありますが、こちらに限ってはメーカ側の修正をひたすら待つしかないというのが...実に寂しい2004年の冬なのです(涙)。

【テクニカルドキュメント】

前回から1月30日の期間中、Apple社のDeveloperサイトにはドキュメントがひとつも登録されませんでした。ただし、デベロッパ向けの読み物として2つの内容が追加登録されています。最初の方は、CHUD(Computer Hardware Understanding Development)に含まれる「Shark」というパフォーマンス・ツール(プロファイラ)についての記事です。興味のある方は印刷して保存されておくと良いでしょう。こうしたデベロッパ向け記事についても日本語訳が欲しいところです。

「Optimizing with Shark: Big Payoff, Small Effort」

http://developer.apple.com/tools/shark_optimize.html

「Mac OS X Makes It Easy to Add Competitive Application Features」

http://developer.apple.com/business/macmarket/barebones.html

1月30日までに新規テクニカルノートはひとつも登録されませんでしたが、テクニカルQ&Aの方は5つ登録されました。いくつかのQ&Aには日本語訳もありますが、内容は古いままです。英語バージョンの方のみが再登録となりますので注意してください。

QA1332 「Shearing a Coordinate Space with NSAffineTransform」
QA1149 「DV Codec settings and performance」(日本語)
QA1328 「Server Processes and the Dock」
QA1087 「Issues with boot time KEXT loading」(日本語)
QA1330 「Music Player Sequence Destinations」

http://developer.apple.com/qa/

【サンプルソースコード】

前回から1月30日の期間中、Apple社のSample Codeサイトには4つのサンプルソースコードが登録されました。「AddNibToNav」サンプルは、Navigationサービス・ダイアログのカスタムエリアに、Nibファイルから読み込んだユーザインターフェースを追加する仕組みを紹介しています。今までは、リソースファイルからDITLリソースを読み込んで実現していた機能です。

「Verification」(DiscRecording関連)
「ElectricImageComponent」(QuickTime関連)
「AudioBurn」(DiscRecording関連)
「AddNibToNav」(HIToolbox関連)

http://developer.apple.com/samplecode/

【デベロップメント SDK】

前回から1月30日の期間中、Apple社のDeveloperサイトに登録されたデベロップメントSDKは「Kernel Debug Kit」の最新版だけです。また、ToolsサイトにCHUDの最新版 v3.0.4が登録されています。

「Kernel Debug Kit 10.3.2」

http://developer.apple.com/sdk/

「Computer Hardware Understanding Development Tools 3.0.4」

http://developer.apple.com/tools/performance/

MOSAからのお知らせと編集後記は割愛します

MOSA Developer News   略称[MOSADeN=モサ伝]
Apple、Mac OSは米国アップルコンピュータ社の登録商標です。またそのほかの各製品名等はそれぞれ各社の商標ならびに登録商標です。
このメールの再配信、および掲載された記事の無断転載を禁じます。
http://www.mosa.gr.jp/
Copyright (C)2004-2006 MOSA. All rights reserved.