RealBasic University

このコラムはStone Table Softwareのオーナーであり、またREALbasic Developerの編集者でもあるMarc Zeedar氏により書かれたものを、著者の許可を得て翻訳したものです。この翻訳はHREM Researchにより提供されています。この日本語版へのご意見はRBU-Jまでご連絡下さい。

URL: http://www.applelinks.com/rbu/090/
INDEXに戻る

OOP University: パート 14

前回、SuperDrawプロジェクトに、polyClasspictClassの2つの新たな描画オブジェクトを導入しました。今回は、テキストオブジェクトを追加していきます。

しかし、まず先週の問題点を訂正することから始めましょう。

SuperDrawとREALbasic 5

何人かの読者が、先週のSuperDrawプロジェクトは、REALbasic 5では動作しないことを報告してくれました。まさにその通りです。REALbasic 5は前バージョンに比べて、ネーミングの問題に関してシビアになっていますので、4.5ではうまくいったものでも、RB 5ではコンパイル中にエラーメッセージを出して止まってしまいます。

今回のケースでは、問題点はdoubleClickedメソッドとdoubleClickedイベント(どちらも同名)がshapeClassオブジェクトに存在することです。私は、これはまずいのではないかと思ったのですが、REALbasicはエラーを出さずにプログラムも動いたので、問題ないと思いました。私は今回のコードを、RB 5の最終版がリリースされる直前に仕上げましたので、RB 5でテストすることはできませんでした。(将来のRBUプロジェクトでは、RB 5との互換性をお約束いたします。)

この解決策は簡単です。まずshapeClassを開き、doubleClickedイベント(メソッドの方ではありません)を、doubleClickと名前を変更してください。それから――これはとても重要です――doubleClickedメソッドを開いて、次のようにコードを変更してください:

  
doubleClick

これは、単にdoubleClickと名称が変更されたイベントを、メソッドが間違いなく呼ぶためのものです。この変更で、プログラムはREALbasic 5でもうまく動作するようになります(今回の機能拡張も含めて)。

テキスト・オブジェクトの追加

新規クラスを追加することから始めましょう(ファイルメニューの「新規クラス」)。それにtextClassと名前を付けて、supershapeClassにしてください。

それを開いて、コードを追加していきましょう。最初に、2つのプロパティを追加します(編集メニューの「新規プロパティ」):

  
text as string
textFont as string

これらのプロパティは、テキスト・オブジェクトに使用される設定項目を含むことになります。

次に、paintイベントに次のコードを入力してください:

  
if textFont = "" then
init
end if

g.textFont = textFont
g.textSize = calcTextSize(g)
g.drawString(text, left, top + g.textHeight, width)

ご覧の通り、これはテキストのフォント、サイズ、そしてテキストの描画の設定を行います。しかし、ここでは2つのメソッドが呼ばれます。ひとつはinitと呼ばれるもので、それはデフォルトのtexttextfontの値を設定します。

initという新規メソッドを追加して(編集メニューの「新規メソッド」)、次のコードを入力してください:

  
// ここで設定の初期化を行う
text = "Sample text"
textFont = "Geneva"

次に、パラメータとしてg as graphicsをもつ、整数を返すcalcTextSizeというメソッドを追加してください:

  
dim tSize, tHeight, tWidth as integer

g.textFont = textFont
tSize = 1 // はじめのサイズ
g.textSize = tSize
tHeight = g.stringHeight(text, width)
while tHeight <= height
tSize = tSize + 1
g.textSize = tSize
tHeight = g.stringHeight(text, width)
wend

// 最大のサイズ
return tSize - 1

この関数は、形状の幅と高さに合わせて、水平方向にぴったり合うような最大のテキストサイズを計算します。これは、渡されたテキストの高さをピクセル値で返す、stringHeightというREALbasicのメソッドを使用しています。我々はそのメソッドにはwidthの値も渡しているので、stringHeightはテキストの分量とテキスト領域の幅に基づいたワードラッピングを考慮に入れ、正しい行数の高さを報告します。その後、我々はボックスの高さよりも高くならないかを確認するための比較を行います。

関数はサイズ1からスタートし、テキストがはみ出すまで、サイズの値を1ずつ増大していきます。そして、最後に1を引いた数を返します(フィットしたサイズ)。

この関数は、オブジェクトの形状に合わせてテキストのサイズをできる限り大きくすることがわかったでしょう。したがって、仮にオブジェクトのサイズや形状を変化させても、テキストのサイズはそれにつれて変化します。

さて、ユーザにテキストを編集してもらう方法もなければなりません。これは簡単なダイアログボックスで行っていきます。しかし、まずdoubleClickイベントに次のコードを追加しておきましょう:

  
askTextDialog.parentObject = self
askTextDialog.editField1.text = text
askTextDialog.choosePopup(textFont)
askTextDialog.showModal

