Gtk::ScrolledWindow と Gtk::EventBox の順番

概要

Gtk::Image などの "no window" ウィジットでイベントを取得するにはGtk::EventBoxに貼る(add)必要が あるが、さらに Gtk::ScrolledWindow と組み合わせるときにウィジットを貼る順番を間違えると一部の イベントが正常に取得できないことがある。

例えばGtk::Image -> Gtk::EventBox -> Gtk::ScrolledWindow の順に貼っても、 Gtk::Image -> Gtk::ScrolledWindow -> Gtk::EventBox の順に貼っても表示は同じであるが、 後者の場合はマウスのボタンを押しながらのmotion_notifyイベントを取得できない。

従って正しくイベントを取得するには "no window" ウィジット -> Gtk::EventBox -> Gtk::ScrolledWindow の 順に貼る必要がある。

ソース

eventscr.cpp (わざとマウスボタンを押しながらのmotion_notifyイベントを取得出来ないようにしてある)
#include <gtkmm.h>
#include <iostream>

class MainWin : public Gtk::Window
{
    Gtk::Image m_img;
    Gtk::ScrolledWindow m_scr;
    Gtk::EventBox m_event;

public:
    MainWin();

private:
    bool slot_motion_notify_event( GdkEventMotion* event ){ std::cout << "motion\n"; }
};


MainWin::MainWin() : m_img( "./test.png" )
{
    m_event.add_events( Gdk::POINTER_MOTION_MASK );
    m_event.signal_motion_notify_event()
           .connect( sigc::mem_fun( *this, &MainWin::slot_motion_notify_event ) );

    m_scr.add( m_img );
    m_event.add( m_scr );
    add( m_event );

    show_all_children();
}

int main( int argc, char *argv[] )
{
    Gtk::Main kit( argc, argv );
    MainWin mainwin;
    Gtk::Main::run( mainwin );

    return 0;
}

コンパイル

必要なコンパイルオプションは pkg-config を使って取得する。

g++ eventscr.cpp -o eventscr `pkg-config gtkmm-2.4 --cflags --libs`

結果

上のコードではマウスボタンを押さないときにマウスを動かすと "motion" という文字が表示されるが、 マウスボタンを押しながらマウスを動かすと何も表示されない。そこでMainWin()を次のように変更する。
MainWin::MainWin() : m_img( "./test.png" )
{
    m_event.add_events( Gdk::POINTER_MOTION_MASK );
    m_event.signal_motion_notify_event()
           .connect( sigc::mem_fun( *this, &MainWin::slot_motion_notify_event ) );

    m_event.add( m_img );
    m_scr.add( m_event );
    add( m_scr );
    
    show_all_children();
}
Widgetをaddする順番に注意。今度はマウスボタンを押しながらマウスを動かしたときでも"motion"と表示される。