Apple Developer Connection
Advanced Search
Member Login Log In | Not a Member? Contact ADC

< Previous PageNext Page >

ビュー

NSViewオブジェクト(または単にビュー)は、ウインドウの中で矩形領域を占有します。Cocoaでは、ビューはNSViewのサブクラスのインスタンスです。ビューはApplication Kitの中で最も普遍的なタイプのオブジェクトであり、Cocoaアプリケーションで目にするオブジェクトのほとんどすべてがビューです。ビューは描画とイベント処理の両方について最初に処理を行います。したがって、重要性の高いタイプのオブジェクトの1つとして理解しておく必要があります。

ビューが画面上で実行する描画は、ビューオブジェクト自身の視覚表現と捉えることができます。実際、ビューは自分自身の描画を行います。また、ビューは、マウスやキーボードその他の入力デバイスからの入力に応答できるサーフェスも提供します。

参考資料: NSViewオブジェクトの描画に関連した概念や処理の詳細については、『Cocoa Drawing Guide』を参照してください。また、ビューの操作に関連した各種の処理の詳細については、『View Programming Guide for Cocoa』を参照してください。

In this section:

各種のビュー
ビュー階層
ビューのジオメトリと座標
ビューが描画される仕組み
ビューとプリント
ビューとイベント


各種のビュー

NSViewは、アプリケーションの基本的な描画、イベント処理、およびプリントのアーキテクチャを定義したクラスです。NSView自体はコンテンツを描画したりユーザイベントに応答したりすることはありません。そのため、通常はNSViewのインスタンスと直接やり取りすることはありません。代わりに、NSViewのカスタムサブクラスのインスタンスを使用します。カスタムビュークラスはNSViewを継承し、そのメソッドの多くをオーバーライドします。オーバーライドメソッドはApplication Kitによって自動的に呼び出されます。

Application Kitのクラス階層(Figure 1-9)を見てみると、NSViewを直接的または間接的に継承するクラスが多数あることがわかります。これらのクラスは次のように分類されます。

オブジェクトによっては上記の分類に複数当てはまるものがあります。たとえば、NSTableViewオブジェクトは複合ビューですが、コントロールでもあります。

ビュー階層

“「ウインドウ」”ですでに説明したように、ビューオブジェクトはそれぞれ、ビューオブジェクト自身が表示されるウインドウに関連付けられます。ウインドウ内のビューはすべてビュー階層として相互に連結されます。各ビューは自身のスーパービューとなる別のビューを持ちます。また、自身が任意の数のサブビューのスーパービューとなる場合もあります。ビュー階層の最上位にはウインドウのコンテンツビューがあります。コンテンツビューにはパブリックのスーパービューがありません(プライベートのスーパービューはあります)。ビュー階層には「囲う」という重要な視覚的特徴があります。つまり、スーパービューによってそのサブビューが囲われ、それらのサブビューの位置はスーパービューが基準になります。Figure 6-11はこの囲った構造を図示します。


Figure 6-11  ビュー階層

Figure 6-11 ビュー階層

ビューを階層状に整理することは、描画とイベント処理の双方にとって利点があります。描画の面では以下の3つの利点があります。

注: ビューのインスタンス階層とビューのクラス継承階層とを混同しないようにしてください。ビューの継承階層は、クラスを共通の属性、インターフェイス、および動作に基づいて整理したものです。ビューのインスタンス階層は、特定のビューのインスタンス群を囲い構造に基づいて整理したものです。

ビュー階層(ここではビューのインスタンス階層のことです)はレスポンダチェーンの主要な一部分となっているため、イベント処理において重要な役割を果たします。レスポンダチェーンの詳細については、“「レスポンダとレスポンダチェーン」”を参照してください。

ビュー階層は動的に変化します。アプリケーションが実行されているときに、ビューの配置を変更したり、ビューを追加したり、ビューを削除したりできます。あるウインドウから別のウインドウにビューを移動したり、特定の階層の中でビューを移動したりできます。

NSViewには、ビュー階層の中でビューを探すための便利な関係プロパティが3つあります。

Figure 6-12は、ウインドウオブジェクトとそのビュー階層の関係を、上記のプロパティを反映して図示します。