これは2、3のことを行います。まず始めに、重要な部分に当たりますが、ダイアログ・ウィンドウ内に自身のリンクを作成します。そのリンクを用いて、ダイアログはtextClassオブジェクトと通信することが可能となります。それがないと、我々はユーザがいつテキストに変更を加えたのか知る術がありません!

2番目は、編集するテキストとそのフォントを、askTextDialogに伝えます。

最後は、ダイアログを表示します。ダイアログそのもののコードは、変更された値すべてをtextClassオブジェクトに返す処理を行います。

新規ウィンドウを追加し(ファイルメニューの「新規ウィンドウ」)、次のような設定をしてください:

ウィンドウが次のような外観になるようにしてください:

ポップアップにはfontPopupと名前を付けてください。テキスト入力欄はEditField1、キャンセル用のプッシュボタンはcancelButton、OKのプッシュボタンはokButtonとなります。

それではコードに移ります。parentObject as textClassというプロパティを追加してください。このプロパティは、ダイアログを開いたtextClassオブジェクトへのポインターを保持します。

次に、choosePopupというメソッドを追加し、次のコードを入力してください:

  
sub choosePopup(theItem as string)
dim i, j, n as integer

j = -1
n = fontPopup.listCount - 1
for i = 0 to n
if fontPopup.list(i) = theItem then
j = i
exit
end if
next // i

fontPopup.listIndex = j
end sub

このメソッドは、文字列をパラメータとして取り出し、渡されたフォントを探すためにfontPopupリストを検索します。それが見つかったときは、fontPopupメニューをそのフォントに設定します。(基本的に、これはユーザがポップアップメニューでフォントを選択するのと同じことです。)

controlsの部分では、いくつかのコントロールへコードを追加しなければなりません。

cancelButtonに関しては、self.closeをコードとして追加します。

fontPopupのopenイベントには、次のコードを入力してください:

  
dim i, j, n as integer

n = FontCount - 1
for i = 0 to n
me.addRow font(i)
if parentObject <> nil then
if font(i) = parentObject.textFont then
j = i
end if
end if
next // i

me.listIndex = j

これは、RBのユーザーズ・ガイドに載っていたコードで、現在インストールされているフォントのリストをポップアップメニューに表示します。

okButtonでは、actionイベントに次のコードを入力してください:

  
if parentObject <> nil then
parentObject.text = editField1.text
parentObject.textFont = fontPopup.text
end if
self.close

理論上、parentObjectは無効(nil)になる可能性があるので、まずそれをチェックしておきます。問題なければ、それを呼び出しているオブジェクトのtexttextFont属性に設定します(parentObjectnilであると、このコードはnilObjectExceptionエラーを起こし、強制終了します)。ここでは変更(もしあれば)を、ダイアログを開くtextClassオブジェクトに返します。

もうほとんど完成しました。後はwindow1pushButtonをもうひとつ追加するだけです。それには、一番下のものを複製して、そのテキストを「New text」と変更してください。そしてindexが5であることを確認してください。

最後に、先週行ったのと同じように、ケース文をもうひとつ、drawCanvasClassのaddObjectメソッドへ追加します:

  
case 5 // text
objectList.append new textClass

これは、pushButtonを押したときに、新しいtextClassオブジェクトを作成します。

それでは、SuperDrawを実行してみてください。すべて正確に行っていれば、テキストが追加でき、移動やサイズ変更、さらにはそれを編集したりフォントを変更したりすることができるはずです:

すばらしいでしょう?今までで、様々な種類の描画要素をサポートするキャンバスを作成してきました。いくつかの基本的なものから、画像や編集可能なテキストのインポートのような高度なものまでありました。これは実際にも役に立つツールです。私は、請求書作成のプログラムを受注しましたので、請求書のレイアウト(テキスト入力欄の位置、ロゴのインポートなど)をユーザが編集できる機能を追加するために、これらのクラスを使用する予定です。

なんといっても、これはオブジェクト指向の流儀に沿って作成されているので、修正や拡張が簡単にできます。オブジェクトの追加も簡単に行えます。

重要な機能である書類の保存/読み出しに加えて、SuperDrawの完成にはいくつかの小さな機能拡張が必要です。我々は、それを次回のレッスンに行い、それをもってOOP Universityのこの部分を終了したいと思います。

今週のチュートリアルの完全なREALbasicプロジェクト(リソースを含む)を手に入れたい場合は、ここからダウンロードしてください。

次週

SuperDrawを仕上げます。

REALbasic Developer 1.5 予告編

RBDの次号は現在印刷中ですので、ここでは内緒で予告を行います!

