|
Backnumber May, 2006 April, 2006 March, 2006 February, 2006 January, 2006 December, 2005 November, 2005 October, 2005 September, 2005 August, 2005 July, 2005 June, 2005 May, 2005 April, 2005 March, 2005 Feburary, 2005 January, 2005 December, 2004 November, 2004 October, 2004 September, 2004 Augsut, 2004 July, 2004 June, 2004 May, 2004 April, 2004 March, 2004 February, 2004 January, 2004 December, 2003 November, 2003 October, 2003 September, 2003 August, 2003 |
- HMDT archive-
|
|
はじめてのブラウザのつくり方 10.3を更新。ステータステキストを Cocoa バインディングを使って表示するだ。 Cocoa バインディングを使うと、ほんとアプリケーションの作り方が、がらっと変わるね。 追記:プロジェクトのイメージから、一部ファイルが抜けているという、どうしようもない致命的なミスを犯していたので、アップし直しました。ごめんなさい。 |
|
XO さんの、Cocoa バインディングが分かりにくいワケに突っ込んでみる。長いので、こちらで。
「監視」という名前から、ポーリングのような処理を想像する?おっしゃるとおり、中身は「通知」です。Apple の KVO のドキュメントでも、真っ先に NSNotification との比較がされてるしね(What is Key-Value Observing)。NSNotification との違いは、NSNotificationCenter を経由するか、一対一の関係か、というところでしょう。
Controller Key っていうのは、ビューからコントローラに KVC でアクセスするための、プロパティです。つまり、このキーを使って、コントローラに valueForKey: でアクセスするわけ。KVC の名前規約(Accessor Search Implementations Details)によれば、始めはインスタンス変数にトライして、そこになければアクセッサメソッドを探す。コントローラで使われることになるキーの多くは、インスタンス変数に対応していない。つまりこれは、名前を指定したメソッドの呼び出しです。Interface Builder の Controller Key コンボボックスに出てくるのは、NSObjectController や NSArrayController のメソッドの名前です。 では、このメソッドを呼ぶと何が返ってくるか?モデルが返ってくるんですよ。Controller Key ってのは、コントローラからモデルを取得するためのキーです。ただし、コントローラが管理しているモデルは 1 つではない。動的に変わることもある。さらに、コントローラはモデルの「選択」もサポートしている。これらのどれを取得するかを決定するのが、Controller Key です。 ちなみに、Controller の状態を取得するためのキーもある。canAdd とか。これはモデルは返さないっす。
Model Key Path の場合は、valueForKeyPath: を使って、モデルのプロパティにアクセスするんですな。キー・パスの利点は、関連をたどることができること。たとえば、バインディングの Bind to には、コントローラ以外にも File's Owner を指定することもできる。この場合、Controller Key は使えなくなるんで、Model Key Path を使って、モデルを指定する。たとえば、File's Owner が NSApplication で、そのデリゲートが WebView を持っていて、WebView から WebPreferences を取り出して、その defaultFontSize にバインディングするには、Model Key Path に、delegate.webView.preferences.defaultFontSize って指定してやればいい。ま、これは、極端な例だけど。この場合、File's Owner をかますので、nib でインスタンス化していないオブジェクトも、モデルとして指定できる。 また、キー・パスには演算子を指定することもできる(Array Operators)。オブジェクトの数や、値の平均、最小値、最大値とかが得られる。これを使うと、対多関連のプロパティを表示するときに、選択しているものが全体の何番目かを示す「2 of 200」って感じのを、コーディングなしで実現できたりする。
これ分からんよね。1 つは、おっしゃってるように、bind:toObject:withKeyPath:options: で何をやればいいのか分からない。あと、現在バインディングしている、またはバインディングされているものを知る方法が無い。だから、動的にバインディングを変更できないし、バインディングしているキー・パスを知ることもできない。これ、けっこう嫌だ。 いちおう、NSObject の observationInfo がそれらしいんだけど、void* 型のデータが返ってきて、中身公開されていないし。この中身が分からんと、不便だなー。 |
|
さらに、ツッコミ返し。
属性と関連はきちんと定義(Terminology)がありまして、端的に言うと、属性はプロパティを持たないもの、関連はプロパティを持つものです。さらに踏み込んでいってしまえば、属性はバインディングの対象になるもの、関連はならないもの、です。関連から属性を取り出して、それをバインディングすることになります。たぶん、こう言い切っていいと思うんだけど。 具体的にいえば、属性は NSNumber だったり NSString だったり NSColor だったり。NSNumber や NSString はテキストフィールドの value にバインディングできるし、NSColor はカラー・ウェルの value や、テキストフィールドの textColor にバインディングできる。 それに対して、関連は自分で定義したモデルクラスだったり NSMutableDictionary だったり。これを直接バインディングすることはなくて、そっから属性を取り出します。 関連の概念では特に対多関連が大事です。たとえば、テーブルにデータを表示するときのことを考えてください。テーブルの 1 行分のデータが 1 つのモデルクラスに納められている。そのモデルクラスは Music っていうクラスで、title、artist、time っていう属性を持っているとする。それを、テーブルのそれぞれの列に表示するとする。 こういう場合は、テーブルとコントローラの間を「対多関連」で関連づけます。これには、arrangedObjects コントローラキーを使うでしょう。そして、コントローラとモデルの間は、「属性」を指定する。title とか artist ですね。 というわけで、属性と関連の違いは、Cocoa バインディングの肝です。少なくとも、NSArrayController を使うときは、かなり意識します。個人的には、NSHierarchyController みたいのが欲しいっすね。で、それを NSOutlineView や NSBrowser にバインディングできれば、とっても嬉しいんだけど。 |
|
前に、iBook に不具合があるから、ロジックボードの交換を行う、っていう告知があったでしょう(iBook - Logic Board Repair Extension Program)。 うちにも iBook があるんだけど、そういや 1 年ほど前に修理に持っていったんだよね。なんか、ふたの開け閉めをすると、画面がちらついて。そのうち映らなくなった。修理の対応をしてくれた兄ちゃんは、「あぁ、これね」っていう感じの受け答えで、あっさりロジックボード交換とあいなった。 あれって、この交換プログラムに含まれんのかなー、と思っていたら、Apple から手紙が来た。いわく、「お前にやってやった修理はいまただでやってるから、リファンドしてやる」だって。おぉ、金返ってくるのか。当たり前の対応だけど、Apple がそんな当たり前のことをできるようになったんだ、と思って、ちょっとびっくり。 この修理って、Apple Store に持ち込んでやってもらったんだよね。だから、スムーズだったりするのかも。直営店は、やっぱり便利というか、安心感がある。 |
|
Safari のさ、戻る、進むボタンって、長押しするとメニューが出てくるじゃない。コントロール + クリックでも出てくるんだけど。あのボタンを作ってみようと思ったんだよ。 そのために、まずボタンをクリックしたときの挙動を調べてみた。ボタンである NSButton をクリックすると、mouseDown: が呼ばれる。その次に、NSCell の trackMouse:inRect:ofView:untilMouseUp: が呼ばれる。その中からは、きちんと設定すれば、startTracking:inView:、 continueTracking:at:inView:、 stopTracking:at:inView:mouseIsUp: が呼ばれて、ドラッグの状態を知ることができる。 えーと、ということは、trackMouse:inRect:ofView:untilMouseUp: をオーバーライドして、NSApplication の nextEventMatchingMask:untilDate:inMode:deque: でも呼んでよればいいのか。ということで、NSButtonCell を継承したクラスで、次のような実装をしてみた。 (sample)
まず、NSApplication の nextEventMatchingMask:untilDate:inMode:dequeue: を、NSLeftMouseUpMask と NSLeftMouseDraggedMask を指定して呼んで、ユーザのドラッグを 1 秒間待つ。その間にドラッグかマウスアップが発生したら、NSButtonCell のメソッドを呼ぶ。ドラッグしなかったら、NSMenu を使ってコンテキストメニューを表示する。 これで、とりあえずは動く。ちゃんと、長押しでメニューが表示される。でも、問題もある。
うーむ。どうしたもんだろう。もう少し対策をつめれば、ちゃんと動きそうな気もするけど。でも、今日はワインを飲んで酔っぱらっているので、続きはまた後日。
ソースコードダウンロード
|
|
void GraphicWizardsLair(void); 経由、「火星でいったい何が起きたのか?」この間の、NASA の探査機が火星で再起動を繰り返したときの、原因と解決法。 まず、発生した問題を、無意味に隠さずにきちんと公表するのは正しいよね。隠したって、ぜんぜん意味ないし。この記事で、何が起きたかを理解するには十分な量の情報がある。 個人的な印象は、優先度逆転での問題って実際に起こるんだ、ってこと。そりゃ確かに、起こりうることは周知のことだけど、そこまで突き詰めなくても、たぶん大丈夫だよね、って感覚があった。そうか、ほんとうに起こるんだ。 ただ、VxWorks のプログラム書くなら、pipe() や select() 使わない方がいいんじゃない?ネイティブで用意されている、セマフォやメッセージキューを使えよ、という気はする。それが直接の原因ではないにせよ、UNIX 的な皮を使うよりは、ネイティブ API を呼ぶ方がいいって。この場合は、移植性を気にしなくていいし。火星探査機用プログラムを移植するか? |
|
ひさしぶりに、はじめてのブラウザのつくり方を更新!ジャカジャン! 今回は、WebPreferences を Cocoa バインディングで設定するだ。あの、WebView 用の初期設定パネルを、Cocoa バインディングを使って実装しよう、という話だぜ。ポイントは、NSObjectController のsetContent: を動的に使うところ。詳しくは、読んでみて。
ほんとは、これにフォントウェルを使いたかったんだけど、今回は断念。きちんと nib パレット用に書き出さないと、あまり恩恵が受けられないから。そのうち、きちんとやるぞ、これも。 |
|
使っている PowerBook G4 のバッテリが、だめだめになってしまった。充電しても 10 分も持たない。これじゃ、ぜんぜんバッテリ駆動できねーよ。というわけで、新しいバッテリを買ってきてしまいました。そうしたら、駆動時間が 3:30 にのびた。すばらしい。 PowerBook G4 の、初代をほぼすぐに買ったんだよな。たしか、2001 年の 1 月か 2 月だったような。丸 3 年使っているのかぁ。バッテリもそろそろへたりますか。 |
|
Xcode の CVS サポートを、いろいろと弄んでみた。いやー、使いにくいね、これ。とりあえず、まとめてみるよ。 始めにいっておきますと、mkino は会社では Perforce と VSS (Visual Source Safe) を主に使っていて、CVS はほとんど使ったこと無いです。つまり、バージョン管理の概念は知ってますけど、CVS 自体はよく知らないです。というわけで、CVS 入門も兼ねながらまとめるよ。 まずは、Xcode の CVS サポートを手っ取り早く体験してみよう。そのために、ローカルで CVS リポジトリを作る。つまり、ローカルのマシンを、CVS サーバとして使うということね。 ローカルで使うには、適当な箇所に、CVS のリポジトリを作る。たとえば、/usr/local/newrepos に作ってみよう。それには、コマンドラインから以下のように打ち込む。
CVS の init コマンドっていうのが、新しいリポジトリを作るためのもの。これで、ローカルマシンに、CVS のモジュールを作ることができるようになる。 次に、CVS に入れる、Xcode のプロジェクトを作る。Xcode を起動して、適当なプロジェクトを作ってくれ。仮に、TestProject っていう名前にしよう。 そうしたら、このプロジェクトを CVS に入れる。それには、コマンドラインで TestProject のディレクトリに移動して、次のコマンドを入れるんだ。
import コマンドが、CVS に新しいモジュールを作るためのコマンド。-m の後に来るのは、コメント、モジュール名、ベンダータグ、リリースタグ。とりあえず、モジュール名が大事。このコマンドを実行すると、追加されたファイル名がずらずらと出てくると思う。 これで、CVS にファイルが入った。ただし、この状態では Xcode は自分が CVS に入れられたことを知らない。そこで、いったんファイルをすべて CVS から取り直す必要がある。まず、Xcode を終了する。そして、TestProject ディレクトリの名前を他の名前に変更してくれ。そして、CVS からファイルを取り直す。次のコマンドを実行してくれ。
co は checkout の意味。これで、TestProject のファイルを CVS から取得できる。新しい TestProject ディレクトリをのぞくと、CVS っていうディレクトリができていると思う。ここに、CVS の情報が入る。そして、このディレクトリによって、Xcode は CVS を利用していることを知ることができる。 で、Xcode を起動し直す。そうすると、SCM メニューが使えるようになる。ファイルを変更して diff を取ったり、変更をコミットしてみてくれ。 ここまでで分かるのは、Xcode からは、リポジトリの作成、新規モジュールの作成、ファイルのチェックアウトはできない。これらはコマンドラインから実行する必要がある。CVS から取得した Xcode のプロジェクトファイルを使うと、コミット、diff、アップデートなどができるようになる。 といったところで、次回へ続く。 |
|
掲示板の方で要請(ってほどじゃないけど)があったので、試しにコメント機能をつけてみたよ。HaloScan を使っています。 前から、やらんといけないなー、と思っていたので、ちょうどいい機会なので。そろそろ、サイト全体をオーバーホールしないといけないなぁ。 |
|
Matz にっきや、mput の日記から。あなたのあこがれのプログラマって誰だ? そら、あんた、簡単な話で、ビル・アトキンスンだし、アンディ・ハーツフィールドだし、アビー・テバニアンでしょう。まぁ、Mac ユーザって単純。 |
|
かりやん日記さんの、Cocoa バインディングの件の件。 その通りでして、もちろんモデルを setValue:forKey: で更新するのが正しいと思います。それができるのならば。問題は、ビューの値を更新しようとするオブジェクトが、ビューのことしか知らない場合です。バインディングの Controller Key と Model Key Path は、通常 Interface Builder で設定するので、そのオブジェクトは知らないです。 では、ビューから、現在持っているバインディングの設定を取り出すことができるか?唯一それらしいことができるメソッドは、NSObject の observationInfo でしょうか。でも、これ返ってくるのが void* 型で、どんなデータか分かんねー。 ということで、ユーザの挙動のトレースしか手が無いのです。 |
|
とはいうものの、挙動トレースをしようとしても、やっぱりうまく動かん。冷静になると、たしかに無駄な努力の気もするし。この問題の箇所は、Cocoa バインディングを使わない方向でいきます。ぷしゅ〜ぅ。 |
|
NSTextField の value を、あるモデルのプロパティとバインディングしたとしよう。たとえば、Album っていうモデルクラスの title プロパティとバインディングしたとする。このとき、他のオブジェクトが title プロパティを変更すると、NSTextField の値が更新される。これはオッケー。また、ユーザがテキストフィールドの値を手で変更すると、今度はモデルの title プロパティが変わる。これもオッケー。でも、プログラム上で NSTextField に setStringValue: を使って値を変更すると、モデルの title プロパティは変更されない。これはよくない。 察するに、setStringValue: でモデルのプロパティも変更してしまうと、ループのような状況に陥ってしまうのではないか。だから、わざと更新しないようにしている。そうだとしたら、それはしょうがない。じゃあ、どうするか?プログラム上で、ユーザが手で編集したのと同じような処理を行ってやればよい。NSControl やら NSCell のメソッドを眺めていると、editWithFrame:inView:editor:delegate:event: や endEdting: あたりが怪しいのではないかと。これをコードから呼んでやれば、ユーザが手で編集したのと同じことになるのでは?と、予測をたててみた。後で実験してみる。 でも、このへんは Cocoa バインディング側でケアしてほしいなぁ。 |
Surfin' Safari で、Safari 1.2 の修正箇所が紹介されているぜ。ざっと抜き出すと、
よく分かんないところもあるけど、こんな感じ。詳しくは Surfin' Safari のページでどうぞ。 |
|
Cocoa 1001 の更新。Cocoa バインディングでエンコーディングメニューを作る。こんな感じのエンコーディングメニューを、Cocoa バインディングで作ってみた。
|
|
フォントウェルに対する反応がいくつかあったよ! まずは site-aro さん。パネルが出っぱなしになるのはいやなので、メニューみたい終わったらひっこむといいのかではないかと。うーむ、出っぱなしがよくないのは賛成ですけど、パネルをそのままメニューにするのはどうかと。下のボタン、隠れちゃうし。 ヘチマコンピュータさんは、最近使った項目と、よく使う項目のメニューを追加した HTFontWell を。これは使いやすいかも。NSSegmentedControl のほうが、たしかにかっこいいし。 両方とも、メニュー形式を採用しているんだよ。やっぱり、ワンアクションで選択できるポップアップメニューは、パネルよりも便利ですな。でも、項目が 40 とか 50 もずらずら続くのは勘弁。5 から 10 ぐらいのメニューから選択できるのが、いちばん楽なのかなぁ。 |
|
たいへんひさしぶりに、Cocoa 1001 を更新。ツールバーを使って、タブを選択するっす。初期設定パネルのように、ツールバーとタブがくっついたインタフェースの作り方の話。 ちなみに、Mac OS X 10.3 からは、NSToolbar のデリゲートで toolbarSelectableItemIdentifiers: を実装することで、ツールバーのアイテムを選択表示することが可能。この手の初期設定パネルでは、これを使おう。 |
|
いま、あるアプリケーションをちょびちょび書いていて、そのとき気づいたものを書き留めいているのが、最近の更新なのでした。 |
|
Cocoa Bindings Examples and Hints。おぉっ、まだほとんどみかけることのない、Cocoa バインディングの例が。 |
|
NSPopUpButton の Bindings では、文字列しか表示させることができないのか?NSMenuItem 渡したら、その description を表示しやがった。これじゃ、セパレータを表示できないじゃないか。うーむ。 |
|
きのうカラーウェルの話を書いたけど、実は、始めはフォントを設定するときのユーザインタフェースを考えていたんだ。
個人的に、このインタフェースはあんまり好きになれない。ポイントは 2 つ。1 つは、ボタンとテキストフィールドという、2 つの部品を使っていること。1 つにまとまっていた方が、すっきりして好き。もう 1 つは、どれが設定中のフォントか分からないこと。一応、最後に「設定」ボタンを押した方のフォントを設定することになっているんだけど、インタフェースにその情報が表示されていないから、ぱっと見分からんよね。 これとは別に、ポップアップメニューを使うという手もある。でもこれは、フォントの数が 40 とか 50 になると、かなり使いづらい。それに、せっかくなら、システムが用意しているフォントパネルを使いたいよね。
フォントウェルは、フォントを選択、表示するためのインタフェースだ。使い方は、
フォントウェルには、アクティブ状態と、非アクティブ状態があるんだ。
さらに、排他制御も行う。
といった仕様にして、実装してみた。とりあえず手っ取り早く行うために、NSButton のサブクラスにしてみた。だから、Cocoa バインディングにも対応できるぜ。使ってみた感じはけっこういいと思うんだけど、どんなもんでしょ。ソースコードをダウンロードしておくようにするんで、興味のある人はどうぞ。 ダウンロード
FontWell.tar.gz |
|
Apple が .Mac メンバに配布していた、スーパージグゾーパズルにどっぷりとはまる。好きなんだよ、こういうの。500 ピースぐらいにしてやってみたら、すげー難しい。でも、ピースがはまったときの快感が病み付きになって、やめられなくなる。5 時間が飛んでいった。あぅぅ。 |
|
カラーウェルの謎
カラーウェルってあんまり使ったことがなかったので、どういう動作をするか調べてみた。まず、当然のことながら、
ということができる。これは、見れば分かるね。さらに、
ことができる。そして、カラーパネルで色を変更するために、
うーむ、なるほど。で、さらにアクティブ状態のことについて調べてみると、こんな特性もある。
アクティブ状態は、ラジオボタンみたいに、排他的にできるんだ。だけど、普通排他的な制御をするには、お互いのことをしらないといけないよね。たとえばラジオボタンだと、NSMatrix の中に入れられて管理されている。しかし、カラーウェルは、そういう明示的な設定がいらない。さらに、実験してみたら、異なるウィンドウ上にあるカラーウェルの間でも、排他的に制御されてる! なんでー?どうやってんのー?と思って、調べてみた。デバッガ立ち上げていろいろ見てみると、どうも NSColorWell は、インスタンスが作られると、どこかで一元的に管理されているみたい。で、あるカラーウェルがアクティブになると、他のインスタンスに非アクティブにしろ、という通知が行くみたい。 なるほどー。そういうことですか。将来役に立つかもしれないから、いちおう覚えておくことにする。 |
|
Safari 1.2 が公開されたよー。 今回のアップデートでは、WebCore と JavaScriptCore のソースコードも、速攻で公開された。毎回、こうしてくれよー。バージョンは v125 になったらしい。中身は、まだ見てない。 |
|
Omni Web の 5.0 beta も出たよー。 Omni Web も、Safari と同じく WebCore をベースにしている Web ブラウザ。ほうほう、どれどれ、とパッケージを開いて、WebCore と JavaScriptCore のバージョンを確認してみると、v85。あれー?古いじゃん。これって、WWDC 2003 のときのバージョンだね。つまり、Web Kit が公開されたときのもので、もう半年ぐらい前のかな。Omni のサイトで公開されているソースコードも変わっていないし。5.0 は、ユーザインタフェースの変更だけで、レンダリングエンジンは変更ないのか? |
|
なんか、とにかく、えらいこと忙しくてですね。やらなくてはいけないことが、やってもやっても終わらなくてですね。HMDT の方が、ぜんぜん更新できなかったのです。 そのうちに、忘れた頃に、成果をお見せできる、かも。 |