Gtk::TextViewでカーソルのある位置の画面上での座標を取得

概要

Gtk::TextView::get_iter_location() によってカーソルのバッファ内での座標が得られるが、スクロール状態にある場合は 画面上の座標とずれてくるので、Gtk::TextView::buffer_to_window_coords() を用いてウィンドウ内座標に変換する必要がある。

ソース

textview3.cpp

#include <gtkmm.h>
#include <iostream>

class MainWin : public Gtk::Window
{
    Gtk::Window m_popup;
    Gtk::Label m_label;

    Gtk::Label m_label2;
    Gtk::VBox m_vbox;

    Gtk::ScrolledWindow m_scrwin;
    Gtk::TextView m_textview;

public:
    MainWin();
    virtual ~MainWin(){}

private:
    void on_buf_changed();
};


MainWin::MainWin()
    : m_popup( Gtk::WINDOW_POPUP )
{
    m_label.set_text( "popup" );
    m_popup.add( m_label );
    m_popup.show_all();

    // バッファ更新シグナル
    m_textview.get_buffer()->signal_changed().connect( sigc::mem_fun( *this, &MainWin::on_buf_changed ) );

    m_label2.set_text( "テスト" );
    m_scrwin.add( m_textview );

    m_vbox.pack_start( m_label2 );
    m_vbox.pack_start( m_scrwin );

    add( m_vbox );
    show_all_children();

    resize( 300,100 );
}


void MainWin::on_buf_changed()
{
    std::cout << "---------------------\n" << m_textview.get_buffer()->get_text() << std::endl
              << "何行目   = " << m_textview.get_buffer()->get_insert()->get_iter().get_line() << std::endl
              << "何文字目 = " << m_textview.get_buffer()->get_insert()->get_iter().get_line_offset() << std::endl;

    // TextView の左上の画面に対する座標
    int rx, ry;
    m_textview.get_window( Gtk::TEXT_WINDOW_TEXT )->get_origin( rx, ry );
    std::cout << "rx=" << rx << " ry = " << ry << std::endl;

    // バッファ内でのカーソル座標
    // スクロール状態は無視
    Gdk::Rectangle rect;
    m_textview.get_iter_location( m_textview.get_buffer()->get_insert()->get_iter(), rect );
    std::cout << "x=" << rect.get_x() << " y = " << rect.get_y() << std::endl;

    // ウィンドウ内でのカーソル座標
    // スクロール状態の時は TextView の左上からの座標
    int wx,wy;
    m_textview.buffer_to_window_coords( Gtk::TEXT_WINDOW_TEXT, rect.get_x(), rect.get_y(), wx, wy );
    std::cout << "wx=" << wx << " wy = " << wy << std::endl;

    m_popup.move( rx+wx, ry+wy );
}


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

    return 0;
}

コンパイル

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

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

結果

文字を入力するとカーソルの位置にポップアップが表示される。