RealBasic University

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

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

REALbasic の基礎 IV

今週はこの「基礎」のコラムを終了します−−皆さんにとってこのコラムを有用であったことを望みます。我々は色んなコントロールの使い方を勉強しましたので、何か得ることはあったと思います。音楽の好きな読者のために、今日はNotePlayerコントロールを見てみましょう。それと同時に、プログレスバー(progressBar)やその他のコントロールについても学習します。

REALbasicで作曲を

私はミュージシャンではありませんので、このコラムが本当の音楽を創造するとは期待しないで下さい:我々はランダムな音を出すためにNotePlayerコントロールを使うだけです。しかし、それでコントロールの使い方は判るでしょう。もしあなたが音楽が得意であれば、歌を作曲する第一歩としてこの例を使うことができるでしょう。

この例には幾つかのインターフェースが必要です。いつもように、完全なサンプルプロジェクトRBU Demoをダウンロードすることが出来ます。もし、あなたが最初からそれを作るのであれば、幾つかのものをWindow1のドラッグしてくる必要があります:1つのプッシュボタン、1つのプログレスバー、幾つかのchasingArrows、1つのnotePlayerそして1つのタイマが必要です。それらをWindow1の下の方に、次のように配置します:

notePlayerタイマは不可視の(ユーザからはそれらは見えない)コントロールですので、どこにそれらを配置しても問題にはなりません。あなたにコントロールの存在が判るように、そしてそのコントロールにコードを入力できるようにREALbasicはアイコンを示しているだけなのです。

基本的なコントロールを配置したら、PushButton1に注目しましょう。そのCaption属性を"Start Music"と設定し、次のコードをActionに入力します:

   // Disable self 
me.enabled = false

// Reset the progress bar
progressBar1.maximum = (rnd * 500) + 100

// Show chasingArrows1
chasingArrows1.visible = true

// Start a "song" playing
timer1.mode = 2

先ず最初に、ボタンを選択不能にします。これは「音楽」がなっている間にユーザが再びボタンを押せないようにしたいからです。次に、プログレスバーmaximum属性をランダムな値に初期化します:これは音楽の長さになります。

それから、chasingArrows1を可視状態にします。これはchasing arrowsに関して我々のできるほとんどのことです:それは可視の時には回転し、それ以外はなにもしません。我々はそれを処理が進行中であることを示すのに使います。それは時間を必要としますが、どれだけ掛かるかが前もってよく判らない処理の場合に有用です。(もし、処理の時間を計算できるのであれば、プログレスバーも用いてユーザにどれだけ処理が残っているかを示す方がより適切です。しかし、chasing arrowsは少なくともユーザにコンピュータがフリーズしていないことを表していますので、無いよりはましです。)

最後に、そのmode属性を2に設定してtimer1をスタートさせます。modeが0に設定されたタイマは停止します。1に設定すると、タイマに書かれたコードが1度だけ実行されて、それから停止します。modeが2に設定されると、period属性で設定された頻度で繰返し呼ばれます。(period属性はミリ秒単位ですので、1000は1秒です。この例では、私は100(すなわち、1秒間に10回)に設定しました。)

NotePlayer1progressBar1の両方ともそのなかにコードを全く持っていないことは面白いことです:それらはプログラムで設定して、ユーザと遣り取りする必要のないコントロールなのです。それで、我々は多くのコントロールを追加しましたが、コードを必要とするのはただTimer1だけです。それが持つイベントはActionですので、次のものをそこに入力しましょう:

   // Set the notePlayer1 to a random instrument 
notePlayer1.instrument = (rnd * 127) + 1

// Play a random note
notePlayer1.playNote(60, 60)

// Increment the progress bar
progressBar1.value = progressBar1.value + 1

// if we're at the end, stop
if progressBar1.value = progressBar1.maximum then
// Stop note playing
notePlayer1.playNote(60, 0)

// Turn off timer
me.mode = 0

