レッスン19

grDemoの内幕

【以下【】の中は訳者が付け足したものです。】

グラフィックデモンストレーションプログラム(grDemo)の内部の動作を説明しますが、それを始める前に、あなたはその基本的な動作に慣れておく必要があります。まず、‘grDemo’ソースファイルの全行を印刷しましょう。このファイルは‘demo folder’に置かれています。 このレッスンでの議論を理解するには、ソースコードリストを追いかける必要があります。以下のファイルを手元に印刷して持っておくと役に立つでしょう:zWindowmod.txt (windowmod.txt), zWindow+ (6Window+), zCtl (6Ctl), View, scroller そしてzQD (6QD) 【()内は68k Mops】

次にgrDemoをMops辞書にロードするために、Mops.dic (68k Mops)かPowerMops (PPC)アイコンをダブルクリックしてMops辞書をメモリー内にロードします。それから、‘Load ...’をFileメニューから選択します。ダイアローグが現れたなら、grDemoを選んでそれを開きます。 このファイルは、必要なファイルに対するNEEDコマンドを含んでおり、それらのファイルは自動的にロードされます。各ファイルがロードされる毎に、何がロードされたかを知らせるメッセージが表示されるでしょう。すべてのファイルがロードされたなら(Mopsプロンプトが点滅する状態になります)、GOと打ち込んでください。


するとプログラム(私達は‘Curves’と呼んでいます)が始まります。スクロールバーを動かしたり、Graphicsメニューから違うルーチンを選んだりして、実験しましょう。

以下、仕上げとなるいくつかのレッスンの中で、このプログラムの様々な部分を説明しますが、それにともなって、Macintoshツールボックスの多くの特徴が明らかにされることになるでしょう。これは決してInside Macintosh (ないしCarbon documentation)の代わりになるものではありませんが、それでも、Mopsでプログラミングする際にあなたが利用できる数多くのオプションを吟味することができるでしょう。また、これ以外のアプリケーションをデザインするための手引きとするのに十分なものを、ここでみることができるでしょう。

このプログラムを説明する前に、それがどのような結果を必要としているのかを理解しておくことは重要です。これはまさに、プログラムを書き始める前に、そのプログラムに何をして欲しいのかを知ることが必須であるというのと同じことです。このデモンストレーションプログラムは、メニューや(スクロールバーのような)コントロール、それに、様々なグラフィックルーチンが表示される区画された領域を持つウィンドウといった、シンプルな例を含んでいます。ウィンドウ内に表示される図像はTurtleデモで定義されたもので、以前のいくつかのレッスンで説明しました。

このプログラムをあなた自身がデザインするとすれば、次のような二つの基本的な問いを自問すべきことになるでしょう:

このプログラムはどのような種類のオブジェクトを持つことになるだろうか?どのようなクラスを定義する必要があるだろうか?
何がスクリーン上に表示されることになるだろうか?
第一の問いはプログラムの内部的な働きの側により一層関連していますが、第二の問いは‘対人インターフェイス’の側面に関連しています。もちろん、これら二つの問いは相互に関連していますが、初めにはそれらを別々にみることが有益であることがしばしばあります。

わたしたちのデモプログラムの場合、内部的働きの問題は既に大部分答えがでています。というのは、前のいくつかのレッスンで展開したルーチンを利用するからです。しかし、インターフェイスの問題は残っており、たくさんの作業がここで成されなければなりません。 とはいうものの、鬱陶しくなるような細部については、その大部分はMopsが既に手配してくれていることに気付くことでしょう。

Views(ビュー)

スクリーン上に現れる何かの外見について考えるとき、難しい作業の大部分をしてくれるMopsクラスがViewクラスです。本質的には、ビュー(View)とは、ウィンドウ内の長方形領域であって、そこに何かを表示するもの、です。ウィンドウそれ自体はビューではありませんが、ウィンドウはタイトルバーを除く全領域を覆う特別なビューを一つ持っています。このビューは、そのウィンドウのContViewと呼ばれます(というのは、それはそのウィンドウの内容(contents)領域全体をおおうからです)。ウィンドウに表示されるその他のすべてのものは、あるビューの中に表示されなければなりません。
クラスViewは、各ビューの大きさや位置を設定したり、クリックされたときあるいは描画が起ったときに為すべきことをコントロールしたりすることを非常に容易にしてくれる、たくさんの特性を持っています。

