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

1. ツリービュー

  IEのお気に入りやMozillaのブックマークのような木構造を表すためのコントロールです。

1.1. その1

  %href: ./rb/treeview1.rb treeview1.rb%

--ruby
001  require 'phi'
002  
003  form = Phi::Form.new(:form1, 'フォームです')
004  edit = Phi::Edit.new(form, :edit1, '')
005  edit.align = Phi::AL_BOTTOM
006  treeview = Phi::TreeView.new(form, :treeview1, '')
007  treeview.align = Phi::AL_CLIENT
008  nodes = treeview.items
009  
010  nodes.add(nil, '1')
011  nodes.add(nil, '2')
012  child_node = nodes.add(nil, '3')
013  
014  nodes.add_child(child_node, '3-1')
015  nodes.add_child(child_node, '3-2')
016  nodes.add_child(child_node, '3-3')
017  
018  treeview.on_click = proc do
019    unless treeview.selected.nil?
020      edit.text = treeview.selected.text
021    end
022  end
023  
024  form.show
025  Phi.mainloop
--

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

1.1.1. 解説
  6行目がツリービューを生成しているところです。 Phi::TreeView.new の使い方はいつもと同じです。

  8行目で treeview.items( Phi::TreeView#items ) を nodes に代入しています。 Phi::TreeView#items はツリービューの項目全体を表すオブジェクト( Phi::TreeNodes )で、これを使うことでツリーの項目を操作することができます。このスクリプトでは何回も Phi::TreeNodes のオブジェクトを使うので、nodes に代入して簡単に参照できるようにしています。

  10〜12行はnodes.addを使ってツリーの一番上に「1」「2」「3」の項目を追加しています。nodes.add( Phi::TreeNodes#add )の第1引数を nil にすることで、ツリーの一番上の部分に項目が追加され、第2引数によって追加された項目の文字列が設定されます。

  14〜16行はツリーの「3」の項目に「3-1」「3-2」「3-3」の項目を追加しています。nodes.add_child( Phi::TreeNodes#add_child )は子ノード(子の項目)を追加するためのメソッドで、第1引数には親ノード( Phi::TreeNode のオブジェクト ) を、第2引数は子ノードに表示する文字列を指定します。

  18〜22行はツリービューをクリックした時のイベントハンドラです。 Phi::TreeView#on_click が何に使われるかはすぐ分かりますよね。 treeview.selected( Phi::TreeView#selected )は現在選択されている項目(ノード)を表す属性なので、19行の treeview.selected.nil? は選択されている項目がある時に true を返します。20行は選択された項目の文字列をエディットに表示させます。この行で使われている TreeNode#text は項目の文字列を得るための属性です。

1.1.1.1. クラスやメソッド
: Phi::ListView#
* Phi::ListView.new
* Phi::ListView#align ( < Phi::Control#align )
* Phi::ListView#items
* Phi::ListView#on_click ( < Phi::Control#on_click )
* Phi::ListView#selected

: Phi::TreeNodes#
* Phi::TreeNodes#add
* Phi::TreeNodes#add_child

: Phi::TreeNode#
* Phi::TreeNode#text

1.2. その2

  %href: ./rb/treeview2.rb treeview2.rb%

--ruby
001  require 'phi'
002  require 'find'
003  require 'dialogs'
004  
005  form = Phi::Form.new(:form1, 'フォームです')
006  form.height = 400
007  
008  panel = Phi::Panel.new(form, :form1, '')
009  panel.align = Phi::AL_TOP
010  panel.height = 24
011  button = Phi::Button.new(panel, :button1, 'フォルダ選択')
012  button.align = Phi::AL_RIGHT
013  button.width = 100
014  edit = Phi::Edit.new(panel, :edit1, '')
015  edit.align = Phi::AL_CLIENT
016  edit.width = panel.width - button.width
017  edit.text = 'd:/docu/document/apollo'
018  
019  show_btn = Phi::Button.new(form, :show_btn1, '表示')
020  show_btn.align = Phi::AL_BOTTOM
021  
022  treeview = Phi::TreeView.new(form, :treeview1, '')
023  treeview.align = Phi::AL_CLIENT
024  nodes = treeview.items
025  
026  button.on_click = proc do 
027    result_path = ''
028    if Phi::select_dir('フォルダーを選択してください', '/', result_path)
029      edit.text = result_path
030      form.set_focus
031    end
032  end
033  
034  show_btn.on_click = proc do
035    if edit.text != '' and FileTest::directory?(edit.text)
036      nodes.clear
037      nodes.update {
038        path = File::expand_path(edit.text)
039        dir = {}
040        top_node = nodes.add(nil, File::dirname(path))
041        dir[File::dirname(path)] = top_node
042        Find::find(edit.text) do |f|
043          dirname = File::dirname(f)
044          node = nodes.add_child(dir[dirname], File::basename(f))
045          if FileTest::directory?(f)
046            dir[f] = node
047          end
048        end
049      }
050    else
051      Phi::message_dlg(edit.text + ' はフォルダーではありません。', 
052  		     Phi::MT_ERROR, [Phi::MB_OK], 0)
053    end
054  end
055  
056  form.show
057  Phi.mainloop
--

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

1.2.1. 解説
  このスクリプトは %href: http://ruby.freak.ne.jp/gtk/ Ruby/GTKチュートリアル% のTreeウィジェットの章で紹介されているスクリプトを Apollo に移植したものです(少し手を入れています)。このスクリプトでは指定されたフォルダの一つ上のフォルダをツリーのトップにして、その下にあるファイルやフォルダをツリー状に表示することができます。このスクリプトは少し難しいので、Rubyに馴れていない人はFindのモジュールを使った他のRubyスクリプトを読んでから、このスクリプトを読んだ方が良いかもしれません。

  2行目はRubyに標準添付されているFindモジュールを使うためのおまじないです。

  8行目は Phi::Panel のオブジェクトを生成しています。これはウィンドウの上の方にある ボタンとエディットをまとめている部分です。このスクリプトではボタンとエディットでパネルの部分を完全に覆っているので、パネルを見ることはできません。

  8〜24行は分かると思います。

  26〜32行は画面の上にある「フォルダ選択」ボタンが押された時のイベントハンドラを設定しています。28行目の Phi::select_dir はディレクトリ選択のダイアログを表示させるためのメソッドです。%href: img/select_dir.png ディレクトリ選択のダイアログの図%

  図を見てもらえば分かりますが、Phi::select_dirの第1引数はダイアログに表示される文字列を表しています。第2引数はダイアログに表示される一番上のフォルダーを指定します。これは '/' から変更する必要はないと思います。最後の第3引数にはユーザーが選択したフォルダのパスが代入される変数が入ります。27行で result_path を初期化しているのはこのためです。 Phi::select_dir はダイアログの「OK」ボタンを押した時にtrueになります。

  28行で Phi::select_dir の返り値がtrueの場合、29行によってユーザーが選択したフォルダのパスがエディットに設定され、フォーカスがフォームに合わせられます。

  34〜54行は「フォルダーを選択してください」のボタンが押されたときのイベントハンドラです。35行はエディットの文字列が適切なものかどうか調べています。エディットの文字列が適切なものでない場合は51〜53行が実行されてメッセージダイアログが表示されます。一方、エディットの文字列が適切な場合は、36〜49行が実行されます。

  36行は nodes.clear( Phi::TreeNodes#clear )によって今までツリーに表示されていた項目がすべて消去されます。

  37行の nodes.update( Phi::TreeNodes#update )は{}に囲われた部分(今回の場合は38〜48行)がすべて実行されるまで画面描画を抑制するために使われます。

  例えば、 Phi::TreeNodes#update を使わずに100単位の項目をツリーに追加すると、項目を追加する度に画面が描画されるため項目の追加が非常に遅くなります。これを防ぐのが Phi::TreeNodes#update です。

  Delphiの TTreeNodes.BeginUpdate と TTreeNodes.EndUpdate に当たるメソッドが Phi::TreeNodes#update になるので、Delphiを使っている人は注意してください。

  38行ではエディットの文字列を Phi::expand_path を使ってフルパスに変換し、path に代入します。40行では nodes.add によって一番上のノードが追加されます。ここではエディットで指定されたパス名より一つ上のフォルダが追加されます。41行ではパス名が鍵、値が最上位のノード( Phi::TreeNode のオブジェクト )となるように Hash のオブジェクトに値をセットしています。

  42行はFindモジュールのfindメソッドを使っています。 Find::find ではイテレーターが使われていて、Find::find の引数となるフォルダを探索し、指定されたフォルダの下にあるファイル名が順に f に代入されます。例えば、下のスクリプトでは 「d:/docu/document」 の下にあるすべてのファイルが標準出力に表示されます。

--ruby
require 'find'

Find::find('d:/docu/document') do |f|
  print f
end
--

  43行でfのファイル名をフォルダー名とベース名に分離し、44行で項目を追加しています。ここの第1引数が何故 dir[dirname] になるのかについては考えてみてください。46行は f がフォルダーの時に実行され、dir に新しい鍵と値の関係がセットされます。

1.2.1.1. クラスやメソッド
: Rubyの組み込みモジュール
* FileTest

: Rubyに標準添付されているモジュール
* Find

: Rubyの組み込みクラス
* File

: Phi#
* Phi::select_dir

: Phi::Panel#
* Phi::Panel.new

: Phi::TreeNodes#
* Phi::TreeNodes#clear
* Phi::TreeNodes#update