// Hide chasingArrows1
chasingArrows1.visible = false

// Renable start button
pushButton1.enabled = true

// Reset the progress bar
progressBar1.value = 0
end if

これは実際に「音楽」を演奏するプログラム部分です。しかし、これは歌という訳ではありません -- ただ、ランダムに選んだ楽器でド音を鳴らすだけです。(楽器の番号に関してはREALbasicのオンラインヘルプを参照して下さい。)

playNoteには2つのパラメータが必要です:音程(0 から 127までの数値で、60は中間のド音)とRBが"velocity" (0 から 127)と呼ぶもの(キーの押される強さで、127に変えてプログラムを実行すれば判るでしょう)です。もし、興味があれば、プログラムで音程をランダムに選択するようにしてもいいでしょう。次のように、最初の60 を round(rnd * 127)で置き換えます:

 notePlayer1.playNote(round(rnd * 127), 60) 

次の行はprogressBar1'のvalue属性を増加しています:ここでプログレスバーの棒グラフの現在の長さが設定されています。プログレスバーコントロールがバーの比率や描画などの全ての面倒をみています -- あなたがすることは現在の位置と最大の値を設定することです。我々の場合では、maximumは演奏する全体の音程の数ですので、それぞれの演奏される音程に対してvalueを1ずつ増加させます。

最後に、「音楽」の最後に達したか(value = maximum)を調べます。そうであれば、音を出すのを止め("velocity" をゼロにする)、Timer1を止め、chasing arrowsを隠し、"Start Music" のプッシュボタンを選択可能にし、そして progressBar1をゼロにリセットします。

追記

実際のところ、NotePlayerコントロールを使って実際の音楽をつくるのはもう少し複雑です。それぞれが適切な音階と強さをもつ一連のplayNoteコマンドを単純に用ることも可能でしょう。そかし、それはあまり直感的ではありません(非常に単純な音楽はできるでしょうが)。

より良い方法は自分自身の音楽生成プログラムを書くことでしょう。それは鍵盤のインターフェイスを持っていて、あなたが演奏した音階をそれぞれのキーを押した時間だけ「記録」します。その後で、あなたは全体の音楽を再生することができます。音楽データはあなたのプログラムが解析できる形式(多分、楽器コード、音階、強さおよび長さ)ですので、それを保存して、後で再生することが可能でしょう。

もし、皆さんが興味があるようであれば、そのようなプログラムの作成をRBUプロジェクトとして考えます。希望をお知らせ下さい!

これでRBU Demoは終わりです。ご自由に切り離して、また値を変えて何が起るか実験してみて下さい。これはREALbasicの多くのコントルールを説明していますので、勉強するのに良いプロジェクトだと思います。私が説明しなかったsockets, serial コントロールや databaseQueryオブジェクトなどの幾つかの高度なコントロールがあります。それらに対しては個々の解説を将来することになるでしょう。

REALbasic の美学:コードの見栄え

今日のレッスンは種々雑多なものですので、今まで話したかったのですが、その適切な機会が無かったことについて、この機会に話したいと思います:それはコードの美学です。

ご存知のように、REALbasicは自動的にある種のフォーマットをしてくれます。例えば、REALbasicはループとif-then構文を自動的にインデントします、そしてキーワードを色付けします。しかし、あなたのコードの見栄えに関してあなたが自由にできる多くの他の側面があります。例えば、スペースを付け加えること、1つの引数に括弧を付ける(あるいは付けない)ことは自由です、また、変数(属性)に自分の好きなように名前を付けることができます。