Figure 6-12  ビュー階層内のオブジェクトどうしの関係

Figure 6-12 ビュー階層内のオブジェクトどうしの関係

ビューのジオメトリと座標

ビューのジオメトリは、主に各ビューに関連付けられる2つの矩形(フレームと境界)によって定義されます。これらの矩形は同じ領域を囲むものですが、目的は異なります。これらは一体となって、ビューの位置とサイズを定義するのに役立ちます。また、ビューが描画を行ったりイベントに応答したりする際の座標系を定義するのにも役立ちます。

注: これらの矩形によって示される寸法と位置は浮動小数点値で表されます。

フレーム

フレーム矩形はビューの領域を定義するもので、描画の対象にできる板のようなものです。ビューをウインドウ上の矩形領域として捉えた場合、フレームは、その矩形の寸法と、ウインドウ内での矩形の位置を、指定するものになります。ビューは自身のフレームの中でのみ描画を行うことができます。Application Kitのデフォルトでは、ビューが描画するコンテンツはビューのフレームを最大範囲として強制的にクリップされます。

Figure 6-13に示すように、ビューのフレーム矩形は、通常はそのスーパービューのフレーム矩形の中に置かれます。しかし、必ずしもこのようにする必要はなく、ビューのフレーム矩形をスーパービューのフレームの外まで広げることもできます。ただし、その描画は、そのビューを含んでいる祖先ビューのチェーンを最大範囲としてクリップされます。画面上に表示されるのは、ビューのフレーム矩形内の部分と、そのビューのすべての祖先ビューのフレーム矩形内の部分だけになります。


Figure 6-13  階層状のビュー

Figure 6-13 階層状のビュー

Figure 6-14も、階層的に関連している3つのビューを示します。ただし、この例では、中間のビューの一部がそのスーパービューのフレーム矩形の外に及んでいます。最下位のビューはそのスーパービューの内側に完全に収まっていますが、一部が祖先ビューの外にも及んでいます。したがって、色の付いた部分だけが表示されます。


Figure 6-14  スーパービューによってクリップされたビュー

Figure 6-14 スーパービューによってクリップされたビュー

ビューによっては、ウインドウが表示に使用できる領域に収まらない量の表示情報を持つものがあります。たとえば、長い書類の内容を含むビューなどがあります。このようなビューは、書類の一部のみを表示する別の小さなビューのサブビューにすることもできます。この小さなビューのことをクリップビューと呼びます(NSClipViewのインスタンス)。クリップビューを使用するユーザは、クリップビューを囲うスクロールビュー(NSScrollView)と、クリップビューが管理するスクローラ(NSScroller)を利用して、クリップビューの中で書類の表示部分を制御することができます。サブビューが移動すると、別の部分がスクロールされて表示されます。

ビューの位置をそのスーパービューの中で移動するには、ビューのフレームの原点を再設定します。ビューのサイズを変更するには、フレーム矩形のサイズを変更します。これらの値はスーパービューの座標系に従って解釈されるため、スーパービューの座標が変更された場合にも、画面上でのビューのサイズと位置が変更される可能性があります。

ビューはそのフレーム原点を中心にして回転させることができます。回転を実行してもビューの形状やサイズには影響はありません。回転の結果、ビューに一定の角度が付き、フレームの各辺がスーパービューのX軸およびY軸に対して平行でなくなったとしても、ビューは矩形のままです。フレームの原点は、フレームの回転角度に関係なく、同じ点に留まります。サブビューも、回転したビューに沿って配置されるため、回転したビューのスーパービューに合わせて回転することになります。Figure 6-15のビューは、Figure 6-13に示したものと同じ3つのビューですが、この例では階層の中間のビューを回転しています。


Figure 6-15  「回転したビューとそのサブビュー」

Figure 6-15 「回転したビューとそのサブビュー」

境界

ビューのフレームは、そのビューを含んでいるスーパービューの中でビューのサイズと位置を設定する手段を提供しますが、ビューの描画にはほとんど使用されません。ビューは自身のローカル座標系の中で描画とイベント処理のすべてを実行します。この座標系はビューの境界矩形によって定義されます。

