title: Apollo チュートリアル
Author: NISHIO Mizuho
mailto: mzh@portnet.ne.jp


1. メニュー

1.1. その1(メニュー)

  %href: ./rb/menu1.rb menu1.rb%

--ruby
001  require 'phi'
002  require 'dialogs'
003  
004  form = Phi::Form.new(:form1, 'formです')
005  button = Phi::Button.new(form, :button1, 'ボタンです')
006  
007  $flag = true
008  
009  Phi::new_menu(form, :menu1, [
010    menu_file = Phi::new_item('ファイル(&F)', '', :menu_file1),
011    menu_edit = Phi::new_item('編集(&E)', '', :menu_edit1),
012    menu_help = Phi::new_item('ヘルプ(&H)', 'Ctrl+H', :menu_help1),
013    ])
014  
015  button.on_click = proc do
016    if $flag 
017      $flag = false
018      form.menu_file1.add( Phi::new_item("閉じる(&C)", '', :menu_close) )
019      menu_edit.add( Phi::new_item("コピー(&C)", '', :menu_copy) )
020    end
021  end
022  
023  menu_help.on_click = proc do
024    Phi::message_dlg('ヘルプはありません。', Phi::MT_ERROR, [Phi::MB_OK], 0)  
025  end
026  
027  form.show
028  Phi.mainloop
--

  このスクリプトを実行すると、%href: img/menu1.png このような% ウィンドウがあらわれます。

