簡単な描画ツールを作成2(オフスクリーン使用)

概要

簡単な描画ツールを作成する。今回はオフスクリーンを使用する

前回作ったツールはウィンドウを切り替えるなどして再描画を行うと 画像が消えていた。そこで今回はオフスクリーンを使用して再描画を 行っても画像が消えないようにする。

オフスクリーンとしてGdk::Pixmapを使用する。Gdk::Pixmapは Gdk::Windowと同じくGdk::Drawableのサブクラスであるから描画系のメンバ 関数を使用して画像を描くことが出来る。オフスクリーンに描いた画像は on_expose_event()でdraw_drawable()を使って表のスクリーンにコピーする。 またオフスクリーンに描画したらqueue_draw()によって再描画を行う。 それ以外は基本的に前回とほとんど変わらない。

ソース

drawpic2.cpp

#include <gtkmm.h>

class MyDrawArea : public Gtk::DrawingArea
{
    Glib::RefPtr< Gdk::Pixmap > m_pixmap;
    Glib::RefPtr< Gdk::GC > m_gc;

    // ポインタの以前の座標
    int m_pre_x;
    int m_pre_y;
    
public:
    MyDrawArea();

private:
    void draw_line( int x1, int y1, int x2, int y2 );
    
protected:
    virtual void on_realize();
    bool on_expose_event( GdkEventExpose* event );
    virtual bool on_button_press_event( GdkEventButton* event );
    virtual bool on_motion_notify_event( GdkEventMotion* event );
};

MyDrawArea::MyDrawArea()
{
    // OFFになってるイベントを追加
    add_events( Gdk::BUTTON_PRESS_MASK | Gdk::POINTER_MOTION_MASK );
}

void MyDrawArea::on_realize()
{
    // 元のon_realize()へのコールを忘れないこと
    Gtk::DrawingArea::on_realize(); 

    // オフスクリーン作成
    m_pixmap = Gdk::Pixmap::create( get_window(), get_width(), get_height() );
    m_gc = Gdk::GC::create( m_pixmap );

    // 背景を白く塗りつぶし
    int width = get_width();
    int height = get_height();
    m_gc->set_rgb_fg_color( Gdk::Color( "white" ) );
    m_pixmap->draw_rectangle( m_gc, true, 0, 0, width, height );
}

bool MyDrawArea::on_expose_event( GdkEventExpose* event )
{
    // オフスクリーンから画像をコピーするだけなのでデフォルトのGCを使う
    get_window()->draw_drawable( get_style()->get_fg_gc( get_state() ),
                                 m_pixmap,
                                 event->area.x, event->area.y, event->area.x, event->area.y,
                                 event->area.width, event->area.height );
    return true;
}

// 線を引く
void MyDrawArea::draw_line( int x1, int y1, int x2, int y2 )
{
    m_gc->set_rgb_fg_color( Gdk::Color( "red" ) );
    m_gc->set_line_attributes( 4, Gdk::LINE_SOLID, Gdk::CAP_ROUND, Gdk::JOIN_ROUND );
    m_pixmap->draw_line( m_gc, x1, y1, x2, y2 );

    // 再描画依頼
    queue_draw();
}

// マウスクリック
bool MyDrawArea::on_button_press_event( GdkEventButton* event )
{
    m_pre_x = (int)event->x;
    m_pre_y = (int)event->y;
    draw_line( m_pre_x, m_pre_y, m_pre_x, m_pre_y );

    return true;
}

// マウスをドラッグした
bool MyDrawArea::on_motion_notify_event( GdkEventMotion* event )
{
    if( event->state == Gdk::BUTTON1_MASK ){

        int x2 = (int)event->x;
        int y2 = (int)event->y;

        draw_line( m_pre_x, m_pre_y, x2, y2 );

        m_pre_x = x2;
        m_pre_y = y2;
    }

    return true;
}


class MainWin : public Gtk::Window
{
    MyDrawArea m_drawarea;

public:

    MainWin(){
        resize( 400, 400 );

        add( m_drawarea );
        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++ drawpic2.cpp -o drawpic2 `pkg-config gtkmm-2.4 --cflags --libs`

結果

再描画を行っても画像は消えなくなる