ビューの境界矩形は、ビューのローカル座標系をビューの領域上にどのようにマップするのかを定義します。境界矩形はフレーム矩形とまったく同じ物理領域を表しますが、この領域はビューのローカル座標系で示されます。デフォルトでは、ビューの境界矩形は、そのサイズがフレームとまったく同じで、原点が(0.0, 0.0)です。この条件の下で、正の値の座標を使用して、ビューのコンテンツの位置設定と描画が行われます。

ただし、ビューが反転された場合はこの状況が変わります。ビューの座標系を反転させることで、描画の原点をビューの左上隅とし、Y軸が下に向かって正になるようにできます。Figure 6-16は、反転した座標系がどのようになるのかを示します。反転したビューは、英語などの言語でテキストを描画するアプリケーションの場合に特に便利です。英語では、テキストがドキュメントの左上隅から始まり、右および下に向かって記述されます。


Figure 6-16  ビューの反転

Figure 6-16 ビューの反転

ビューでは通常、画面上にレンダリングされることの決してないものが無駄に描画されないように、境界矩形が使用されます。祖先ビューの範囲外にある描画はクリップされるため、境界矩形それ自体が信頼できる指標になるのは、スクロールされずにすべての祖先のフレーム矩形の内部に完全に収まるビューの場合だけです。NSViewクラスには描画の場所を決定するための他のプログラミング手段も用意されていますが、境界矩形は依然としてすべての描画計算の一部となります。

描画座標

境界矩形はビューの描画座標をビューに提供します。ビューが自分自身の描画を行う前に、ビューの座標系がアプリケーションの現在の座標系にされます(“「ビューが描画される仕組み」”を参照)。先述のように、ビューのデフォルトの座標系は、以下の点を除いてビューのスーパービューのものと同じです。

ただし、境界に対して変換を実行した場合は、詳細が変わる可能性があります。

Figure 6-17は、ビューのデフォルトの座標系とビューのスーパービューの座標系との関係を示します。この図のinnerViewオブジェクトは、スーパービューの座標系で(400.0, 200.0)の位置にあります。innerViewでどのような描画を実行しても、この同じ点が座標原点(0.0, 0.0)として扱われます。例に示すように、innerViewで開始点を(100.0, 200.0)としてテキストを描画するときは、座標点がスーパービューの原点からではなくビュー独自の原点から測定されます。図のようにnewViewが回転した場合でも、境界の軸がフレームと一緒に回転します。ビューの描画座標の原点は変わりません。


Figure 6-17  ビューの座標系とスーパービューの座標系との関係

Figure 6-17 ビューの座標系とスーパービューの座標系との関係

ビューでは、いくつかの方法でビュー自身のデフォルトのローカル座標系を変更できます。

上記の変更によって、ビューが描画の対象にする座標系が変更され、描画の外観が影響を受ける場合がありますが、描画が出現する領域は変わりません。言い換えれば、ビューのフレーム矩形はこれらの変更の影響を受けません。

ビューが描画される仕組み

ビューは、Cocoaアプリケーションにおいてウインドウの内容を描画する役割を担う主要なオブジェクトです。それ以外のApplication Kitオブジェクト(NSCellNSBezierPathNSAttributedStringオブジェクトなど)でも描画は可能ですが、これらの場合は、描画サーフェスを提供し、描画の調整を行うために、NSViewの「ホスト」オブジェクトが必要になります。以降のセクションでは、Application Kitによるビューの描画の調整処理について、その概要を説明します。

ビューの表示

ビューは通常、いつでも自身を描画できるわけではありません。無効(または「ダーティ」)として明示的にマークし、表示の必要性を示す必要があります。マーク後、ビューの再描画が直ちに実行されるか、または、NSWindowの自動表示機能がオンになっている場合は、メインイベントループの現在のサイクルが完結するまで再描画が遅延されます。ウインドウの自動表示はデフォルトで有効になっています(自動表示の詳細については、“「メインイベントループ」”および“「ウインドウと描画」”を参照してください)。

