13 KiB
楽しいプログラミング 《第5回》
明日から旅行に行きます。サンフランシスコ1週間。海外はおろか、いわゆる長期旅行としても修学旅行以来です。もちろん飛行機も初めて。しかし・・・、なんなんだ、この盛り上がりのなさは。小学校の遠足でさえ、もっとわくわくしたぞ。まぁ、「一度くらい海外旅行してハクをつけよう」などという不純な動機ですから、いたしかたないかも。そんな事考えてるようじゃ、プログラマとしての老い先も短いですね。そういえば、旅行といえば、カメラが必要でした。考えもしなかったなぁ。
■ Turbo Vision
前回、VZの「STD.INC」の解説でお茶を濁した反省に基づき、今回はひと月みっちり勉強して、Turbo Visionについて書こうと思っていたのですが・・・。今回もまた反省しなくちゃ(^_^;)。
はなから、「Turbo VisionにおけるOOPなGUIの構築法」などという解説が書けるとは思ってもいません。将来的にも、私自身はPascalを使うつもりはありませんから、詳細な言語仕様について読むつもりもありませんでした。しかし、これから、新しいアプリケーション(ユーティリティ、ゲームを問わず)を作っていこうという者にとって、「OOPなGUI作法」というのは避けて通れない課題です。Turbo Visionは、これに対する一つの解答であり、とにもかくにもTurbo Pascal6.0のIDE自身がTurbo Visionで書かれているという実績は、何物にも得難い説得力を持ちます。
そして、もうひとつの方向性は、Windowsです。Turbo Visionはご承知のとおりテキストベースのウインドウ環境です。しかし、「GUIの構築法」という視点で捉えれば、Turbo C++、Turbo Pascal6.0のIDEレベルになると、テキストかグラフィックスかはあまり問題ではありません。誰もが待ち望んでいるOOPなWindowsの開発環境。ボーランドが近い将来、Turbo C++をWindowsへ指向してきた時、そのベースとなるクラスライブラリは、果たしてTurbo Visionライクなものなのでしょうか? 本稿が、その答えを得るための何等かの指針となれば幸いです。
■ 当面の興味
それにしてもユーザー・インターフェイス・クラスライブラリの仕様は大きい。テキストベースでこのボリュームでは、本格的なGUIとなるといったいどういう事になるのか・・・。それだけに、どのクラスライブラリと心中するかの選択は重要です。
私事で恐縮なのですが、おいおい、テキストベース、グラフィックベースを問わず、マウス・ウインドウ指向のアプリケーションを作っていきます(いつから言ってるんだか・・・)。この場合、「ターゲットはWindows」というように見切れれば、何も迷いはないのですが、それはまだ時期尚早でしょう。そもそも、WindowsSDKは、まだC++ベースではありません。とすると、当面は自前のウインドウ・マネージャを用意しなくてはなりません。とはいえ、本格的なものをゼロから作っていたのでは、できた頃には恐らくWindowsが普及してしまっています。
このジレンマを回避するために、当面、オーバーラップ・ウインドウのクリッピング処理等の複雑な部分は、できる限り簡素化あるいは省略します。そのため、フルスクリーンベースの使用を前提とし、その上で以下のような各種パーツを構築します。
- プルダウンメニュー
- ダイアログボックス
- スクローラ、ボタン等のアイテム
とりあえず、実用的なクラスライブラリ構築のための手始めとしては、この辺が適当ではないでしょうか。
さて、このようなシステムを設計する場合に、以前から重要だと考えてきた事項が2つあります。
- サイズ、座標指定の排除
- コードとリソースの分離
これらをTurbo Visionではどう実現しているか、それも大変興味があります。では、順番に見ていきましょう。
■ サイズ、座標指定の排除
以前に簡単なGUIアプリケーションを作っていた際、サイズ、表示座標は、640×400ドットのスクリーンサイズに基づいて、すべてコード中に記述していました。しかし、これはとんでもない労力を必要とします。まず、「だいたいこんなものだろう」という値を適当に指定します。実行して画面を表示します。まぁ、重なったり、はみ出したり、小さすぎたり。全体のバランスも考慮して、まさしく「トライ&ゴー」で適当な値が見つかるまで、エディット・コンパイルを繰り返すわけです。
こんな事をやっていてはいけない。その時痛切に感じましたが、とりあえずソフトを作ってしまう事が先決です。根本的な対策を講じることなく、うやむやになってしまいました。
MS-Windowsでは、このような手間を省くため、リソース・エディタを用いて、ウインドウ上でパーツを表示しつつ位置、サイズをエディットし、その結果をリソース・ファイルとして保存します。さらに、これをリソース・コンパイラでコンパイルし、コード本体とリンクして、実行ファイルを作成します。この方法は確かに一歩進んでいます。しかし、
- リソース・エディタで編集しなくてはならない。
- リソースをユーザサイドでカスタマイズする事はできない。
等の不満な点はあります。
さて、Turbo Visionではどうでしょう。私がマニュアルを読んだ範囲では、この座標指定の排除に関するアプローチは、ほとんど見られません。基本的には、矩形(Rectangule)の4つの座標を保持するTRectクラスに対して、
var
R: TRect;
...
R.Assign(0,5,10,15);
といった具合に、「top-left, bottom-right」の座標を指定するのみです。この「R」を、各種パーツのサイズ、表示座標として渡していくわけです。
ただし次のように、表示する親ウインドウを取得するメソッドは用意されています。
GetExtent(R);
これを用いて、親ウインドウの上端1行分の矩形、親ウインドウよりひと回り小さい矩形等を表すことができます。
GetExtent(R);
R.B.Y := R.A.Y + 1; { A,B: Tpoint }
GetExtent(R);
R.Grow(-1, -1);
余談ですが、どうして矩形を表現する際、2点の座標を指定するのでしょう。「top-leftの座標と矩形のサイズ」という方が、私は好きです。BGIを意識したのでしょうか。
座標の指定で、「Assign」(割り当てる)というメソッド名が使われています。これを一歩すすめて、自動的に「Alignment」(整頓)させてしまう事ができないか、というのが、私の希望です。いわば「Auto Alignment」。ウインドウ上に各種パーツを配置する場合を想定してください。単にパーツの位置関係だけを規定し、右寄せ、左寄せ、センタリング等の割り付けを指定すれば、パーツの座標、全体のウインドウのサイズも決まってしまうような気がしませんか? もしこれが実現すれば、たいへん便利な事この上ありません。
- リソース・エディタを用いずとも、簡単にリソースが記述できる。
- メッセージを変更しても、ウインドウサイズを変更する必要はない。
- 実行中にフォントサイズを変更しても、動的に再配置される。
- 解像度に依存しないコードが書ける。
このように、プログラムから、イミディエートの絶対座標、ドット・サイズ情報を排除する事は、(完全には無理としても)GUIプログラミングを簡便にするためには欠かせないテクニックだと思います。
■ コードとリソースの分離
GUIプログラミングでいうところの「リソース」とは、すなわちユーザ・インターフェイス記述コードを指します。これは、使用環境、ユーザの嗜好によって、いかようにも変わりますから、プログラム本体とは分離し、ユーザサイドでカスタマイズできることが望ましいと考えます。では、リソースはどのような形態で実行コードと関連づけるべきでしょうか。
・リソースは別ファイルとし、実行時に必要な部分を読み込む。
・必要ならば、リソースをEXEファイルの末尾に付加することもできる。
・ユーザには、リソースのソースファイルと、リソース・コンパイラを提供する。
・あるいは、EXEファイルのリソース部のカスタマイザのみ提供する。(これは汎用ツールである)
このような事柄を念頭において、Turbo Visionのユーザ・インターフェイス記述コード、リソースについて見ていきましょう。
次のリストは、Turbo Visionによるプルダウンメニューの記述例です。
MenuBar := New(PMenuBar, Init(R, NewMenu(
NewSubMenu('~F~ile', hcNoContext, NewMenu(
NewItem('~O~pen', 'F2', kbF2, cmFileOpen, hcNoContext,
NewItem('~C~lose', 'F3', kbF3, cmFileClose, hcNoContext,
NewLine(
NewItem('E~x~it', 'Alt-X', kbAltX, cmExit, hcNoContext,
nil))))),
NewSubMenu('~E~dit', hcNoContext, NewMenu(
NewItem('~C~ut', 'F4', kbF4, cmCut, hcNoContext,
NewItem('C~o~py', 'F5', kbF5, cmCopy, hcNoContext,
NewItem('~P~aste', 'F6', kbF6, cmPaste, hcNoContext,
nil)))),
nil))
)));
なんだかものすごい記述法です。よく見ると、併記してある関数が実はネストしている事に気付いて、二度驚きます。どうして素直に構造体(Pascalではレコードですか)の配列として定義しないのでしょう。
余談ですが、このリストの「cm...
」というシンボルは、「コマンド」と呼ばれ、プログラムの中で一意に定まる定数です。各メニュールーチンは、イベントとして特定の「コマンド」を受け取る事で実行されます。
ラジオボタンのようなグループ化されたアイテムも、同様の記述をしますが、プッシュボタンのような独立したアイテムは、そうでもありません。
R.Assign(...);
Insert(New(PButton, Init(R, '~O~K', cmOK, bfDefault)));
R.Assign(...);
Insert(New(PButton, Init(R, 'Cancel', cmCancel, bfNormal)));
こんな具合に一つ一つインサートしていきます。
この辺まで読み進んで、「リソース」という概念のかけらも感じられなかったため、いささか閉口してきました。しかし、最後にちゃんと「Resources」という章があるではないですか。いったいこれをどういう具合に「リソース」として分離するのだろうか。リソース・コンパイラも見当たらないし。この答えは、意外とあっけないものでした。
- リソースを生成するコードを書く。
- コードをコンパイルして実行ファイルを作る。
- これを実行させると、リソース・ファイルが作成される。
というわけです。アプリケーション側には、リソース・ファイルのローダを加えます。この方法は確かに簡便で効果的です。リソース・コンパイラも必要ありません。コンパイラをもったユーザには、リソース生成部のソースのみ配布すれば、ユーザカスタマイズもできます。
リソースのアクセスには「キー文字列」を用いる方法と、文字列リストを「番号」で参照する方法があるようです。
このあたりを検討した限りでは、Turbo Visionは、テキストベースとしては極めて実用的なクラスライブラリだといえます。しかし、リソースの記述方法、グラフィックスへの移行性の欠如からみて、来るべきC++、Windowsベースのクラスライブライが、Turbo Visionとの互換性を考慮する可能性は低いと思われます。ではいったいどんな仕様になるのでしょう。
(雑誌「PC POWER 1992年11月号」掲載)