ビューは階層的です。つまり、ビューは他のビューの中に属することができ(また通常そうなってい)ます。別のビューを含んでいるビューは親ビューと呼び、そのビューは子ビューをもっている、といいます。Newton【かつてAppleから出ていた先進的PDA。時期尚早で失敗だったといわれているようです。】プログラミングの経験がおありなら、この用語法はよくご存知でしょう。実際、Mopsビューの特性の多くはむしろなじみ深いものに見えることを喜んでいただけると思います。

ビューコントロールを特定するために、Curvesウィンドウをまたみることにしましょう。


このウィンドウは、その中に図像が描画される長方形領域を持っています — 明らかに、これはビューといえるでしょう。また三つのスクロールバーがあり、それぞれがその下にデジタルディスプレイを持っています。このスクロールバーもビューであり、デジタルディスプレイもまたビューとなります。

ビューの位置決め

ここまでは良いでしょう。次は、これらのビューがどのようにして位置決めされるのかも見る必要があります。明らかに、各スクロールバーに属するデジタルディスプレイは、たとえスクロールバーがウィンドウ内のどこか別の場所に行ってしまうことを認めたとしても、なお、そのスクロールバーの下に止まるべきです。これを実現する最も単純な方法は、さらにいくつかのビューをつくり出すことです。スクロールバーとそのデジタルディスプレイがともに一つの親の子であるなら、それらを一緒に動かすことは容易になります。ですから、わたしたちは、このデモプログラムでは、三つの"Indicator"ビューを定義し、各インディケーターにその子供として一つのスクロールバーと一つのデジタルディスプレイを持たせています。

ビューはもう一つあって、それはこのウィンドウのcontView – ウィンドウ領域の全体を覆うビュー – です。

したがって、全部で11個のビューがあることになります。contViewはトップレベルにあります。それから、図像領域と三つのインディケーターが次のレベルになります—これらはcontViewの子供です。それから、三つのインディケーターの各々が二つの子供—スクロールバーとデジタルディスプレイ—を持っています。

ビューの位置と大きさは、その境界長方形 – viewRect – で定義されます。しかし、プログラムにおいては、通常はviewRectを直接に設定することはないでしょう(そうしなければならないときには出来ないわけではありませんが)。通常は、そのビューの親か同胞(siblings)に相対的に、この長方形の四つ辺を、一連のオプションとともに特定することになるでしょう。このオプションは四つの辺に対して独立に設定することができます。

この仕組みもまたNewtonプログラマーにはよく知られたものでしょう。ですから、わたしたちが提供している位置揃えオプションもまた、いくつか追加的なものはありますが、その大部分は見慣れたものでしょう。追加したものの一つには、各ビューごとに、二つ(横と縦)だけではなくて、各辺ごとに一つの、四つの位置揃え値を与えたことがあります。—これは、MacにおいてはNewtonにおけるよりも、プログラム走行中にビューがリサイズされる公算が高いという事実を反映したものです。

可能な位置揃え値はこのようになります:

名前 意味 説明
parLeft parent left 境界はその親の左端から測られます。
parRight parent right 境界はその親の右端から測られます。
parCenter parent center 境界はその親の中央から測られます。 parCenterとparPropは、自明な意味で縦方向にも利用できることに注意しましょう。
parProp parent proportional 境界値は、10000を基準として、その親の幅との比(x:10000)に当たる距離を表します。
parTop parent top 境界はその親の上端から測られます。
parBottom parent bottom 境界はその親の下端から測られます。
sibLeft sibling left 境界は直前の同胞【同じ親の子】の左端から測られます。
sibRight sibling right 境界は直前の同胞の右端から測られます。
sibTop sibling top 境界は直前の同胞の上辺から測られます。
sibBottom sibling bottom 境界は直前の同胞の底辺から測られます。
myLeft my left (右端境界のみ)—このビューの左端から測られるので、ビューの幅を直接に特定することになります。
myTop my top (底辺境界のみ)—このビューの上辺から測られるので、ビューの高さを直接に特定することになります。

デフォルト値はparLeft、parTopです。これは単純に、子ビューの境界はその親の左上隅から測られることを意味します。

