週に一度はOPL

Psionのシンプルな開発環境であるOPLの簡単なTipsを週に一度は追加しようと いう試みです。頓挫したら笑って下さい。
なお、サンプルコード等の著作権は考慮頂かなくて結構です。著作権を 主張するほどの内容はありません(そのままの無断転載は御遠慮願います)。


第3回 メニュー 00.11.19 はやくも一月のブランク..
第2回 ツールバー 00.10.02
第1回 ポップアップメニュー 00.09.27


第3回 メニュー

今回はメニューです。Epoc OSのメニューがMacやWindowsなどのメニューと 異なる点は、メニューバーが常に表示されておらず 必要な時だけ 出現するところでしょう。縦に広がる個々のメニューだけでなく、 メニューが出てくる根っこになるメニューバー自体も普段は隠れているので、 狭い画面をより有効に使える反面、一旦メニューバーを出してからメニューを 選択するというように操作が増えるのが煩わしいという欠点もあります。
メニュー項目の選択方法は大きくふたつあり、ペンで左上のメニューアイコンを クリックしたり、キーボードのMenuボタンを押してメニューバーを出し、 個々の項目をペンないしカーソルキーで選択する方法と、キーボードから直接 それぞれのメニューに割り当てられているショートカットキーを押す方法です。 後者は直接メニューが表示されるわけではないので、厳密にはメニューの選択 ではありませんが、Epoc OSの作法としては両方とも実装しないと格好悪いですので ここでは一緒に説明いたします。

ペンないしMenuボタンによるメニュー表示

まず、イベントループでペンによるメニューアイコン(画面の外の左上のアイコン)の クリックを検出します。これはGETEVENT32で取得したevent&()の一番目が 10000の場合に相当します。同様に、Menuボタンが押された場合は、event&(1)には4150が入ります。両者を区別する必要は特にありません。

GETEVENT32 gEvent&()
IF ..
  ...
ELSEIF gEvent&(1)=4150 OR gEvent&(1)=10000
  rem -- menu event.
  rem -- "control+#" event is processed in Event_Key: .
  Event_Menu:
ELSEIF ..
このソースではペンによるメニューアイコンのクリックや、Menuボタン押下があった場合Event_Menu:というプロシージャを呼び、その中にメニューの処理を入れています。
proc	Event_Menu:
  local k%, a$(10), cmdstr$(3)
  cmdstr$ = "dea"
  mINIT
  mCARD "File","Dummy",-%d,"Exit",%e
  mCARD "Info","About..",%a
  k% = MENU
  if k% AND (LOC(cmdstr$,chr$(k%))<>0)
    rem -- it will call "cmd#" (# is d,e or a)
    a$ = "cmd" + chr$(k%) : @%(a$):
  endif
endp
上の4-6行のmINIT/mCARDが具体的なメニューの構造を定義しています。 ここではmCARDを2回呼んでいます。mCARDを1回呼ぶ毎に、メニューバーに 1行メニューが追加されます。
mCARDの第一引数はメニューバーに表示されるタイトルで、それ以降の引数はメニューの各項目の名前とショートカットキーの組となっています。 ここでは、"Dummy"にCtrl+D(%d)、"Exit"にCtrl+E(%e)、"About.."にCtrl+A(%a)のショートカットを与えています。
なお、%xはxのキーコード(整数)を表します(ASCIIコードの小文字と等しい。%a=65,%b=66,...)

DummyとExitの間に横線が入っていますが、これは"Dummy"のショートカットを%dではなく-%dとすることで入れることができます。

mINIT/mCARDに続くk%=MENUの一文で、ユーザがどのメニューを選んだかを取得できます。ペンを使ったかそれともカーソルキーとリターンキーで選択したかはここでは区別されず、選択されたメニューの値が返されます。キャンセルの場合は0、何かが選択された場合はそのメニューのショートカットのキーコードが返ります。例えば"About"なら%a(=65)です。
LOC()という関数は、第一引数の文字列の何番目に第二引数の文字が入っているかを返す関数です。ここでは、選択されたショートカットが"d""e""a"のどれかであるかどうかの判別に用いています。もし"d""e""a"のいずれかである場合は、"cmd"を頭につけたプロシージャを呼びます。@%(a$):というコードがそれにあたります。これは文字列a$に"%:"をつけたプロシージャ、つまりa$="cmde"ならばcmde%:というプロシージャを呼び出します。もちろん、呼ばれるプロシージャ(cmdd%: cmde%: cmda%:)は別に定義しておく必要があります。

ショートカットキーによる処理

上記のコードだけですと、一度メニューを出さない限りショートカットが動きませんので、直接Ctrl+何かが押された場合のコードも書かなくてはいけません。ここではキーの押下はevent&(1)の値が300以下か否かで判別しています(この300という値は少々自信なし)。

GETEVENT32 gEvent&()
IF ..
  ...
ELSEIF gEvent&(1)<=300
  Event_Key:
ENDIF

..

proc Event_Key:
  local isS%, a$(10), k%, tx%,ty%
  local cmdstr$(3)
  cmdstr$ = "dea"

  if gEvent&(4) AND 4 rem -- Control key is pressed
    rem -- when ctrl, value of gEvent&(1) is a/A=1, b/B=2,...
    rem -- then +64 is needed to convert ascii character code.
    rem -- if you want capital-sensitive code,use gEvent&(4) AND 2
    rem -- to find shift is pressed or not.
    k% = gEvent&(1)+64
    if LOC(cmdstr$,chr$(k%))
      rem -- it will call "cmd#" (# is d,e or a)
      a$ = "cmd" + chr$(k%) : @%(a$):
      return
    endif
  endif
endp
event&(4)に修飾キーのコードが入っています。Ctrlが押されたかどうかは 4とANDを取ればわかります。(ちなみにShiftの判別はAND 2)
なぜかCtrlが押された場合は、event&(1)には直のコードではなくaならば1 bならば2というような値が入っていますので、64を加えてキーコードに合うよう調整した後に、先ほどと同じように"cmda%:"などのプロシージャを呼び出しています。

呼び出されるプロシージャの作成

これは、前回と同様ですので省略します。ちなみに、なぜ呼び出されるプロシージャを"cmda%:"などという名称にしたかと言いますと、ツールバーで呼び出されるプロシージャと同じ名称にあわせることでコードが共有できるからというだけの問題です。

サンプルコードと実行バイナリ

今回のサンプルの内容は前回と全く同じものです。
サンプルコード(ttoolbar.opl)
実行バイナリ(ttoolbar.opo)
テキストファイル
圧縮せずにおいてあります。別名で保存などでファイルに落とし、Psionにコピーしてください。


第2回 ツールバー

ツールバーとは、Epoc OS特有のGUIで、一般に右端にあるボタンや時計の表示 された領域のことを指します。

ツールバーには、「他のタスクを表示する」 「ボタンを提供する」「時計や日付やバッテリを表示する」などの機能が 入りますが、実際にプログラムで考えないといけないのは「ボタンを提供する」 部分だけで十分です。ただし、APIとしてはいくつかのオマジナイが必要ですので ひとつという訳にはいきません。

ツールバーの初期化(その1)

ツールバー用のAPIを利用するために、最初にツールバー用のモジュールを ロードする必要があります(LOADM)。また、TBarLink:()というAPIも最初に呼んでやる 必要があります。引数には、このAPIをコールした後に戻ってきたときの プロシージャの名前を入れてやります。下の例で言うと、TBarLink:()を呼んだ あと、処理はMain:に移ります。

proc Start:
  LOADM "Z:\SYSTEM\OPL\TOOLBAR.OPO"
  TBarLink:("Main")
endp

PROC Main:
  ...
ちょっと注意が必要なのは、Start:のプロシージャにはもう戻らないということです。つまり、TBarLink:()からendpまでの間に何かコードを書いたとしても、そのコードは決して呼ばれないのです。

ツールバーの初期化(その2)

続いて、ツールバーの本当の初期化ルーチンを書きます。

  TBarInit:("tTBar", gWidth, gHeight)
  TBarButt:("a", 1, "About", 0, &0, &0, 0)
  TBarButt:("d", 2, "Dummy", 0, &0, &0, 0)
  TBarButt:("e", 3, "Exit", 0, &0, &0, 0)
  TBarShow:
TBarInit:()の第一引数には、ツールバーの最上段に表示される文字列を入れます。 なお、プログラム実行中に変更することも可能です(TBarSetTitle:()を使う)。また、 大体7文字以上入れると見にくくなるので、そう多くの情報は表示できません。
TBarButt:()では、ボタンの設定をします。第一引数は呼び出されるプロシージャを 決める文字を入れます。"a"を設定すると、このボタンを押したときに"cmda%:" というプロシージャが呼ばれます。"d"なら"cmdd%:"プロシージャです。
TBarButt:()の第二引数は、ボタンの位置(上から幾つめか)を表します。Revoでは 最大3つしか表示されませんが、4を設定してもRevoでは表示されないだけで 害はないようです。 第三引数はボタン上の文字列です。それ以降の引数は、ボタンの装飾や振舞いに 関する設定のためのものですのでここでは割愛します。
TBarShow:はツールバーを可視にするためのプロシージャです。いつ呼んでも構いません。TBarHide:で隠すことも可能です。

イベントループ内のツールバー呼び出し

ツールバーを動作させるのはペン(指でもいいですが)入力のみで、キーボードからは 操作できません。イベントループでペンの入力があった場合には、まずツールバーに対する操作であったかどうかを確認する必要があります。

  global gEvent&(16)
  ...
  do
    GETEVENT32 gEvent&()
    IF gEvent&(1)=Pointer_Used
      IF TBarOffer%:(gEvent&(3),gEvent&(4),gEvent&(6),gEvent&(7))
        RETURN
      ELSEIF ...
  until 0
GetEvent32でイベントを取得後、ペン入力であった場合はまずTBarOffer%:()を呼びます。もしツールバーに関する入力である場合には、このAPIが自動的にプロシージャを呼ぶなどの処理をやってくれます。ツールバーに関する入力でなかった場合、このAPIはfalseを返すので、ペン入力に対する独自の処理をその下に書けば良いでしょう。

呼び出されるプロシージャの作成

最後に、ツールバーのボタン押下に対する処理を書きます。このプロシージャは TBarOffer%:()から勝手に呼び出されます。

proc cmde%:
	stop  rem -- simply exit
endp
プロシージャ名はTBarButt:()で設定した文字の前後に"cmd"と"%:"をつけたものにしてください。

サンプルコードと実行バイナリ

サンプルコード(ttoolbar.opl)
実行バイナリ(ttoolbar.opo)
テキストファイル
圧縮せずにおいてあります。別名で保存などでファイルに落とし、Psionにコピーしてください。


第1回 ポップアップメニュー

ポップアップメニューとは、普通のメニューと違い任意の場所に出す メニューで、カスケード(サブメニュー)ができないなどの制約があります。

一見面倒そうですが実は簡単で、メニューを出したい位置を指定してmPopup()を 呼ぶだけです。ポップアップメニュー表示中は、ペンの他にreturn/esc/arrow/shortcut(ctrl+何か)キーも使えます。escを選ぶと、返り値はゼロになります。

上記のような図を出すコードは以下のようになります。
val% = mPopup(inxpos&, inypos&, 0, "one",1,"two",2,"three",3,"extra",%e)

サンプルコードと実行バイナリ

サンプルコード(tpopmenu.opl)
実行バイナリ(tpopmenu.opo)
圧縮せずにおいてあります。別名で保存などでファイルに落とし、Psionにコピーしてください。


Psion Revoページに戻る

トップに戻る


created by H.M 00.09.27