Button の右クリック
理解できれば、それまでのことだったのですが。
そろそろ(漸く?) WxRuby のドキュメント に目を通し始めました。
とりあえずは、Sizer (BoxSizer) と、Control と、Event あたりから、順にチマチマと読み進めています。
で、とりあえず、Button を並べて event handling しただけのもの
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 | ... } がちゃんとあるのですが、上記のコードで、
を
に置き換えて実行すると、何かよく分からないエラーになります。今度は、
で実行すると、直ぐにエラーにはならないものの、ボタンを右クリックしてもなにも起こらない。ところがボタンの表示されていない、ウインドウ下部の余白の部分を右クリックすると event を拾います。今度は、
でやってみると、無事にボタンの右クリックでイベントを拾いました。
考えてみると、evt_button method はレシーバが指定されていないので、暗黙のレシーバである self, この場合は MyFrame の instance に message sending しているわけです。ここから、Frame 内の Button が左クリックされた場合のみ、該当する Button に event を伝え、Button 側はボタンが押し込まれて元に戻る画面処理を行うという動作なのでしょう。そして、Frame から Button に event を伝えるのは、画面処理を行う左クリックの場合のみである、と。
一方、b[i].evt_XXX のように、レシーバを特定して message を投げると、そのレシーバとなった instance に生じた任意の event を受け付けることができるので、直接右クリックを拾うことができるわけです。但し、この場合、ボタン押し下げの画面処理は行われず(自前でやればできるのでしょうが) event が拾われるだけです。
試しにと思って以下のようにコーディングしても、最初と同じように動作しました。
ちなみに、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 ) } の短縮記法です。
今日はここまで。
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
最近のコメント