今回のメイン特集はREALbasic 5で、それもひとつではなく、2つもの詳細な記事が掲載されます。

REAL Software社の技術者であるJoe Strout氏が、今回の新しい環境の心臓部分に当たる、新たなコンパイラーについて説明します。そして、Matt Neuburg氏が、RB5の新機能の詳細なまとめをし、あなたも知らないいくつかの秘密を明らかにします。

Joe氏はさらに、経路探索のアルゴリズムのまったく新しい利用方法を提供してくれました。明らかな使い道は、迷路で道を探し出すことですが、この記事を勉強することによって、他の多くのユーザにとっても有益なテクニックとなり得ることがわかるでしょう。

「事後分析」では、Jacob Lauritzen氏がSmartLaunchについて述べ、私はSpamfire(現在のマーケットでもっとも成功しているREALbasic製の製品)の作者であるMichael Herrick氏にインタビューしました。

他のニュースについては、私は雑誌にすこしユーモアを取り込みたかったので、Dan Wilson氏(第1.2号の表紙制作者)によるRBDのために制作されたオリジナルの漫画、Hackerを掲載することをお知らせいたします。

これは熱狂的なREALbasicプログラマーの日常を描いています。これから毎号、新しい漫画を掲載していく予定です!

さらに、コラムやトピックス、ニュースやレビューも通常通りです。まだ定期購読されていない場合は、今すぐ申し込んで、お見逃しのないように!

Letters

今週は、Joe Riceさんがめずらしい質問をしてきました:

ご無沙汰しています。また問題にぶつかりました。

私は、アプリケーションを作成するアプリケーションを書こうとしています。:)

基本的には、テンプレートの設定があり、メインのアプリケーションをひねくって、2番目の内容を変更します。私は、アプリケーションとして「保存」するにはどうすればよいのか分かりません。

よろしくお願いします。

残念ながら、あなたのやろうとしていることは複雑です。まさに、独自のコンパイラーを書こうとしています(コンパイラーはテキストコードを実行可能なマシン語に変換します)。これはREALbasicはおろか、どんな言語をもってしても簡単なことではありません。

しかし、作成するアプリの種類に応じて、いくつか選択肢があります。

第1に、あなたのアプリが、「新しい」アプリケーション内の設定あるいは情報を単純に変更するだけならば、アプリのリソース・フォークにその情報を保存しておくことで可能です。そうして、REALbasicの「アプリ エディター」が標準アプリケーションの複製を作成し、それらのリソースを編集したり変更したりすることで、「新しい」アプリケーションができあがります。たとえばこれは、組み込まれているユーザのロゴや名前や住所情報をもって新しいアプリケーションを作成する場合にうまくいきます。

これと似たもっと強力な別の方法は、テンプレートとなるアプリケーションに、アプリに必要となる要素をすべて含めてしまうことです。それは、記述ファイル(XMLファイルがよいでしょう)から動的な設定を読み出し、その要素だけを表示させます。

簡単な例として、ユーザのアプリのあるダイアログボックスが2種類あるとしましょう。それをDialogAとDialogBとします。あなたの質問では、ユーザに使用したいどちらかのダイアログを選択させて、そのダイアログで新しいアプリケーションをコンパイルします。ところが、XMLの設定ダイアログを使う場合には、テンプレートとなるアプリはどちらのオプションも含んでいます。そして、定義ファイルの設定にもとづいて、それはユーザの選択した方だけを使用するのです。

このアプローチの欠点は、テンプレートとなるアプリケーションがやや大きくなってしまうこと(アプリの可能な要素すべてを含める必要があります)ですが、ユーザの視点から見れば、その結果はカスタムのアプリケーションと同じになるでしょう。

うまくいきそうな第3のアプローチは、プラグインとしてRBScriptsを用いることです。これについては、RBU 071で説明しました。RBScriptsはRBコードの外部テキストファイルで、それはプログラムが実行されるまではコンパイルされません。これと同じアプローチを使って、RBScriptモジュールをテンプレートとなるアプリケーションにインストールすることができます。これらのスクリプトは異なる処理をすることができます。プログラムが実行されるとき、インストールされたスクリプトによって、機能の仕方が変わってくるでしょう。これによって外部からカスタマイズする方法が与えられ、テンプレートアプリを複製しながら、それが使用するスクリプトを変更することが可能になります。

あまりよい解決策がなくて申し訳ないですが、この3つのうちのいずれかが役に立つことを期待しています。

私が何か見過ごしていたり、誰かほかによいアプローチをご存じの場合は、ぜひご連絡ください!


RBU-Jの通知サービス!コラムが発表されるたびに日本語版REALbasic Universityのお知らせの emailがあなたに届きます。登録・削除は ここ から。

INDEXに戻る