REALbasic の基礎 II
このコラムはStone Table Softwareのオーナーであり、またREALbasic Developerの編集者でもあるMarc Zeedar氏により書かれたものを、著者の許可を得て翻訳したものです。この翻訳はHREM Researchにより提供されています。この日本語版へのご意見はRBU-Jまでご連絡下さい。
URL:INDEXに戻る
先週、我々は画像をキャンバスに表示し、スクロールバーによってユーザーに画像をスクロールさせる方法について学びました。今週も引き続いてREALbasic の持つ基本的なコントロールについて学習していきます。
もし、あなたがプログラミングに興味があるならば、Mac OS X のためのAppleのプログラミング環境であるココアCocoaについて聞いたことがあるでしょう。ココアはNeXT computerの開発環境を基礎としているもので、使いやすいと評判です。昔、私はコンピューターショーに行き、真新しいNeXT computerをこの目で見ました。ほんの少しの時間プログラムしただけにもかかわらず、驚くべきことに、非常に簡単であることが判りました(マニュアルや解説者すらなかったにもかかわらず)。
私が試した処理は単純な次のようなものです:スライダをドラッグすると数値を変えるスライダsliderコントロールを作成することです。そのようなコントロールは数値を入力するよりも容易で、Macのインターフェースとして非常に一般的です。しかしながら、従来のMacプログラミングにおいてはそれは非常に複雑なものです。しかし、それはNeXTにおいてはおどろくほど簡単でした:一行のコードを書く必要もありませんでした! 私は、スライダをウィンドウにドラッグし、そしてテキスト入力欄にそれをリンクしただけです。
私がREALbasicを発見したとき、最初にテストしたことの一つは、同じスライダコントロールを作ってみることでした。REALbasicはNeXTと同じほどには容易ではありませんでしたが(RBでは数行のコードが必要でした)、それは私にREALbasicの購入を決意させるほどに簡単でした。
私が先週に始めたRBUデモを見れば、スライダテストと呼ばれる領域を見つけられるでしょう。slider1 コントロールを選択して、そしてそのOpenイベントにいきましょう。そこで、以下のコードを入力してください。
me.value = 75
これれはスライダを75の位置に移動させます(ユーザーがそこにドラッグしたかのように)。これは、コントローラが表示される前に行われますので、ユーザーがデフォルトゼロ点からの移動を見ることはないでしょう。
追記 |
ここに、あなたへの質問があります:スライダのvalueはプロパティウィンドウで設定できるのに、なぜOpenイベントに書き込むのでしょう? その答えは、私達はスライダの値をeditField1の内容に反映させたいからです。editField1の内容はスライダのvalueが変化したときに設定されますが、プロパティウィンドウで値を設定した場合には、slider1のValueChangedイベントは起こりません。このために、プログラムを起動してもユーザがスライダをドラッグするまで、editField1は正しい値を示さないでしょう。あなたはeditField1の内容をSlider1のvalueに書き換えることもできます。しかし、それは二箇所に手動で値を設定することになるため、それらが合致するように注意する必要があります。もっとも簡単な方法はslider1のvalueをコードでプログラム的に設定することです。 |
では、slider1のValueChangedイベントに以下のコードを打ち込んでください。
あなたは、ネットワークのどのタイプをお勧めします、なぜでしょうか?
editField1.text = str(me.value)
これは、slider1のvalueの数値を文字列に変換し、それをeditField1に設定します。(meは現在のコントロール(ここではslider1)を示しますので、me.valueはslider1.valueと同じであることに注意して下さい。)
上の行が文字入力欄(もしくはテクスト要素)のテキストをスライダコントロールの位置に対応する値に設定するためのに必要な全てです。簡単でしょう。
しかし、これはスライダから文字入力欄への一方向的なリンクです。文字入力欄からスライダへ双方的なリンクでしょうか? ユーザーが文字入力欄に数値を入力したときに、スライダはそれによって変化するでしょうか?
それは、難しいことではありませんが、もう少し多くのコードを必要とします。コードエディターでeditField1を見付けて、TextChangeイベントに移動して、以下のコードを打ち込みます。
// 内容を数値に変換
me.text = str(val(me.text))// slider1 にこの値を設定
if val(me.text) > 0 then
slider1.value = val(me.text)
end if
最初の行はすこし奇妙に見えます:これはeditField1の内容が数字であることを確実にしています。私達はそこに在る文字列をvalコマンドで数字にして、それからそれを文字列(テキスト)に戻して、それのテキストをeditField1に設定します。
なぜこのようなことをするのでしょう? そうですね、もしそこにあるものが数字でないか、あるいは文字の一部が数字でなければ、これはそれを実効的に除外して、正しい有効な数値の部分だけを保存します。例えば、editFieldの内容が"3b0"であった場合、それを3に変換します。
次のステップはSlider1のvalueを設定することです。まず、数値が0より大きいことを確認します:val関数は何らかの理由によってうまく変換できなかった場合には0を返してきます。slider1の範囲は1から2000ですので、0は許容されません。数値が0以上であればで、slider1.valueにその値を設定します。
これで、コントロールは双方向にリンクされました:editField1への入力はslider1をその数値に設定し、その逆も行われます。しかし、数字だけ許す欄に文字の入力を許すのは綺麗では在りません。それを改良しましょう。
editField1のKeyDownイベントに行き、以下を入力します。
dim n as integern = asc(key)
// 削除キーと矢印キーを受け付ける
if n = 8 or (n > 27 and n then
return false
end if// 数字キー以外を拒否する
if (n or (n > 57) then
return true
end if
これらは何を意味するのでしょう? まず、ユーザーの入力した文字であるkeyをasc関数によって数値に変換します。(これは必須ではありませんが、これにより数値の演算が簡単になります。)この数字をnとして保存します。
これで、私達はユーザが数値を入力したかがわかります。そして、もしそうでなければ、入力を拒否します。しかし、そのアルゴリズムには欠点があります。ユーザーは幾つかの重要な不可視の文字を打つことが可能だからです。例えば、削除(BSキー)やカーソルを動かす矢印キーなどです。それらはaや7、%と同じ本物の文字なのです。もし、そのような文字を許さないと、ユーザは間違いの削除やカーソルの移動などがマウス無しではできなくなります。
ですから、私達の使うアルゴリズムは以下のようになります:まず、打たれた文字が正当な不可視文字であるかを確認します。もし、そうであるならば、それを通過させます。それ以外で、数字でないものは拒否します。
これはどのようにして行うのでしょうか? それは、nが8か28,29,30,31であるか調べます。削除(Delete)キーはASCIIの8であり、一方、矢印キーは28〜31だからです。
追記 |
どのASCII値が削除や矢印キーと一致するかはどのようにあいて知るのでしょうか? そうですね、私は経験と記憶でそれを知っていますが、あなたも自分で調べることが可能です。空のRBプロジェクトにeditFieldをドラッグしてきて、option-TabでKeyDownイベントを開き、以下のコードを打ち込みます。 msgBox str(asc(key)) これは、あなたの押したキーのASCII値を表示します。あなたの必要とするキーの値を書きとめて置きましょう。 |
入力された文字が正しい場合には、それに許可しなければならないということに注意しましょう。我々はそれをreturn false行で行っています。これはどのように働くのでしょうか?
そうですね、KeyDownイベントは関数functionです:これは論理値booleanを返します。REALbasicの初期設定では、特に値を返さない限りは偽(false)となっています。KeyDownイベントでfalseを返せば、あなたがその文字を自分で処理せずに、その文字を受け取って文字編集欄に表示したいのだと解釈します。 すなわち、return trueは文字入力を阻止します、しかしreturn falseは文字入力を許可します。
いつものように、関数がreturnコマンドに遭遇するとき、その点で処理が中断され、そして呼び出された点に移動します。言い換えれば、そのルーチンのその後の処理は行われないということです。従って、return falseに達したときに、KeyDownイベントは終了します。
数字でない文字を阻止するためには、我々は単純に打たれた文字が48未満か57より上であることを確認します(48 はゼロで、57は9です)。もしそうなら、我々はそれを阻止するためにtrueを返します。もし、その文字が数字であるならば、阻止されず、REALbasicがルーチンの最後まで達したときに、初期値のfalseが返されて、タイプされた数値が保持されます。
課外テーマ |
ところで、これは全てを阻止するわけではありません:ユーザがクリップボードからぺーストしたものは阻止されません。RBはクリップボードを自動的に処理しますので、ユーザーは文字をぺーストすることが可能となるでしょう。 しかし、editField1をそれが含んでいる数値に再設定するという我々の方法はこのことを回避します。でもそれはエレガントではありませんし、またもしクリップボードに文字が入っている場合にはペーストを排除できません。課外テーマとして、どのようにすればいいのか考えてみて下さい。 |
では、他のREALbasicのべーベルボタンBevelButtonコントロールを見てみましょう。これは少し妙なコントロールです:ポップアップメニューPopupMenuとプッシュボタンPushButtonの中間的な物です。あなたがどのようにプログラムするかによりますが、べーベルボタンは多様な外見と機能を持つことができます。
RBUデモのBevelButtonのテストエリアでは、その特徴を明らかにするコードを持った4つのべーベルボタンを配置してあります。
最初のものアイコンを含んでいるという点以外は機能的には単純なプッシュボタンと同じです。あなたはキャプションとアイコンの位置をプログラムで設定できます。BevelButton3はアイコンが無く、「トグル」ボタンであることを除いてよく似ています:「トグル」ボタンは押されたとき押されたままになり、その後もう一度押されたときに飛び出します。
BevelButton1とBevelButton3はコードをまったく含んでいません:これらはプロパティウィンドウの設定によって完全に定義されています。
しかし、BevelButton2はいくらかのコードを含んでいます。それはポップアップメニューを持っていますので、我々はボタンのOpenイベントでメニューのアイテムを定義し、ユーザがそのうちの1つを選んだときに何が起こるかを設定します。
BevelButton2のOpenイベントは非常に単純です:
me.addRow "Bevel 0"
me.addRow "Bevel 1"
me.addRow "Bevel 2"
これは示されているような3つのメニューを追加するだけです。もし、ユーザーがメニューの一つを選んだ場合、我々はボタンの"bevel"に対応する値(0,1,2)を設定します。これはBevelButton2のActionイベント用のコードです:
me.bevel = me.menuValue
簡単でしょう。これはボタンのbevelプロパティを0,1,2に設定しているだけです。ユーザーは即座にその結果を見ることができます。
BevelButton2のメニューがボタンの下にドロップダウンすることに気付きましたか? BevelButton4のメニューはボタンの横に表示されます。これはプロパティウィンドウでの設定によります。
BevelButton4は、インストールされてるフォントのリストを示すというような、もう少し有用なことを行うようにしましょう。それで、Openイベントでポップアップメニューにフォント名を読み込みます:
dim i, n as integern = fontCount - 1
me.addRow font(0)
for i = 1 to n
me.addRow font(i)
next
fontCountはインストールされているフォントの個数を返すREALbasicの特別なコマンドです。font 関数はREALbasicに組み込まれていますが、配列に似ています(ある観点ではそのとおりです)。これは基本的に添字を必要として、文字列を返します。ですから、font(0)は最初にインストールされたフォントを、font(1)はその次を返します。fontは0から始まっていますので、最後のフォントに対して正しい添字で終わるためにはfontCountから1引く必要が在ります。(コマンドfont(fontCount)はエラーを返しますが、font(fontCount-1)はOKです。)
ユーザーがメニューからフォントを選ぶと何が起こるでしょう? 簡単です:べーベルボタンのフォントを選ばれたものに変更します。
Actionイベントにこれを入力しましょう:
me.textFont = me.list(me.menuValue)
もう一度、meは現在のコントロール(つまりBevelButton4)であることに注意しましょう。MenuValueは選ばれたメニューの番号、例えば、メニューの27です(これは28番目のフォントです、最初はゼロです)。べーベルボタンのListはメニュー項目の文字列(すなわち、フォント名)を含む0を基底とする文字列の配列です。
ですから、上記の少し難解な処置がしていることは選ばれたメニューの番号をメニューの文字列に直すことです。これはフォント名ですので、それをべーベルボタンのtextFontプロパティを設定するのに使うことができます。これは、実際上はかなり単純なことなのですが、べーベルボタンが選ばれた文字列ではなく項目の番号を知らせてくれるだけですので、このような方法が必要となります。(ポップアップメニューコントロールはメニュー番号を示すListIndexとメニューの文字列を示すTextを知らせてくれる両方のプロパティを持っています。)
今週はこれで充分でしょう。まだRBUデモには多くの基礎的なコントロールのセクションがあります。そこではtabPanelsやcontextual menus、QuickTime moviesなどについて学習するでしょう。
次週
REALbasic の基礎の続き
今週の手紙はStefaan Degryseさんからで、次のように書いてきています:
今日は、Marcさん
この前のコラムの「RBU裏技」(リストボックスの高速設定)は非常に有効に思えましたので、それを試してみました。
しかし、私はおかしなことを発見しました。
もし、チェックボックスをチェックしない状態で例題プロジェクトを走らせると長い時間が掛かりますが、261 ticksからはほど遠いものでしした(私の場合は約35 ticksでした)。チェックボックスをチェックした場合には、それは実際に速くなりました(約16 ticks)。
しかし、ここで問題が現れました。チェックボックスのチェックを再びはずした場合、リストボックスはチェックボックスをチェックした時と同じように高速に設定されました。
もし、逆の順序でこれを行なえば(最初にチェックを付けて、それからチェックをはずすと)、同じ時間が得られるでしょう。
結論:RBはリストボックスが最初に満たされるときに、何かその初期化をしているようです。
しかし、全てが無駄というわけではありません。これは次のような典型的なコードが使われる複数列のリストボックスの場合に大いに有用な手法です。
ListBox1.AddRow some stuff for column 0
ListBox1.Cell(ListBox1.LastIndex, 1) = some stuff to put in listbox
ListBox1.Cell(ListBox1.LastIndex, 2) = some more listbox thingiesとにかく、あなたがこの結果を知りたいと思ったものですから。RBUを続けて下さい ;-)
ところで、私はこれを自宅の G4 と職場の iMac で RB 2.1.2 と RB 3.2 でテストしました。
面白い結果ですね! 私も同じ結果になることを確認しました:しかし、何故こうなるのかは判りません。最初の設定は長く掛かります、しかしボックスが満たされた後では速くなります。非常に奇妙です。私はREALbasicでのリストボックスの奇妙な振る舞いについて気が付いています。例えば、リストボックスを浮かんでいるパレット型のウィンドウに置くと通常のウィンドウに置くよりも設定するのに時間が掛かります! 何故そうなるのかは、私には判りません。しかし、そのような速度の低下に遭遇して、私のプログラムの最適化を試みているときにこの解決法を見いだしたのです。
フィードバックを有り難うございます、Stefaanさん。このような手紙を歓迎します! 私はあなたの質問に直ぐには答えないかも知れませんが、たぶん今後のコラムで取り扱うでしょう。(もし、あなたの手紙が公表されるのを望まない場合には、その旨を明記して下さい。そうでなければ、公表してもいいものとして取り扱います。)
RBU裏技 |
見出しのあるリストボックスのコラムによる自動並び替え(sorting)を止めさせるには、sortColumnイベントにreturn trueを書きましょう。 |
RBU-Jの通知サービス!コラムが発表されるたびに日本語版REALbasic Universityのお知らせの emailがあなたに届きます。登録・削除は ここ から。
0 comments:
Post a Comment