NSViewdisplayメソッド群(メソッド名にそれぞれ「display」が付いているのでここではこのように呼びます)の1つを使用すると、ビューまたはビューの一部分の再描画を直ちに開始できます。これらのメソッドはさまざまな点で異なりますが、結果的にはすべて、Application Kitで以下の処理が実行されます。

  1. 無効になっているビューのフォーカスをロックする(“「フォーカスのロック」”を参照)

  2. ビューのdrawRect:メソッドを呼び出す(“「drawRect:で実行される処理」”を参照)

  3. 描画パスの最後に、ビューに関連付けられているウインドウをフラッシュする(ウインドウのバッキングストアが二重バッファ方式の場合)

ほとんどの場合、ビューを直ちに表示するのではなく、自動表示のメカニズムを使用してイベントサイクル中にビュー(またはビューの一部分)を要表示としてマークすることをお勧めします。ビューに関連付けられているNSWindowは、マークされたビューを収集し、ビュー階層内の位置の順(最上位のビューを先頭とする)に並べたリストにします。イベントサイクルの最後に、NSWindowは1回の描画パスの中でこのリストを再帰的に処理し、各ビューのフォーカスを順にロックします。そして、要表示としてマークされたビュー全体またはビューの一部分を描画するよう、ビューに要求します。すべてのビューの描画が完了すると、ウインドウがフラッシュされます(バッファ方式の場合)。

Application Kitは、アプリケーションで要表示として明示的にマークされたビュー以外に、追加のビューおよびビュー領域に対しても描画を要求する場合があります。また、対応するウインドウ領域を完全に更新するために追加のビューの描画が必要であると判断する場合があります。これは、ビューの描画においてビューの不透明度が重要だからです。ビューは自身のサーフェスのすべてを必ずしも描画する必要はありませんが、そうする必要がある場合はビュー自身を不透過として宣言する必要があります(これには、YESを返すようにisOpaqueを実装します)。ビューを要表示としてマークすると、Application Kitによってビューの不透明度がチェックされます。不透過ではない場合(つまり、一部が透明の場合)は、Application Kitによって、不透過のスーパービューが見つかるまでビュー階層が上位に向かって検索され、不透過の祖先のうち元のビューに覆われている部分が算出されます。その後、そのビューから、最初にダーティとしてマークされたビューまで、階層内のビューが順に描画されます。ビューの描画前にApplication Kitで最初の不透過な祖先を検索しないようにする必要がある場合は、いくつかの「不透明度を無視するdisplay」メソッドを使用できます(これらはTable 6-1およびTable 6-3に列挙しています)。

または、自動表示のメカニズムが起動されるまで待つのではなく、ビューやそのサブビューの一部分を要表示としてマークした後、それらを一度に再描画することもできます。NSViewのdisplayメソッド群のうち、この機能を提供するものは名前がすべてdisplayIfNeeded...で始まります。displayまたはdisplayRect:メッセージを個々のビューに送信しても直ちに表示されますが、これらのメソッドを使用したほうが効率的です。

Table 6-1は、個々のビューまたはビューのリージョンを直ちに表示するためのNSView displayメソッドを示します。

Table 6-1  NSViewのdisplayメソッド(即時表示)

表示領域と不透明度

displayメソッド

ビュー全体

display

ビューの一部分

displayRect:

ビュー全体(不透明度を無視)

なし

ビューの一部分(不透明度を無視)

displayRectIgnoringOpacity:

Table 6-2は、自動表示機能を使用して再描画するようにビューまたはビューのリージョンをマークするメソッドの一覧を示します。

Table 6-2  NSViewのdisplayメソッド(遅延表示)

表示領域

displayメソッド

ビュー全体

setNeedsDisplay:

ビューの一部分

setNeedsDisplayInRect:

Table 6-3は、Table 6-2に示したメソッドを使用して無効にされたビュー(またはビューの一部分)を強制的に即時表示するメソッドの一覧を示します。

Table 6-3  NSViewのdisplayメソッド(マークされたビューの即時表示)

表示領域と不透明度

displayメソッド

ビュー全体

displayIfNeeded

ビューの一部分

displayIfNeededInRect:

ビュー全体(不透明度を無視)

displayIfNeededIgnoringOpacity

ビューの一部分(不透明度を無視)

displayIfNeededInRectIgnoringOpacity:

処理を繰り返す場合、各ビューを直ちに表示する方法は自動表示機能を使用する方法よりも効率が悪くなり、ビューのうちマークされた部分だけを直ちに表示する方法はその中間くらいの効率となります。また、ビュー全体をダーティとマークするよりも、ビューの領域をダーティとマークするほうが、通常は効率が良くなります。displayメソッド群はアプリケーション開発の便宜のためにあります。ビューは、フォーカスをロックし、ビュー自身を描画した後、フォーカスのロックを解除できます。しかし、この方法はコンテンツをタイマーコールバックに応じてアニメーション表示する場合など、特定の場合にのみお勧めします。通常は、Application Kitの表示メカニズムを避けないようにしてください。

フォーカスのロック

Application Kit(または自分のコード)によってビューのフォーカスがロックされると、NSViewによって以下の準備手順が完了します。

ビューのフォーカスをロックするには、lockFocus(または関連するlockFocus...)メッセージをビューに送信します。フォーカスを持つビューで描画が完了したら、unlockFocusをビューに送信してフォーカスのロックを解除します。drawRect:メッセージをビューに送信した場合は、Application Kitによってフォーカスのロックとロック解除が自動的に行われます。

フォーカスを持つビューとは、現在描画しようとしているビューのことです。ウインドウはすべてウインドウグラフィックコンテキストを持っています。ウインドウグラフィックスコンテキストはウインドウサーバの描画対象を定義するものです。このグラフィックスコンテキストには1つ以上のグラフィック状態が含まれており、それぞれの状態によって個々のビューの描画操作が分離されます。このうち、現在のグラフィック状態には、直前にフォーカスを得たビューの有効な座標系その他の描画パラメータが含まれています。

グラフィック状態には現在の変形行列が含まれています。変形行列は、回転、拡大縮小、変換の各操作によって、ある座標空間の点を別の座標空間にマップするために使用される数学的な構成要素です。グラフィック状態はまた、画像をレンダリングする際に描画操作から参照することのできる現在のクリッピング領域その他のパラメータも定義します。次のパラメータがあります。

あるビューがフォーカスを持っているときに別のビューのフォーカスをロックすることも可能です。実際、Application Kitは描画パス中にこのようなロックを行います。ビューはそれぞれ、自身の座標系をスーパービューの座標系を変換したものとして追跡しているので、通常はそのスーパービューの後にフォーカスを受け取ります。無効になっているビューのグループでは、Application Kitによって最上位のビューのフォーカスがロックされた後に、ビュー階層の下位に向かって順にロックされ、ネストされた状態でlockFocusを順次呼び出します。各ビューのフォーカスが順にロックされていく過程で、グラフィックコンテキストによって管理されているスタックに、現在のグラフィック状態が保存されます( Figure 6-18を参照)。ビューのフォーカスのロックが解除されると、スタックの先頭にあるグラフィック状態が「ポップ」され(取り出され)、現在のグラフィック状態として復元されます。


Figure 6-18  ネストされた、フォーカスを持つビューと、グラフィック状態スタック

Figure 6-18 ネストされた、フォーカスを持つビューと、グラフィック状態スタック

drawRect:で起きること

Application Kitは、ビューのフォーカスをロックした後、 drawRect:メッセージをビューに送信します。ビューのクラスは、ビューを描画するためにこのメソッドを実装しています。drawRect:に渡される矩形は、ビューの座標系内で描画する必要のある領域を定義します。この矩形は、ビューの境界に対応する場合もあれば、対応しない場合もあります。たとえば、無効としてマークされたビューのすべての矩形リージョンの和集合であったり、そのスーパーセットであったりするかもしれません。

描画の命令とデータをウインドウサーバに送信することはサーバに負担をかけるため、可能な限り避ける必要があります。描画が最終的に表示されないのであれば、なおさらです。Application Kitは、主要な最適化処理として、特に複雑な描画を行う場合に描画領域を限定する機能を備えています。ビューは、ビュー全体を描画することを選ぶか(最も効率の悪い方法)、または、渡された矩形によって定義される領域を描画できます。ビューの描画手順として、さらに効率的である可能性のある手順としては、無効化になっているリージョンのリストを(NSViewのメソッドgetRectsBeingDrawn:count:を通じて)取得し、それらの各リージョンを選択的に順に描画する方法があります。