この仕組みは複雑に見えるかも知れませんが、実際には全く簡単に使えます。大抵の状況で、境界と位置揃えは、ビューひとつずつについてコンパイル時に設定できます(setJust:とsetBounds:メッセージを用います)し、あなたのプログラムはそれ以外のアクションをとる必要はないでしょう — ビューは、その親が動くときにはいつでも、それに合わせて自分自身を自動的に正しい位置に移動し続けるでしょう。

わたしたちがgrDemoアプリケーションの中でビューにこれらの値をどのように設定したのかを見ることにしましょう。IndicatorクラスのClassInit:メソッドをみてください:
:m CLASSINIT:
     parCenter   parTop      parCenter   parBottom   setJust: theVscroll
     -8          0           8           -20         setBounds: theVscroll
     parCenter   parBottom   parCenter   parBottom   setJust: theReadout
     -12         -16         12          0           setBounds: theReadout
     classinit: super
;m
ここでは、Indicatorの子ビュー、つまり、縦方向のスクロールバーであるtheVscrollとデジタルディスプレイtheReadoutのボックスの位置を決めています。

setJust:とsetBounds:メソッドはどちらも四つのパラメターをとり、通常の順序通り、左、上、右、下の順となっていることに注意してください、

横方向には、どちらの子ビューもIndicator内の中央に合わせたいと思います(theReadoutはtheVscrollの直下になるでしょう)。スクロールバーの幅は常に16ピクセルですから、左右の揃えをparCenterに設定し、その水平境界を(-8,8)とします。 値読み出しボックスは24ピクセル幅ですから、ここでもまた左右の揃えはparCenterに設定し、水平境界の方は(-12,12)とします。

縦方向には、スクロールバーの上端はindicatorの上端に一致するようにし、下端はindicatorの下端から固定20ピクセル分上方にして、値読み出しボックスの場所を空けておきたいと思います。そこで、上端揃えはparTopとし上端境界値は0に設定します。そして、下端揃えはparBottomにし、境界値は-20とします。値読み出しボックスは16ピクセルの固定した高さをもち、いつも正しくindicatorの下端にあることになるでしょう。そこで、上端および下端の揃えをどちらもparBottomとし、境界値は、(-16,0)とします。

デモウィンドウをリサイズしてみれば、これらの設定の結果が分かるでしょう。縦方向のスクロールバーはウィンドウの高さに合わせて伸び縮みするでしょう。このやり方のおかげで、一つより多いインディケーターをもつことが容易になります。今のところ、わたしたちは三つのインディケーターをもっていますが、もっと増やすのも容易でしょう。

図像表示ビューであるdPane、三つのインディケータ自体、およびウィンドウのcontViewであるdViewの場合は、わたしたちは単にそれらを辞書内に宣言しています。これらは確かにgrWindのインスタンス変数とすることもできました。というのは、これらは実際にこのgeWindに属しているからです。このやり方は、たった一つではなく、たくさんのgrWindオブジェクトを持つ場合には有利でしょう。ここの例では、ひとつしかgrWindオブジェクトを持たないのですから、これらのビューを通常のオブジェクトとして辞書内に宣言する方が少しだけ簡単です。

これは、プログラムをデザインする際に頻繁に起る類のトレードオフの一例です。Mopsにおいては、しかし、プログラムの多くの部分が書かれた後でも、様々にデザインを変更することもあまり難しくはありません。これはオブジェクト指向プログラミングの利点の一つです。

わたしたちはこれらのビューを辞書内に宣言したのですから、grWindのCLASSINIT:メソッドでそれらを設定する必要はありません。コンパイル時に直接に設定することができます。この設定をしているコードを見れば、わたしたちがこれらのビューをどのように配置しているのかを点検することができます。わたしたちはまた、他の選択肢となりうるコードも書いた上で、コメントアウトしています。代わりにこの行を利用すれば、インディケーターは、その結果として、ウィンドウの右側にではなくて、下側に均等間隔に並んで配置されるでしょう。parProp位置揃えを用いて均等間隔を達成するやり方に注意してください。

ビューの描画–DRAW:メソッド

スクリーンの座標はビューの左上の角が(0,0)になるように設定されているでしょう。Macの用語法ではビューに相対的な原点の設定と呼びます。

