プログラムを変形する
【以下、"空白"は全て"半角空白"を意味します。なお、以下【】の中は訳者が付け足したものです。】
クラスをもうひとつ付け加えます。 しかし、それはRectのサブクラスになるでしょう。 というのは、私達の目的は、丸め長方形【角の丸い長方形のことです】を描画するオブジェクトを作ることだからです。 丸め長方形は長方形と同じパラメターに加え、さらにもうひとつのパラメターが必要です。: それは、私達の長方形の角を丸める際の曲率を与える楕円のサイズです。 その楕円形の大きさは、高さと幅のピクセル長で定義されます。:
Carbon(カーボン)
フレームワークコール FrameRoundRect (これも、QuickDrawに属します)は、 これらの長さとして二つの整数 (2バイト値)を求めます。 Rectデータについてはそのアドレスを渡す(FrameRectの場合と同じです)のに対して、 幅(w)と高さ(h)については実際の値を渡すことに注意してください (Carbonフレームワークルーチンへの引数供給に関するこれ以上の議論は、 レファレンスパートの第7章を参照してください)。 楕円の長短直径は、Pointクラスの
インスタンス変数に格納すると便利です。
丸め長方形は、通常の長方形(つまり、Rectクラスによって生成されたオブジェクト) ととても共通点が多いので、 Rect クラスのサブクラスとするのが、論理的なアプローチといえます。 名前は、例えば、"RndRect"クラスとしましょう。 一つだけ追加的なインスタンス変数が必要です。"Ovalsize"と名付けましょう。 Rect クラスからの継承のおかげで、 RndRect クラスのオブジェクトは、あわせて三つのインスタンス変数を持ちます。: TopLeft, BotRight, Ovalsize です。 TopLeft と BotRight は、角が"丸められなかった"とした場合の、 RndRect の角を指しています、— つまり、各辺を延ばしていった場合の交差点です。 これらの点は、もちろん、実際にディスプレイ上に描画されるであろう丸められた角に対して、その外側にあるでしょう。
次に、このクラスは、そのオブジェクトインスタンスが受けとる楕円関連値を保管するメソッドを必要とします。 このクラスのための Ovalsize 値はPUT: メソッド(おなじみですね?)によって格納されますが、 このメソッドは、楕円関連値を初期化するのに加えて、Rect クラスから私達のクラスが継承した長方形座標点、 TopLeft および BotRight も初期化します。
最後に、このサブクラス RndRect は、このクラスから生成されたオブジェクトに格納された値に基づいて動作する DRAW: メソッドを必要とします。 この特別な DRAW: メソッドにおいては、 ^BASEは、現在のオブジェクトの"ベース"アドレスを取り出します。 つまり、メモリー中のそのオブジェクトの初めのアドレスです。 この場合、それは長方形座標のアドレスになります (これは、前レッスンを思い出せば、Rect 中にレコード【記録体、構造体ともいいます】として格納されています)。 Carbonフレームワークはこのアドレスを用いて、パラメターとして利用する値の格納場所を特定します。 次に、Ovalsize 値は、Carbonフレームワークが期待するような形でスタック上に置かれ( Point クラスの GET: メソッドを用います。)、そして適切なCarbonフレークワークルーチン( FrameRoundRect )が呼ばれて、スクリーン上への実際の描画が行われます。
このサブクラスは次のようになります。
:class RNDRECT super{ rect }
point Ovalsize
:m PUT: ( l t r b w h -- ) put: Ovalsize put: super ;m
:m DRAW: ^base get: Ovalsize FrameRoundRect ;m
:m DISP: put: self draw: self ;m
;class
このクラスで用いる DISP: メソッド定義は、スーパークラスで用いた定義によって余分なものになってしまうものではありません。 SELF は、いつでも現在のオブジェクトのアドレスを返します。 スーパークラスで SELF が用いられたときには、それは Rectに当たるアドレスを返しました。 私達のクラスでは、それは RndRectのアドレスを返します。
【この説明は、少し舌足らずのように思われます。次の囲み部分が核心です。】
注意: もしも、上でしたように DISP: メソッドを再定義しなかったとすると、 RndRect クラスの任意のインスタンスに対する DISP:メッセージは、 Rect における DISP:
メソッドの定義を用いてしまうことになり、 ひいては、Rectの PUT: とDRAW: メソッド (つまり、私達がサブクラス RndRect で定義した新しいメソッドではなくて) を呼んでしまいます。
【蛇足ですが、これは、Mopsの SELF が静的バインドになっているため、ということができます。 つまり、RectクラスのDISP:メソッドでSELFを受け手に呼び出したPUT:とDRAW:は、もうRectの定義時点でRectクラスのコード用いてコンパイルされ、固定されてしまっているので、 サブクラスRndRectで新たに定義したメソッドを呼び出したいときには、その新しい定義の後で、もう一度それらをSELFで呼び出す新しいDISP:メソッドを定義し直さないといけない、というわけです。ちょっと、先走り。クドくてすみません。】
クラスは定義されたので、オブジェクトを生成する準備は万端です。
RndRect Cynthia
前のレッスンでしたのと同じように、このオブジェクトをウィンドウ ww に描画するには、 次のようにできるでしょう。:
Window w
test: ww
set: ww
20 20 100 60 20 30 disp: Cynthia
【全部マウスでセレクトして一回でenterすれば失敗はありません。】
値 20 と 30は、丸められた角に当たる楕円の幅と高さです。 DISP: メソッドは、私達のクラスとそのスーパークラスとで定義された PUT: メソッドを用いて、 6つの値をすべてスタックから取り除き、私達のクラスで定義されたインスタンス変数とスーパークラスから継承されたインスタンス変数に格納します。 このクラスの追加がプログラム全体の構造の中でどのように作用するのかについての図式は、つぎのようになります。:
次回は、Mopsプログラミングを強力に支援するQuick Editの使い方への入門です。
【元が欠けてるんですが、本来のマニュアル計画にあわせて、QEドキュメント等を基に捏造しました(^^;;)】
最終更新:2018年12月04日 13:17