ビュークラスのdrawRect:の実装では、ウインドウサーバに渡す必要のある描画の命令とデータを指定する、各種の関数やメソッドを呼び出しています。Application Kitでは以下に示す上位レベルの描画関数およびメソッドが用意されています。

Application Kitではこれらのメソッドや関数が、Core Graphics(Quartz)の関数および型を使用して実装されています。また、ビューでは自分自身を描画する際にこれらのCore Graphics関数をネイティブに使用することもできます。これらのQuartzクライアントライブラリ関数はウインドウサーバのレンダリング演算子に直接対応付けられており、最終的に、ウインドウ内の描画においてウインドウのバッキングストアの一部となるラスタ(ビットマップ)画像が得られます。

スレッドと描画

ビューの描画は必ずしもメインスレッドで実行しなければならないわけではありません。アプリケーションの各スレッドで、ビューのフォーカスをロックして描画を行うことができます。ただし、以下の制限があります。

ビューとプリント

ビューはCocoaのプリントアーキテクチャの基礎になっています。画面に表示する内容を提供するのとまったく同様に、プリントする内容を提供します。全般の手順は同じで、Application Kitによってビューのフォーカスがロックされ、ビューのdrawRect:メソッドが呼び出されて、プリント可能な内容がビューによって描画された後、フォーカスのロックが解除されます。ビューのprint:メソッドを呼び出すことによって、ビューに対して自身をプリントするよう指示できます。

ビューとイベント

ビューは、マウスクリックやキー押下などのほとんどのユーザイベントに直接応答する、アプリケーション内のオブジェクトです。ビューはほとんど常に、ユーザイベントの発生元となるサーフェスを提供するオブジェクトです。したがって、これらのオブジェクトにはイベントメッセージを処理するための機会が一番最初に与えられます。

“「ウインドウとイベント処理」”で説明したように、ウインドウは、イベントを受信する必要のあるビュー階層内のビューに、ユーザイベントを(イベントメッセージとして)転送します。マウスイベントの場合、ウインドウはイベントが発生したビューにメッセージを送信します。キーイベントの場合、ウインドウは自身のFirst Responderにメッセージを送信します。通常、最初のレスポンダはキーフォーカスを持つビューです。キーイベントを受信するためには、最初のレスポンダとなるステータスを受け入れることをビューで宣言する必要があります(つまり、NSResponderのメソッドacceptsFirstResponderを、YESを返すようにオーバーライドします)。

ビューはレスポンダオブジェクトであり、したがってNSResponderクラスのプログラムインターフェイスを継承しています。イベントメッセージによって、このクラスに宣言されているメソッドが呼び出されます。そのようなメッセージの例としては、mouseDown:mouseMoved:keyUp:などがあります。イベントを処理するため、ビューのクラスではNSResponderの適切なメソッドを実装する必要があります。実装においては、渡されたNSEventオブジェクト(イベントに関する情報がカプセル化されています)を調べ、そこから処理を進めることができます。ビューでイベントを処理しない場合は、レスポンダチェーンで上位にある次のレスポンダ(通常はスーパービュー)に、イベントを処理するための機会が与えられます。“「レスポンダとレスポンダチェーン」”では、レスポンダについて説明しているほか、レスポンダチェーンでイベントが上位に向かって順に渡される仕組みについて説明しています。

ビューはまた、アクションメッセージに関して重要な役割を果たします。多くの場合、これらのアクションメッセージはNSControlオブジェクトに送信されるイベントメッセージとして発信されます。コントロールオブジェクトではこれらのメッセージを処理するときにアクションメッセージをターゲットオブジェクトに送信します。ターゲットが指定されていない場合は、アプリケーションは、レスポンダチェーンの上位に向かって、アクションメッセージに応答できるオブジェクトを探します。NSControlオブジェクトと、それらが使用するNSCellオブジェクトの詳細については、“「コントロールとメニュー」”を参照してください。



< Previous PageNext Page >


Last updated: 2006-05-23




Did this document help you?
Yes: Tell us what works for you.

It’s good, but: Report typos, inaccuracies, and so forth.

It wasn’t helpful: Tell us what would have helped.
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