クリップ領域はビューに一致するように設定されることになります。ですから、このビューの外に描画することはできますが、スクリーン上にはそれは現れません。これは物事を非常に単純化してくれます。というのは、その時点でビューの正確なサイズがどうなっているかを気にすることなく、ビュー内に描画することができるからです(加えて、当然ですが、そのサイズはプログラム走行中に変化するのですから)。
MopsはRectオブジェクトであるtempRectを持っています。これはたくさんのことに利用されます。DRAW:がビュー上に呼び出されたとき、tempRectはそのビューの境界に一致されるように設定されます。これは非常に有用となり得ます。このデモにおいては、わたしたちはこの特性を用いて、グラフィックの枠を描画し、また値読み出し領域のボックスも描画しています。
ReadoutクラスのDRAW:メソッドを見ましょう。tempRectが、局所座標(ここで有効になっているのはこれですが)において、そのビューの境界になるように設定されていることを、わたしたちがどのように利用しているかに注意してください。 ここでは、わたしたちは前に表示されていた数字を消し、そのビューの周りにボックスを描画しています。次に、数字がおかれるべき場所である‘カーソル’を、その長方形の左上角から、3ピクセル過ぎたところで10ピクセル下がったところにおいています。

さて、新しい数字は、3桁分の領域に印字されます。まず、textmodeを1に、textsizeを9に、textfontを1番に設定します。Textmodeは、スクリーン上に数字を描くペンが、その下地スクリーンの色にどのように反応するかを決めます。このモードを1に設定すると、ペンは白い背景には黒で描きます。Textsizeの数値は、MacWriteフォントメニューで選ぶようなサイズと同じ、実際のフォントサイズです。Textsizeを9に設定すると9ポイントタイプが呼び出されます。

Textfont番号は少し説明する必要があります。Macのツールボックスでは、フォントにはID番号が付されています【QuickDrawのフォントIDになります】。いくつか、よく使われるものを上げると、次の通りです:

SystemFont (Chicago) = 0
ApplicationFont (Geneva) = 1
New York = 2
Geneva = 3
Monaco = 4
Times = 20
ヒラギノ角ゴシック = -31551
ヒラギノ明朝 = -28671
Osaka = 16384

このリストの中ではアプリケーションフォントはGenevaと一致しており、これが【英語での】デフォルトですが、プログラムの中には特別なアプリケーションフォントがそこに挿入されているものもあります。わたしたちはそれをしていないので、わたしたちのアプリケーションのフォントはGenevaになるでしょう。grDemoの値読み出しボックス内の数字のフォントについては、Genevaフォントが選ばれているわけではありません【デフォルトになっているだけです】。Genevaフォントを確実に使いたいのであれば、ID番号3を用いることになるでしょう。そうすればいつもGenevaになります。

次は、IndicatorクラスのDRAW:メソッドを見てみましょう。それは、縦スクロールバーから現在の値を取り、それから、その値をReadoutのPUT:メソッドを通じてReadoutビューに送ります。最後に (DRAW): super を呼び出して、何であれそのスーパークラスが描画のためにすべきことを実行します。後でわかるように、ここで DARW: super を使わないのは、DRAW:によって為されるクリップの設定など、他の自動的に行われる動作のせいです。これらの動作は、このビューに対しては既に実施されているので、再び行う必要はありません。また、再度行う必要のないことの中には、Readoutビューに対してDRAW:を呼ぶことも含まれていることに注意しましょう。というのは、Readoutは子ビューであるので、DRAW:を自動的に受け取ることになるからです。

三つのスクロールバーはVScrollクラスのオブジェクトです。これは、Control(68k Mops)またはRootCtl(PowerMops)クラスのサブクラスであり、これはさらにまたViewクラスのサブクラスです。Macのコントロールはシステムによって描画されます。これは単純に、ControlないしRootCtlクラスのDRAW:の定義で適切なシステムコールを行うようにすることで処理されています。

IndicatorクラスのNEW:メソッドは、そのビューを含むウィンドウが開いたとき、ランタイムに呼び出されます。ここでわたしたちは、このビューの子ビューがどれであるかを設定する必要があります。これはADDVIEW:メソッドで行われます。これはコンパイル時に行うことはできません。というのは、添加する子ビューのアドレスを渡す必要がありますが、この値はMopsを起動するたびに異なるものになるかも知れないからです。

チュートリアル目次へ
前へ < レッスン18 次へ > レッスン20



最終更新:2018年12月09日 22:03