もし、あなたが自分自身のためにプログラムしているのであれば、あなたのコードをどのようにフォーマットしてもそれ程の違いはありません。しかし、他に人があなたの書いたものを読む可能性があるのであれば、どれかの基準に従うのがベストです。全てのプログラマは特別な「スタイル」を決めて、そのスタイルに首尾一貫して従うべきです。どのスタイルにあなたが従うかは首尾一貫するというほど重要ではありません:首尾一貫しないというのは混乱を引き起こします。たとえ、他人があなたの書いたものを見ないとしても、あなた自身が理解しやすい、明瞭で、適切にフォーマットされたコードを書くのがベストです。あなたはそれは問題ではないと思うでしょう、しかし私を信じて下さい。あなたが書いたプログラムを2年後に見たときには、コメントとフォーマットの重要さが判るでしょう。

私の使っているスタイルについてこれから説明しますが、あなたの必要に応じて自由に修正して下さい。あなたは私のスタイルに従う何の義務もありません、しかし、私はそれはコードをより読みやすくしていると思います。

大文字/小文字

私は大文字を好みません -- それらはキーワードや変数に対して不必要に目立ちます。REALbasicはキーワードを色付けしますので、大文字はキーワードに対しても不要です。ですから、私は全てのREALbasicのコードを小文字にしています。変数と関数名に対しては、小文字で始めて、名前の中のワードの最初を大文字にします。

例えば、私はmyVariabletheVariableNameあるいはgThisGlobalVariableのように書きます。

名前の2番目、3番目そして4番目のワードを大文字にすることはいい習慣です。それはそれらのワードを目だ立たせますし、変数の名前にスペースは使えませんから。別の方法はワードを分けるスペースの変わりに下線(アンダースコア)を使います:例えば、the_variable_namethe_computer_score(このようにすれば全てを小文字にできます)。

大文字/小文字を首尾一貫して使用しましょう -- 特に関数や変数の名前である場合には、それはあなたのコードを著しく読みやすくします(あなたはplayerNamePlayerNameは別のものと思うでしょう、しかし、それらはREALbasicにとっては同じなのです)。

命名法

変数についていえば、名前の付け方に幾つかの基準があります。あなたが変数に名前を付けるときには少し時間をかけることを勧めたいと思います:その変数が何であるかを現す名前を考えて、そして同じような名前を付けないようにしましょう(それは混乱のもとですし、REALbasicの自動補完機能を損ないます)。

例えば、theList()は配列にたいする漠然とした名前で、theAddressList()の方がずっと良いでしょう。変数の内容を現す長い名前を付けることを恐れないで下さい:REALbasicはあなたのために入力を完成してくれますので、あなたは決して最初の数文字以上を入力しなければならないということはありません。

メソッドや関数に対しては次のような考え方が適用されます:私は関数の名前としてはreturnTitle()convertStringToHTML()のような付け方を好みます。

変数の名前を付けるとき従うといい幾つかの標準的な規則もあります。例えば、大局的(グローバル)な変数には小文字の"g"を前に付けるというのは長年の習慣です。また、定数には小文字の"k"を付けます。次のものは変数の「適切な」名前です(最初の3つはグローバルとします):

 gScore as integer 
gTheDate as date
gPreferenceArray(6) as string
const kPi = 3.14
const kPar = 72
const kPicasPerInch = 6

あなたはまた自分自身の変数の命名法をつくることも可能です。例えば、文字列の前には"s"、あるいは配列には"a"を付けるなど。私の提案の1つは「ホットヘルプ」の文字列にhSaveButton as stringのように"h"を付けて定義することです。

私の使っている他のテクニックで、込み入ったオブジェクト指向のコードで特に有用なものは、名前に"class"という言葉を付けてカスタムクラスを定義することです。例えば、私は顧客とそれぞれに対して終了したプロジェクトを管理する会計タイプのプログラムを書いているとしましょう。以下のようにカスタムクラスを定義することによって、それぞれの顧客レコードがどのような情報を持っているかを理解しやすくなります:

 clientRecordClass: 
company as string
contact as string
address as addressClass
phone(0) as phoneClass
history(0) as projectClass
notes as string

projectClass:
projectStartDate as date
projectEndDate as date
projectName as string
projectNotes as string
projectCosts as costClass

