るいもの戯れ言

DrawingAreaは、デフォルトではマウスのイベントを拾えないようだ。発生するイベントの種類を増やすには、WidgetExt::add_event()というメソッドを使うらしい。


    let drawingArea: gtk::DrawingArea = builder.get_object("drawingarea1").unwrap();
    drawingArea.set_size_request(300, 300);
    drawingArea.add_events(gdk_sys::GDK_BUTTON_PRESS_MASK.bits() as i32);
    drawingArea.add_events(gdk_sys::GDK_BUTTON_RELEASE_MASK.bits() as i32);

JavaのSwingだと、clickedというイベントで同じ場所でマウスのボタンが押されて離されたという状態を取得できたが、どうやらGTK+には、そういうのが無いようだ。自分でPRESSの時の座標を覚えておいて、RELEASEの座標が同じだったらクリックと判定する必要がある模様。イベントハンドラの登録は、WidgetExt::connect_event()を使う。


        drawingArea.connect_event(|_, e| {
            let clone = e.clone();
            match e.get_event_type() {
                EventType::ButtonPress => {
                    let res: Result<EventButton, Event> = clone.downcast();
                    println!("pressed: {:?}", res.unwrap().get_position());
                },
                EventType::ButtonRelease => {
                    let res: Result<EventButton, Event> = clone.downcast();
                    println!("released: {:?}", res.unwrap().get_position());
                },
                _ => {}
            }
            return Inhibit(false);
        });

Event型で来るため、特定のイベントであるかをEventTypeで判定して、ダウンキャストするというなんとも汚ないコード。なぜイベント自体をenumにしなかったのかな。GTK+との関係で難しいのだろうか。

クロージャの引数は&Eventで、downcastの引数は、&selfではなくてselfそのものなので、そのままイベントを渡すとmoveが起きてしまってコンパイルエラーになる。なので、一度clone()している。

コードサンプルは、こちら