Gtk::TreeViewでリスト表示をする

C++で GTKアプリケーションを作る例が世の中に少なすぎてサンプルを探すのに苦労するので自分でネットに上げておく

2021年9月28日 嶋田大貴

ツリービューでリスト表示したい三銃士を連れてきたよ」

「えっ、C++でGTKを!?」

「インタラクション担当、Gtk::TreeView

「型定義担当、Gtk::TreeModelColumnRecord

「データストア担当、Gtk::ListStore

カラム数分の Gtk::TreeModelColumn<T> を作って Gtk::TreeModelColumnRecordオブジェクトに addしたらそれを使って Gtk::ListStoreを構築、さらにそれを Gtk::TreeView に set_modelする。さらに TreeViewに対してもカラムごとにappend_columnでモデルとの紐付けと当時にタイトルの設定をする必要がある。行の追加操作イテレーションなどは ListStoreに対して行う。

カラムの型によって自動的にそれ用のレンダラーが選択されるあたり、張り切ってC++していると言える。(boolのカラムに注目)

ユーザーがリストのアイテムを選択した時のイベントを拾うには TreeViewの signal_cursor_changed シグナルを使う。

画面イメージ

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

class MainWindow : public Gtk::Window {
    Gtk::Box box;
    Gtk::Button button;

    Gtk::TreeView treeview;
    Gtk::TreeModelColumnRecord columnrecoed;

    struct {
        Gtk::TreeModelColumn<std::string> col1;
        Gtk::TreeModelColumn<bool> col2;
        Gtk::TreeModelColumn<int> col3;
    } columns;

    Glib::RefPtr<Gtk::ListStore> liststore;

public:
    MainWindow();
    virtual void on_realize();
    void erase_items_have_even_num();
};

MainWindow::MainWindow() : box(Gtk::Orientation::VERTICAL)
{
    columnrecoed.add(columns.col1);
    columnrecoed.add(columns.col2);
    columnrecoed.add(columns.col3);
    liststore = Gtk::ListStore::create(columnrecoed);
    treeview.set_model(liststore);
    treeview.append_column("文字列", columns.col1);
    treeview.append_column("真偽値", columns.col2);
    treeview.append_column("整数", columns.col3);
    treeview.signal_cursor_changed().connect([this]() {
        auto selected_row = treeview.get_selection()->get_selected();
        if (selected_row) {
            std::cout << selected_row->get_value(columns.col1) << " selected." << std::endl;
        }
    });
    box.append(treeview);

    button.set_label("偶数のやつを消す");
    button.signal_clicked().connect([this]() { erase_items_have_even_num(); });
    box.append(button);

    set_child(box);
}

void MainWindow::on_realize()
{
    Gtk::Window::on_realize();
    liststore->clear();

    auto row = *liststore->append();
    row[columns.col1] = std::string("ぼぎゃー");
    row[columns.col2] = true;
    row[columns.col3] = 123;

    row = *liststore->append();
    row[columns.col1] = std::string("もげー");
    row[columns.col2] = false;
    row[columns.col3] = 456;
}

void MainWindow::erase_items_have_even_num()
{
    auto i = liststore->get_iter("0");
    while (i) {
        if (i->get_value(columns.col3) % 2 == 0) {
            i = liststore->erase(i);
        } else {
            i++;
        }
    }
}

int main(int argc, char* argv[])
{
    auto app = Gtk::Application::create("com.walbrix.simple_list_using_treeview");

    return app->make_window_and_run<MainWindow>(argc, argv);
}

// g++ -std=c++20 -o simple_list_using_treeview simple_list_using_treeview.cpp `pkg-config --cflags --libs gtkmm-4.0`

2021年9月28日 嶋田大貴

記事一覧へ戻る