phoneClass:
phoneNumer as string
phoneKind as string

addressClass:
line1 as string
line2 as string
city as string
state as string
zip as string
country as string

costClass:
projectedBudget(0) as costItemizationClass
actualCosts(0) as costItemizationClass

costItemizationClass:
itemName as string
itemCost as double
itemQuantity as integer
itemNotes as string

上記のものはすべてクラスですので、それらは構造を定義しているだけで、どのようなデータも含んでいません。データを保持する実際の変数(属性)は何かほかの名前が付けられるでしょう(clientRecordArray(0) as clientRecordClassのような) -- しかし、クラスの名前をこのように付けることは、どれがクラス(定義)で、どれが実際のデータであるかを明確にします。

スペースと空白行

スペースと空白行はコードのサイズをそれほど大きくしませんが、明らかにコードを読みやすくします。次のコードの断片のどちらがあなたの目にとってやさしいですか?(この例はREALbasicのオンラインヘルプからのものです。)

 dim i as integer 
dim WindowTitle as string
if WindowCount>1 then
for i=0 to WindowCount-1
WindowTitle=Window(i).Title
ListBox1.AddRow WindowTitle
next
end if
 dim i as integer 
dim windowTitle as string


if windowCount > 1 then


for i = 0 to windowCount - 1
windowTitle = window(i).title
listBox1.addRow windowTitle
next


end if

私は変数の代入の間(例えば、i = 0 )、数式の項目の間(例えば、i - 4 * 7 )、また括弧の中のパラメータの間(例えば、graphics.fillRect(x, y, w, h))にスペースを入れます。余分なスペースはコードの密度を大きく下げて、ものを見付けやすくします。

コードの段落の間の空白行はものごとを分割するのを容易にします:上の例ではfor-nextループがうまくグループ化されています。このような簡単なルーチンでは、これは明らかに必要というわけではありません、しかし、複雑で長いコードの場合には、ちょっとした空白行がコードを大きく改善するのです。

コメント(注釈)

コードにコメントを付けることは我々のできることの最高のことです。憶えておくべきことは、コメントを付けすぎるということなないということです。たとえコメントがコードよりも長いとしても、それは長すぎはしません。あなたが一年あるいは10年後にあるプロジェクトを見たときには、それらの注記に感謝するでしょう。(あなたがアマチュアのプログラマであって、数年後に理解できなくなるようなおかしなコードを書きやすい場合には、これは特に当てはまるでしょう。)

REALbasicでは3種類のコメントを使えます://'remはその行のそれ以降をコンパイラに無視させる正しいコマンドです。(Remはもうほとんど使われませんが、BASICとの互換性のために含まれています。)

私は個人的には // を「本当」のコメントに、そして ' を一時的にコードを隠す ためにために使っています。例えば、私があるルーチンをデバッグしていて、ある描画ルーチンを動くようにしているとしましょう。私のコードは次のようでしょう:

 // Draw player's score 
' staticText1.bold = true
' staticText1.textSize = 24
' staticText1.text = str(gScore)
g = gameWindow.graphics
g.textFont = "Geneva"
g.textSize = 24
g.bold = true
s = str(gScore)
x = g.left + g.width - g.stringWidth(s) - 10
y = g.top + g.textHeight + 10
g.drawString s, x, y

プログラムの第一段階では、私は得点をテキスト要素に書くようにしました。しかし、後でそれを隠して、ウィンドウのgraphicsポートに直接に描画するようにコードを書きかえました。このようにすれば、行ないたいことをまず大まかに実現してプログラムがまず動くようにし、その後でさらに洗練したルーチンを追加することができます。しばしば、少なくともしばらくの間は、私は古いコードを保存しておきます。その理由は、それは動くことが判っていますし、それを参照する必要もあるでしょうし、また新しいコードに問題がある場合には、それに戻すことさえあるでしょう。