1.1.1. 解説
  起動時はメニューに「ファイル」「編集」「ヘルプ」の三つがあります。ボタンを押すことで「ファイル」には「閉じる」が、「編集」には「コピー」のメニューが追加されます。

  7行目は「閉じる」と「コピー」のメニューを一度だけ追加するためのフラッグを設定しています。他にも方法はあるのですが、今回はad-hoc(場当たり的のこと 別名バータリー的(笑))にこの方法を取ることにします。

  9〜13行で起動時に現れるメニューを生成しています。 Phi::new_menu は引数を三つ取ります。第1引数は親になるコントロール、第2引数は以前説明したSymbolのオブジェクト、第3引数は Phi::MenuItem のオブジェクトの集まり( Array のオブジェクト)になります。第3引数で使われる Phi::MenuItem のオブジェクトは Phi::new_item で生成することができます。

  10〜12行は Phi::new_item を生成し、それを変数に代入しています。一見すると、生成された Phi::MenuItem のオブジェクトが第3引数のArrayのオブジェクトの要素にならないように見えますが、Rubyだとこういう書き方をすることが可能です。

  このスクリプトで頻繁に使われている Phi::new_item の引数は最大5つです。上のスクリプトでは第4・5引数を省略しています。第4・5引数を取る場合については次のサンプルスクリプトで説明するので、ここでは第1〜3引数までの説明を行います。

  最初に Phi::new_item の第1引数ですが、これはメニューの文字列になります。第1引数で気を付けることは「&」の扱いです。サンプルスクリプトを実行してみればわかりますが、メニューを見ても「&」の文字は現れず、その代わりに「&」の次の文字に下線がついています。これはWindowsのアクセラレーターキーというもので、Alt + 「&」の次の文字 でメニューを操作できるようにします。例えば、上のスクリプトではフォームがアクティブな時に Alt + F を押すと「ファイル」メニューがアクティブになります。
  
  次に第2引数はショートカットキーの文字を表します。上のスクリプトでは「ヘルプ」メニューに'Ctrl+H'というショートカットキーが割り当てられているので、Ctrl + h を押すと、「ヘルプ」メニューがアクティブになります。

  第3引数は今までよく出てきているSymbolのオブジェクトです。10行目を例に取ると、 第3引数が :menu_file1 となっているので、このメニューのオブジェクトの参照は form.menu_file1 で行うことができます(18行目はその実例です)。

  以上の説明で 9〜13行ではメニューに「ファイル」「編集」「ヘルプ」の三つを付けていることが分かると思います。

  15〜21行はフォームのボタンが押された時のアクションです。 $flag が true の時に17〜19行が実行されます。一度この部分が実行されると、 17行で $flag に false が代入されるので、17〜19行は2度と実行されません。18行は form.menu_file1.add( Phi::MenuItem#add )で「ファイル」のメニューに「閉じる」のメニューを追加していて、19行はmenu_edit.add( Phi::MenuItem#add )で「編集」のメニューに「コピー」のメニューを追加しています。
 
  Phi::MenuItem#add は複数の Phi::MenuItem のオブジェクトを引数にとり、引数の Phi::MenuItem のオブジェクトが表すメニューを自分のメニューの下に作ります。その2のスクリプトにも例があるので、そちらの方も見てください。

  23〜25行は「ヘルプ」のメニューが押されたときのイベントを設定しています。ここではエラーメッセージを表示します。

1.1.1.1. クラスやメソッド
: Phi#
* Phi::new_menu
* Phi::new_item

: Phi::MeneItem#
* Phi::MenuItem#add
* Phi::MenuItem#on_click

1.2. その2(色々なメニュー)

  %href: ./rb/menu2.rb menu2.rb%

--ruby
001  require 'phi'
002  require 'dialogs'
003  
004  def ok_msg(msg)
005    Phi::message_dlg(msg, Phi::MT_INFORMATION, [Phi::MB_OK], 0)  
006  end
007  
008  form = Phi::Form.new(:form1, 'formです')
009  form.height = 95
010  button = Phi::Button.new(form, :button1, 'ボタン')
011  label = Phi::Label.new(form, :label1, '')
012  button.align = Phi::AL_TOP
013  label.align = Phi::AL_CLIENT
014  label.color = Phi::CL_WHITE
015  
016  Phi::new_menu(form, :menu1, [
017    menu_file = Phi::new_item('ファイル(&F)', '', :menu_file1).add(
018      Phi::new_sub_menu('サブ', :menu_sub1, [
019          Phi::new_item("チェック1", '', :menu_check1, true),
020          Phi::new_line,
021          Phi::new_item("ラジオ1", '', :menu_radio1, false),
022          Phi::new_item("ラジオ2", '', :menu_radio2, false),
023        ]),
024      Phi::new_line,
025      Phi::new_item("閉じる(&C)", '', :menu_close1)
026    ),
027    menu_edit = Phi::new_item('編集(&E)', '', :menu_edit1).add(
028      Phi::new_item('切り取り(&T)', 'Ctrl+X', :menu_cut1),
029      Phi::new_item('コピー(&C)', 'Ctrl+C', :menu_copy1),
030      Phi::new_item('貼りつけ(&P)', 'Ctrl+V', :menu_paste1)
031    ),
032    menu_help = Phi::new_item('ヘルプ(&H)', 'Ctrl+H', :menu_help1).add(
033      Phi::new_item('このソフトについて(&A)', '', :menu_about1, false, false)
034    )
035    ])
036  
037  
038  form.menu_radio1.radio_item = true
039  form.menu_radio2.radio_item = true
040  form.menu_radio1.group_index = 0
041  form.menu_radio2.group_index = 0  
042  form.menu_radio1.checked = true
043  
044    
045  # event
046  form.menu_radio1.on_click = proc do
047    unless form.menu_radio1.checked?
048      form.menu_radio1.checked = true
049    end
050  end
051  
052  form.menu_radio2.on_click = proc do
053    unless form.menu_radio2.checked?
054      form.menu_radio2.checked = true
055    end
056  end
057  
058  form.menu_check1.on_click = proc do
059    if form.menu_check1.checked?
060      form.menu_check1.checked = false
061    else
062      form.menu_check1.checked = true
063    end
064  end
065  
066  form.menu_close1.on_click = proc do
067    exit  
068  end
069  
070  form.menu_copy1.on_click = proc do
071    ok_msg('コピー')  
072  end
073  
074  button.on_click = proc do
075    if form.menu_check1.checked?
076      if form.menu_radio1.checked?
077        label.caption = 'チェック1とラジオ1がチェックされています。'
078      elsif form.menu_radio2.checked?
079        label.caption = 'チェック1とラジオ2がチェックされています。'
080      else
081        ok_msg('BUG')
082      end
083    else
084      label.caption = 'チェック1がチェックされていません。'
085    end
086  end
087    
088  form.show
089  Phi.mainloop
--

  このスクリプトを実行すると、%href: img/menu2.png このような% ウィンドウがあらわれます。

1.2.1. 解説
  15行までは分かると思います。

  16〜35行はメニューを生成しています。その1では Phi::new_menu の第3引数でメニューの先頭部分だけを生成しましたが、今回はすべてのメニューを一括して生成しています。
 
  説明が前後しますが、先に20行の Phi::new_line を説明します。 Phi::new_line は引数を取らないメソッドで、メニューの区切り線を表わす Phi::MenuItem のオブジェクトを生成します。
  
  元に戻って17行では「ファイル」メニューを生成し、生成されたメニューのadd( Phi::MenuItem#add )を使って、「ファイル」メニューの下にいくつかのメニューを生成します。この部分では Phi::new_item のすぐ後に add がきていますが、これは Ruby のメソッドチェーンというものです。ruby-listのMLの過去ログを見れば、面白い例がいくつもあるので、詳しくはそちらを参照してほしいのですが、一例をあげますと、

--ruby
#/usr/bin/ruby 
 
print File.readlines('hoge.txt').join(';').gsub('hoge','goo')
--

  のようなものがあります。これがどういうことをするのかは一度調べてみてください。

  Phi::MenuItem#add は複数の引数を取りますが、17行では Phi::new_sub_menu、Phi::new_line、Phi::new_item で生成される三つの Phi::MenuItem のオブジェクトが Phi::MenuItem#add の引数になります。これによってウィンドウ上では「サブ」、区切り線、「閉じる」の三つのメニューが「ファイル」メニューの下に生成されることになります。

  18〜24行で「サブ」の下のメニューが生成されます。生成されるメニューは「チェック1」、「ラジオ1」、区切り線、「ラジオ2」の4つです。 

  18行目の Phi::new_sub_menu は4つの引数を取りますが、ここでは第4引数が省略されています。 Phi::new_sub_menu の第1引数はメニューの文字列を、第2引数は今まで紹介してきたSymbolのオブジェクトを、第3引数は サブメニューとなる Phi::MenuItem のオブジェクトの組み合わせ( Array のオブジェクト )を取ります。第4引数は Phi::new_item の第5引数と同じものです。その詳細は Phi::new_item の説明を読んでください(スクリプトの33行目の説明です)。

  19行は Phi::new_item によって「チェック1」メニューを作っています。ここでは Phi::new_item の第4引数が true になっていることが今までと少し違います。Phi::new_item の第4引数はメニューの横にチェックマークをつけるかどうかを決めます。第4引数が省略されている場合は第4引数をfalseにしたとみなされ、チェックマークはつきません。19行では Phi::new_item の第4引数を true にしているので、「チェック1」メニューにチェックマークがつきます。

  33行以外のメニュー生成の部分についてはその1の説明やその2のこれまでの説明で分かると思うので、省略します。

  33行目では Phi::new_item に第5引数がありますが、これは数当てゲームで紹介した Phi::Button#enabled と同じような設定をしていて、第5引数をfalseにすることでメニュー項目は淡色表示になり，ユーザーはその項目を選択できなくなります。第5引数が省略された場合、第5引数は true として扱われるので、明示的にfalseにしない限りメニューが使えなくなることはありません。

  38〜42行はメニューの一部をラジオボタンと同じように使うための設定です。

  38と39行で Phi::MenuItem#radio_item に true を代入してメニューをラジオボタンのようにし、40と41行で Phi::MenuItem#group_index に 0 を代入して二つのメニューをグループ化します。最後に42行で起動時に「ラジオ1」のメニューにチェックが入るようにします。

  45〜85行はイベント処理ですが、特に難しいところはないと思います。

1.2.1.1. クラスやメソッド
: Phi#
* Phi::new_line
* Phi::new_sub_menu

: Phi::MenuItem#
* Phi::MenuItem#checked
* Phi::MenuItem#group_index
* Phi::MenuItem#radio_index

