2015年4月
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30    
無料ブログはココログ

« 2011年8月 | トップページ | 2011年11月 »

2011年9月の2件の記事

2011年9月15日 (木)

Button の右クリック

理解できれば、それまでのことだったのですが。

そろそろ(漸く?) WxRuby のドキュメント に目を通し始めました。

とりあえずは、Sizer (BoxSizer) と、Control と、Event あたりから、順にチマチマと読み進めています。

で、とりあえず、Button を並べて event handling しただけのもの

# encoding: shift_jis
require 'wx'

class MyApp < Wx::App
private
  def on_init
    MyFrame.new.show
  end
end

class MyFrame < Wx::Frame
  def initialize
    super( nil, -1, 'My Frame App' )
    top_sizer = Wx::BoxSizer.new(Wx::VERTICAL)
    set_sizer( top_sizer )

    b = []
    (1..5).each do |i|
      b[i] = Wx::Button.new( self, -1, "Label_#{i}" )
      evt_button( b[i] ) { |e| event_info( e ) }
      top_sizer.add_item( b[i], -1, :flag => Wx::EXPAND )
    end
  end

  def event_info( evt )
    print "Event : ", evt, "\n"
    obj = evt.get_event_object
    print "Object : ", obj, "\n"
    print "Label : ", obj.label, "\n" if ( obj.respond_to?(:get_label) )
    print "id : ", evt.get_id, "\n"
    print "\n"
  end
end

MyApp.new.main_loop

俗に言う、"print debug" 的に console 出力で反応を確認しているので、command prompt から実行して下さい。

で、次に、button を右クリックした時の event handling をしようとして躓きました。

Button のドキュメント を参照すると、Button の event handler には evt_button(id) { | event | ... } しかなく、右クリックを受け止める method がありません。

MouseEvent のドキュメント を見ると、evt_right_down() { | event | ... } がちゃんとあるのですが、上記のコードで、

      evt_button( b[i] ) { |e| event_info( e ) }

      evt_right_down( b[i] ) { |e| event_info( e ) }

に置き換えて実行すると、何かよく分からないエラーになります。今度は、

      evt_right_down() { |e| event_info( e ) }

で実行すると、直ぐにエラーにはならないものの、ボタンを右クリックしてもなにも起こらない。ところがボタンの表示されていない、ウインドウ下部の余白の部分を右クリックすると event を拾います。今度は、

      b[i].evt_right_down() { |e| event_info( e ) }

でやってみると、無事にボタンの右クリックでイベントを拾いました。

考えてみると、evt_button method はレシーバが指定されていないので、暗黙のレシーバである self, この場合は MyFrame の instance に message sending しているわけです。ここから、Frame 内の Button が左クリックされた場合のみ、該当する Button に event を伝え、Button 側はボタンが押し込まれて元に戻る画面処理を行うという動作なのでしょう。そして、Frame から Button に event を伝えるのは、画面処理を行う左クリックの場合のみである、と。

一方、b[i].evt_XXX のように、レシーバを特定して message を投げると、そのレシーバとなった instance に生じた任意の event を受け付けることができるので、直接右クリックを拾うことができるわけです。但し、この場合、ボタン押し下げの画面処理は行われず(自前でやればできるのでしょうが) event が拾われるだけです。

試しにと思って以下のようにコーディングしても、最初と同じように動作しました。

      b[i].evt_button( b[i] ) { |e| event_info( e ) }

ちなみに、event_info で、event を受け取った(発生された?) object の種類を表示するようにしてありますので、それを参照すると、レシーバなしで evt_button を使っても、Button に直接 evt_button を渡しても、どちらも担当 object は Wx::Button でした。レシーバなしで evt_right_down を使った場合、Frame の余白を右クリックすると、object は MyFrame に渡っています。そうすると、レシーバなしの evt_button も event はまずは MyFrame に渡るはずで、内部で更に Button に event を横流ししているんでしょうね。

ここまでで、Button に右クリックを渡す方法が分かりましたので、ボタンを左クリックすれば上に、右クリックすれば下に並び順を変えるコードを書いてみました。ちなみに、evt_XXX_YYY :method は、evt_XXX_YYY() { |event| method( event ) } の短縮記法です。

今日はここまで。

# encoding: utf-8
require 'wx'

class MyApp < Wx::App
private
  def on_init
    MyFrame.new.show
  end
end

class MyFrame < Wx::Frame
private
  def initialize
    super( nil, -1, 'My Frame App' )
    top_sizer = Wx::BoxSizer.new(Wx::VERTICAL)
    set_sizer( top_sizer )

    b = []
    (1..5).each do |i|
      b[i] = Wx::Button.new( self, -1, "Label_#{i}" )
      evt_button( b[i] ) do |e|
        up_obj( top_sizer, b[i] )
        event_info( e )
      end
      b[i].evt_right_down do |e|
        down_obj( top_sizer, b[i] )
        event_info( e )
      end
      top_sizer.add_item( b[i], -1, :flag => Wx::EXPAND )
    end
    evt_left_down :event_info
    evt_right_down :event_info
  end

  def up_obj( sizer, obj )
    children = sizer.get_children
    index = children.index{ |x| x.get_window == obj }
    if ( index && index > 0 )
      sizer.detach( obj )
      sizer.insert( index - 1, obj, 0, Wx::EXPAND )
      sizer.layout
    end
  end

  def down_obj( sizer, obj )
    children = sizer.get_children
    index = children.index{ |x| x.get_window == obj }
    if ( index && index < children.size - 1 )
      sizer.detach( obj )
      sizer.insert( index + 1, obj, 0, Wx::EXPAND )
      sizer.layout
    end
  end

  def event_info( evt )
    print "Event : ", evt, "\n"
    obj = evt.get_event_object
    print "Object : ", obj, "\n"
    print "Label : ", obj.label, "\n" if ( obj.respond_to?(:get_label) )
    print "id : ", evt.get_id, "\n"
    print "\n"
  end
end

MyApp.new.main_loop

2011年9月 3日 (土)

常用環境への ruby 1.9 & wxRuby 再導入手順控え

普段使いの環境を ruby 1.8 -> 1.9 に乗り換えたときの手順控え。

VMware でいろいろ試していたときは、元々 wxRuby と ruby 1.9 を windows 用にまとめてビルドした mingw32-ruby-1.9.1-wxruby-2.0.1-setup.exe を導入しました。一気に ruby 1.9 と wxRuby が導入できて効率がよいのですが、別件で使いたかった DevKit が動かなかったので、いわゆるOne click ruby の配布サイト から RubyInstaller 1.9.2-p290 を download して install しました。

install したら、環境変数に、install した ruby への path を通します。

今回、One click ruby を install するまでは、cygwin で ruby 1.8 を使っていました。今後は ruby は 1.9 で行きたいのですが、cygwin-ruby 1.8 も残しておくと何かの役に立つかもしれません。今回はあえて uninstall せずに、"cygwin/bin" を環境変数 path の末尾 (ruby 1.9 の path より後ろ) に回すと、コマンドプロンプトから ruby を実行すれば、ruby 1.9 が起動し、ls などの cygwin ツールもそのまま使えます。もし、どうしても ruby 1.8 を使いたければ、cygwin shell を経由すれば使えます。

One click ruby が install できれば、wxRuby を install します。ruby gems から install します。

このとき、

>gem install wxruby

だと、ruby 1.8 用の wxRuby が install されてしまい、実行時に dll がないと、エラーになります。ここでは、

>gem install wxruby-ruby19

を install して下さい。これで、無事に環境導入できました。

« 2011年8月 | トップページ | 2011年11月 »