そのルーチンの最初にメソッドが何をするかという説明を追加するのはコメントの別のよい使い方です。これは将来あなたを助けてくれるでしょう:コードを解析することなくそのルーチンの目的を直ぐにはっきりさせることができます。

例えば:

 dim index, numRecords as integer 

//
// このメソッドは顧客の名字LAST NAMEから
// 配列clientRecord() を並び替えます
//

numRecords = uBound(clientRecord)

(以前に勧めた空白行と一緒に使っていることに気付きましたか? 説明の前後に空白行おき、またその重要なコメント行をさらに目だたせるために空白のコメント行をおいています。)

ルーチンを説明するコメントを追加することの他の利点は、それをどのようにプログラムするかを実際に決める前に、そのルーチンが行なうであろうことを記述しますので、実際のコードを書き始めるときにはあなたの考えがより整理され、組織立っているということでしょう。

REALbasicでは次のようにコードの行の最後にコメントを書くこともできます:

 x = (screen(0).width - x) \ 2 // This centers the drawing point 

しかし、この方法は行を長くするので、私はあまり好みません。次のものがどれほど明瞭か較べてみましょう:

 // This centers the drawing point horizontally 
x = (screen(0).width - x) \ 2

プログラムにコメントを書くことに慣れるのは容易ではありません、しかし、非常に大切なテクニックです:私は今日から全てのコードにコメントを付け始めることを強く推奨します。

これでコードをかく作法の短いレッスンは終わりです。私はあなたが何かを学んび、そして結果としてプログラムを書くよりよい習慣を伸ばされることを期待しています。

次週

カスタムクラスの作り方とともに、カスタムクラスをプロジェクトに組み入れることについて学習します。

RBU裏技

プロジェクトウィンドウからコード編集ウィンドウにオブジェクトをドラッグできることを知っていましたか? 例えば、Window1をコード編集ウィンドウにドラッグすると、REALbasicはWindow1.showと「入力」してくれるでしょう! サウンドをドラッグすれば、それはそのサウンドファイルの名前の後に".play"を付けたものを挿入します。

この裏技は全ての種類のオブジェクトに有効ではありませんが、それは楽しいですし、必要な場合に迅速に行なえます。

Letters

今週の最初の手紙はrcfuzzさんからです:

今日は、私はプログラムを入手したばかりで、グローバルな配列の作り方が判りません。どのようなヒントでも大歓迎です。また、「編集コントロール」が文字列ではなく整数を返すようにするのはどうすればいいのでしょうか。

配列(あるいは、属性)をグローバルにするには、それをモジュールmoduleの中に置きます。属性を追加できるモジュールを作成するには、Fileメニュー行き、"New Module"を選びます。

あなたの2つ目の質問に対しては、あなたが「編集コントロール」で何を意味しているのかがよく判りません -- もし文字列入力欄を意味しているのだとすれば、それはテキストしか保持することはできません、しかし、テキストはval関数で数値に変換することが可能です。

次の手紙はTauseefさんからで、込み入ったグラフィックスに関する質問です:

拝啓、

REALbasicを使ってベクトルマップを利用した地図ソフトを作ろうとしています。私はREALbasicを始めたばかりですので、それはどのようにすればいいのかよく判りません。地図とそのオーバレイがウィンドウに描かれているときに、距離を測るツールを作るという難問に突き当たっています。私はラインコントロールを使って、その一方の端を参照地点に固定し、他端をマウスの移動イベントとともに移動させようとしました。しかし、マウスが動いたとき、以前のラインの位置はそのままで、地図はごちゃごちゃになりました。マウスのイベントハンドラでウィンドウを再描画すると、ラインが移動するときに、スクリーンがひどくちらつきました。この問題を回避する方法を教えてください、さらに、REALbasicでのマルチスレッドを解説している資料を教えて下さい。

