|
|
Log In | Not a Member? |
Contact ADC |
| < Previous PageNext Page > |
アプリケーションに表示されるオブジェクトの多くは、ユーザが操作して意図を伝えることができるようになっています。このようなオブジェクトには、ボタン、チェックボックス、スライダ、テーブルビュー、ファイルシステムブラウザ、そしてメニュー(アプリケーションメニューとポップアップメニューを含む)があります。Cocoaでは、一般的な選択を可能にする2種類のオブジェクトであるコントロールとメニューの実装において、似たようなアーキテクチャがその基礎になっています。これらのアーキテクチャでは、NSViewオブジェクトを含む各種のオブジェクトが連携して機能することによって、ユーザによる選択や意図の指示を可能にしています。
コントロールとセルのアーキテクチャ
メニューの特性とアーキテクチャ
表現オブジェクト
コントロールは、マウスクリックなどのユーザイベントに対応して、アプリケーション内の別のオブジェクトにメッセージを送信することによって応答する、ユーザインターフェイスオブジェクトです。コントロールの一般的な種類として、ボタン、スライダ、テキストフィールドなどがあります(通常、テキストフィールドはユーザがReturnキーを押したときにメッセージを送信します)。そのほか、比較的目立たないコントロールとしては、テーブルビュー、データブラウザ、カラーウェルなどがあります。
コントロールは抽象NSControlのサブクラスのインスタンスで、通常は1つ以上のセルを管理します。セルは、別の抽象クラスであるNSCellのサブクラスのインスタンスです。Application Kitのクラス階層を調べてみると(Figure 1-9を参照)、NSViewのサブクラスであるNSControlが、NSButton、NSStepper、NSTextFieldなど、かなり大きなコントロールクラスの分岐のルートになっていることがわかります。また、階層内のまったく別の位置(NSObjectの配下)で、NSCellがセルクラス群の分岐の起点になっており、それらのほとんどがNSButtonCell、NSStepperCell、NSTextFieldCellなどのコントロールクラスに対応します。
注: NSScrollerとNSColorWellの2つのコントロールクラスは、セルをまったく使用しません。これらのクラスのインスタンスは、ほかのコントロールと同様に、ユーザによる選択の提示を可能にしますが、自身の描画を行い、セルを使用せずにユーザイベントに応答するという点では、非コントロールビューと同様に動作します。
Application Kitにあるコントロールの大部分は、単一のセルを管理します。これらのコントロールでは、コントロールのセルによって実際の処理のほとんどすべてが実行され、コントロールに送信されたメッセージの多くがセルに転送されます。しかし、複数のセルを管理するコントロールもあります。Application Kitでは、コントロールの中で複数のセルを管理するために、大まかに次の2種類のアプローチを採用しています。
単一のセルインスタンスを描画のテンプレートとして使用する方法。コントロールでセルを描画する必要が生じるたびに、このインスタンスを使用して各セルの表現を複製し、内容だけを変化させます。NSTableViewクラスやNSOutlineViewクラスでは、テーブルビューおよびアウトラインビューの列のセルを描画するときに、このアプローチが使用されます。
個々のセルインスタンスによって、コントロール上に描画される各セルリージョンを表す方法。NSMatrixクラスでは、行列のセルインスタンスに対してセル自身を描画するよう要求するときに、このアプローチが使用されます。また、NSBrowserオブジェクトやNSFormオブジェクトも同様に機能します。これらのセルもまた個別のインスタンスです。
NSMatrixオブジェクト(行列)は、ほとんどの種類のセルを管理でき、セルを任意の次元数のグリッドに配置します。Interface Builderでセルの行列を作成するとき、セルはすべて、指定のセルプロトタイプのコピーです。ただし、プログラミングを行って、セルをNSCellの別のサブクラスのインスタンスとなるように設定できます。NSBrowserコントロールやNSFormコントロールでは、管理できるセルの種類がもう少し限定されています。
単一セルのコントロールは冗長なデザインに思われるかもしれませんが、ここで得られる価値はコントロールではなくセルにあります。詳細については、“「コントロール/セルアーキテクチャを使用する理由」”を参照してください。
コントロールは、いわばフル装備のNSViewオブジェクトです。コントロールは要表示としてマークすることができ、自身の描画を行います。また、ユーザイベントに応答でき、レスポンダチェーン内に存在します。実行時の初期状態では、コントロールはビューと同様に動作します。Application Kitは、コントロールのdrawRect:メソッドを呼び出すことによって、コントロール自身に再描画を行うよう要求します。イベントメッセージがレスポンダチェーンにディスパッチされた場合、該当するNSResponderメソッドをコントロールが実装していれば、そのコントロールはイベントを処理する機会を得る可能性があります。ただし、コントロールでは描画とイベント処理を自身で行うのではなく、それらの役割を自身のセルに任せます。コントロールが複数のセルを持っている場合は、セルの動作の調整も行います。
Figure 6-21に示すように、通常、コントロールはそのdrawRect:メソッドの中でdrawWithFrame:inView:をセルに送信し、メソッドに渡した矩形の中でセル自身を描画するようセルに要求します。コントロールに対するフォーカスがすでにロックされているので、セルは自身の「ホスト」ビューのサーフェスを使用して自身を描画できます。コントロールはmouseDown:イベントメソッドの実装の中で、イベントが発生したセルにtrackMouse:inRect:ofView:untilMouseUp:を送信します。セルは通常、自身の境界線の内側でマウスイベントを追跡し、マウスが境界の外に出るか、セルがmouseUp:イベントを受信すると、それに応じて応答します(ほかの種類のイベントも同様の方法で処理されます)。
セルは、自分自身を描画するときに2つの要素を表現する必要があります。1つ目は、セルの全般的な外観です。外観は同じクラスのセルどうしで一貫しています。このような特性には、セルの形状、背景色、スタイル、およびセル状態の視覚的な指標(たとえば、セルの選択を示すチェックボックスや、セルが有効にされていない場合のグレイテキストなど)があります。2つ目は、セルのコンテンツ(内容)です。コンテンツによってセルが個別化されます。コンテンツに関しては、セルは通常、タイトル(文字列)を持つか、画像を持つか、または場合によってはタイトルと画像の両方を持ちます。タイトルにはフォントを指定できます(NSSliderCellなどの一部のセルは、画像やタイトルの代わりにカスタムのコンテンツを持ちます)。
セルはコンテンツ(またはコンテンツの一部)として、オブジェクト値を持ち、表現オブジェクトを持つ可能性があります。オブジェクト値は、文字列として書式を指定でき、したがって、セルタイトルとして表示できるオブジェクトである必要があります。たとえば、float値をカプセル化しているNSNumberオブジェクトなどがあります。表現オブジェクトは、表示はされませんが、セルに関連付けられるオブジェクトです。たとえば、「Red」というタイトルを持つボタンならばNSColor表現オブジェクトを持たせることが考えられます。オブジェクトの値と表現オブジェクトの詳細については、“「表現オブジェクト」”を参照してください。
また、ほとんどのセルを個別化するものとして、セルがアクションメッセージ用にカプセル化している情報があります。ターゲット/アクションメカニズム(“「ターゲット/アクションメカニズム」”で説明しています)によって、ユーザが(ボタンをクリックしたりテキストフィールドでReturnキーを押したりして)コントロールをアクティブ化したときに、コントロールから、指定のオブジェクトにメッセージを送信することができます。アクションは呼び出すメソッドを識別するセレクタであり、ターゲットは指定されたオブジェクトです(ターゲットはnilにすることができます。この場合は、メッセージを処理することのできるオブジェクトをレスポンダチェーンの中で検索するようアプリケーションが指示されることになります。詳細については、“「レスポンダとレスポンダチェーン」”を参照してください)。抽象NSActionCellクラスでは、アクションセレクタとターゲットオブジェクトへの参照を格納および取得するためのインターフェイスが定義されています。NSCellのほとんどのサブクラスはNSActionCellを継承しています。
Application Kitのコントロール/セルアーキテクチャには深い歴史的な由来があり、NeXTSTEPの初期の頃にまでさかのぼります。しかし、その必要性については一見したところではわかりにくいかもしれません。そもそもコントロールがセルに管理を任せるのはなぜでしょう。コントロール自身が、必要な処理をなぜ実行できないのでしょう。
コントロールが処理を実行できない理由はまったくなく、カスタムコントロールを作成する場合に、セルのないコントロールを作成することは確かに有効なアプローチです。しかし、コントロール/セルアーキテクチャは以下のような利点をもたらします。
このアーキテクチャによって、コントロールの利便性が広がります。テーブルビューや行列などのコントロールでは、異なる種類のセルを多数、効率的に管理できます。個々の種類について具体的な情報を取得する必要はありません。NSButtonCellオブジェクトなどのセルは、NSButtonコントロールと連動するように設計することもできますが、行列オブジェクトやテーブルビューオブジェクトとも連動できます。
セルという抽象化によって、異なる種類のグラフィカルオブジェクトをビュー上で管理する作業が簡素化されます。一種のプラグインデザインが可能になり、各種のグラフィカルオブジェクトをコントロールでホストし、オブジェクトはそれぞれに独自のID(ターゲットおよびアクション情報を含む)を持たせることができます。
コントロール/セルアーキテクチャによって、たとえばビューとサブビューのコレクションなどの結び付きよりも強い、コントロールとそのセルの結び付きを可能にします。サブビューは概してそのスーパービューの中で自律的です。一方、コントロールはセルのコーディネータとして、より適切に機能することができます。たとえば、ラジオボタンの行列の中で一度に1つのボタンだけがオンになることが、コントロールによって保証されます。
セルリージョンを描画するためのNSTableViewのモデル(少数のセルのインスタンスを描画用のいわば「ゴム印」として再利用しています)は効率的であり、潜在的に無制限の数のサブリージョンを管理しなければならないコントロールの場合には特に効率が良くなります。
少数のセルインスタンスを描画用のテンプレートとして使用することが実用的でない事例でも、多くの場合、セルはサブビューよりも優れたパフォーマンスを発揮します。ビューは、メモリと計算処理の両面において比較的重いオブジェクトです。たとえば、無効なビューリージョンの追跡と伝達をビュー階層を通じて行う処理は、多くのコストを伴う可能性があります。
セルの使用とサブビューの使用とでは、サブリージョンの描画に関してトレードオフも存在します。ビューの無効化のメカニズムがないため、各セルについてセルに何を描画する必要があるのかを、コントロールの側で管理する必要があります。しかし、ビューは汎用のオブジェクトであるため、多くの場合、特殊化されたコントロールを使用すれば、必要な計算をより効率的に実行できます。
注: コントロール、セル、およびそれらの連携動作を可能にするアーキテクチャの詳細については、『Control and Cell Programming Topics for Cocoa』を参照してください。
コントロールとセルに加えて、ユーザはメニューを使用して自分の意図をアプリケーション(およびオペレーティングシステム)に伝えることができます。メニューは、簡潔な語句で示される選択肢(つまりメニュー項目)のリストであり、ネストされたメニュー(サブメニューと呼ばれます)を持つ場合があります。通常、ユーザはメニュー項目をクリックして選択します(ただしほかの手段もサポートされています)。選択の結果、アクティブなアプリケーションやオペレーティングシステムが実行するコマンドが発行されます。
Cocoaではさまざまな種類のメニューがサポートされています。その中で主なものはアプリケーション固有メニューです。Cocoaでは、アプリケーション固有メニューのことをまとめてメインメニューと呼びます。実行時には、アプリケーション固有メニューに操作対象のアプリケーションのメニュー(アプリケーション名を持つメニュー)が含まれ、「ヘルプ」メニューまでのすべてのメニューがその右側に表示されます。アプリケーション固有メニューは、アップルメニューおよびメニューエクストラとメニューバーを共有しています(メニューエクストラはアプリケーション固有メニューの右側に表示されるサービス固有メニューです)。Application Kitでは、特定のアプリケーション固有メニューが自動的に作成され管理されます。このようなメニューとしては、「サービス」メニュー、「フォント」メニュー、「ウインドウ」メニュー、「ヘルプ」メニューなどがあります。Cocoaアプリケーションで管理できるその他の種類のメニューとして、ポップアップメニュー、コンテキストメニュー、およびDockメニューがあります。
メニュー(および特にメニュー項目)には、いくつかの興味深い特性があります。メニューとメニュー項目はどちらもタイトルを持ちます。メニューのタイトルは、メニューバーに表示される文字列です。メニュー項目ではさらに、タイトルの左に表示される画像を持たせたり、タイトルの代わりに画像を持たせたりできます。タイトルは属性付きの文字列にすることができ、さまざまなフォントを使用できるほか、テキストの添付書類も使用できます(テキストの添付書類を使用すると、メニュー項目のコンテンツ領域内の任意の位置に画像を表示できます)。また、メニュー項目には代替キーストロークと呼ばれるキーを割り当てることもできます。代替キーストロークを修飾キー(Shiftキーを除く)と一緒に押すことによって、マウスクリックと同じ応答が得られます。メニュー項目は有効または無効になります。また、オンまたはオフの状態を示すことができます。項目がオンの状態の場合は、タイトルの左にチェックマークが表示されます。
Cocoaのメニューおよびメニュー項目はそれぞれ、NSMenuクラスおよびNSMenuItemクラスのインスタンスです。Cocoaアプリケーションでは、メニュー(一般的な意味での)はNSMenuオブジェクトとNSMenuItemオブジェクトに相補的な役割が与えられるような、シンプルなデザインがベースになっています。NSMenuオブジェクトは、下方向に順に並ぶメニュー項目のコレクションを管理し描画するもので、そのコレクションを表すNSMenuItemオブジェクトの配列が格納されます。NSMenuItemオブジェクトは、メニュー項目を特徴付けるすべてのデータをカプセル化するものですが、自身では描画やイベント処理をまったく実行しません。NSMenuオブジェクトは各NSMenuItemにあるデータを使用して、メニュー境界の内側にメニュー項目を描画し、メニュー内部のメニュー項目の位置を追跡し、ユーザがメニュー項目を選択したときにアクションメッセージをターゲットオブジェクトに送信します。NSMenuオブジェクトは、描画時には、NSMenuItemオブジェクトのタイトルと画像を使用します。追跡時には、項目のインデックスを使用します。アクションメッセージの送信時には、NSMenuItemオブジェクトに格納されているアクションセレクタとターゲットオブジェクトを使用します。
ポップアップメニューではこの基本的なメニューアーキテクチャが利用されています。ただし、ポップアップメニューはアプリケーションのユーザインターフェイスの中で表示されるため、デザインが追加されています。ユーザがクリックする前のポップアップメニューは、ボタン状のオブジェクトとして表示されます。このオブジェクトはNSPopUpButtonのインスタンスで、NSPopUpButtonはNSPopUpButtonCellのインスタンスを管理します。つまり、この最初の表示のためにコントロール/セルアーキテクチャが使用されます。NSPopUpButtonCellオブジェクトには、NSMenuオブジェクトが、カプセル化されたNSMenuItemオブジェクトと一緒に格納されています。ユーザがポップアップボタンをクリックすると、埋め込まれているこのメニューは、自身を表示するよう要求されます。
メニュー内のメニュー項目は現在のコンテキストに応じて有効性を判断することができます。項目がそのコンテキストに無関係であれば無効にできます。NSMenuには、この有効化を自動的に実行する自動有効化機能が組み込まれています。メニューが表示される前に、この機能によって、メニュー項目のアクションメッセージに応答できるオブジェクトがレスポンダチェーンの中で検索され、そのようなオブジェクトが見つからなければ項目は無効にされます。アプリケーションではNSMenuValidation簡易プロトコルを実装することで、メニューの有効化をさらに細かく制御できます。
コンテキストメニューもポップアップメニューと同様の方法で実装されます。NSResponderのsetMenu:メソッドを使用して、NSMenuオブジェクトを(そのメニュー項目と一緒に)ビューに結び付けることができます。このメニューにはビューに固有のコマンドが一覧表示されます(コマンドはコンテキストに応じて有効化できます)。ユーザがビューの中でControlキーを押しながらクリックするか、または右クリックすると、メニューが表示されます。
セルとメニュー項目には、表現オブジェクト、つまり任意に関連付けられたオブジェクトを持たせることができます。アクションメッセージのターゲットは、クリックされたメニュー項目やセル(sender)にその表現オブジェクトを問い合わせることで、表現オブジェクトの表示やロードなど、取得したそのオブジェクトに関して必要な任意の操作を実行できます。セルやメニュー項目では、表現オブジェクトは、クライアントによるアクセスが可能なほか、アーカイブと復元が可能ですが、それ以外の場合は使用しません。
表現オブジェクトの使用方法を理解するために、いくつかの例を考えてみましょう。行列に、テキストビューの背景色を設定するセルが含まれているとします。これらのセルには「明るい青」、「明るいグレー」、「ピンク」などの名前が付いています。各メニュー項目の表現オブジェクトはそれぞれの色に対応したRGBコンポーネントをカプセル化したNSColorオブジェクトです。アプリケーションでは、表現オブジェクトをListing 6-1に示すような方法で使用できます。
Listing 6-1 表現オブジェクトの使用
- (void)changeColor:(id)sender { |
NSColor *repObj = [sender representedObject]; |
[textView setBackgroundColor:repColor]; // textView はアウトレット |
} |
別の例としては、設定パネルの表示を変更できる、「情報」ウインドウのポップアップメニューを考えてみます。それぞれのメニュー項目に、必要なテキストフィールドやコントロールなどの一式を含むNSViewオブジェクトが、表現オブジェクトとして割り当てられることが考えられます。
表現オブジェクトは、コントロールやセルのオブジェクト値とは異なります。表現オブジェクトは任意で関連付けられるものであるのに対し、オブジェクト値はセルやコントロールに表示される内容の実体です。たとえば、“05/23/2006”と表示されるテキストフィールドのオブジェクト値は、表示される値を表すNSDate、またはNSCalendarDateオブジェクトです。セルやコントロールのフォーマッタは、オブジェクト値を“理解”できる必要があります(フォーマッタはNSFormatterオブジェクトです)。
表現オブジェクトは、セルとメニュー項目に、厳密には限定されていません。たとえば、NSRulerMarkerオブジェクトが表現オブジェクトを持ったり、カスタムビューに表現オブジェクトを持たせるように設計することもできます。
| < Previous PageNext Page > |
Last updated: 2006-05-23
|
Get information on Apple products.
Visit the Apple Store online or at retail locations. 1-800-MY-APPLE Copyright © 2007 Apple Inc. All rights reserved. | Terms of use | Privacy Notice |