あなたは間違っていません、Tauseefさん。しかし、そのようにラインを動的に描くのは少々テクニックが必要です。まず、私はウィンドウのMouseMoveイベントは使いません -- 描画がなされるキャンバスにラインの描画を組み入れるでしょう。いちばんいいのは、地図をどのように描画するか、またクリックされたときに何をするか(ラインを描く)を知っている自分用のキャンバスクラスを作ることです。

私はそれを示す簡単なデモプログラムを作りました:そのプロジェクトファイルはここからダウンロードできます。このプログラムは単純に最初にクリックされたところからラインを動的に描画します。あなたがマウスを移動させると、ラインは新しいカーソル位置に再描画されます。それは次のアニメーションのようです:

(背景に幾つかの図形を描いて、その上をラインが動くようにしています。)

REALbasicの開発環境で実行するとちらつきが激しいですが、プログラムをコンパイルするとちらつきはほとんど無くなりことに気が付くでしょう。

どのようにプログラムが動いているかというと、それは幾つかの部分に別れています。まず、私はcanvasClassと呼ぶカスタムキャンバスクラスを作りました。それから、mouseDownイベントで、次のコードを書きました:

   firstClick.x = x 
firstClick.y = y
return true

これはクリックされた点を私が定義したカスタム変数pointClassに保存しているだけです。最後にtrue(デフォルトのfalseではなく)を返すことによって、mouseDragイベントが可能になります。それで、mouseDragに以下のコードを入力しました:

   if lastClick.x <> x or lastClick.y <> y then 
lastClick.x = x
lastClick.y = y
me.refresh
end if

こでは基本的には「最後にチェックしたときからカーソルが移動したときは、ラインの終点を現在のカーソルの位置に設定せよ。」と言っているだけです。その後で、キャンバスに自分自身で"refresh"(再描画)をするように指示しています。

次は、この問題の核心(キャンバスの再描画部分)です。キャンバスが描かく必要のある全てをPaintイベント内で処理しなければなりません。それで、まず背景の幾つかの物体を赤色で描画します、それからラインを黒色で描きます。

firstClickはカスタムクラスのオブジェクトですので、それを使う前にnewコマンドで生成しなければなりません。それで、それを使用する前に、それが生成されていることを確かめるために、それがnilでないことをチェックします。もし、firstClicknilでなければ、我々は点firstClickから点lastClickまでのラインを引きます。)

   // Draw a few objects so that we have a background 
g.foreColor = rgb(200, 0, 0) // red
g.fillRect(40, 40, 50, 50)
g.fillOval(200, 200, 10, 50)
g.fillRect(400, 100, 25, 120)
g.fillOval(50, 200, 50, 50)

if firstClick <> nil then
g.foreColor = rgb(0, 0, 0)
g.drawLine(firstClick.x, firstClick.y, lastClick.x, lastClick.y)
end if

憶えておくべき1つの重要な点はPaintイベント内の項目が書かれた順番に描画されるということです。それで、あなたは背景を最初に描画して、移動するラインを最後に描かねばなりません。もし、そうしないと、ラインが図形の背後になってしまうでしょう!

次週にカスタムクラスを作る時に、このことについてさらに学習するでしょう:ユーザにオブジェクトの選択を可能にするカスタムクラスの作成法について解説しようと思っています。

あなたのマルチスレッドに関する資料に対しては、私はそれに関する特別なものを知りません、もっとも両方のREALbasicの本(このページのRBUバナーにそれらのリンクがあります[訳注:英語版のみです。2つの本に関しては第14講を参照して下さい])がそのトピックを扱っています。私はスレッドについてこのコラムでいつか取り扱おうと思っています、しかし近い将来という訳ではありません。

このような手紙をお寄せ下さい。私はあなたの質問に直ぐには答えないかも知れませんが、たぶん今後のコラムで取り扱うでしょう。(もし、あなたの手紙が公表されるのを望まない場合には、その旨を明記して下さい。そうでなければ、公表してもいいものとして取り扱います。)


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

INDEXに戻る