ユーニックス総合研究所

  • home
  • archives
  • gtk-tree-view-dir

Gtk3のGtkTreeViewにフォルダ構造を表示する

  • 作成日: 2021-12-25
  • 更新日: 2023-12-24
  • カテゴリ: Gtk3

Gtk3のGtkTreeViewにフォルダ構造を表示する

Gtk3のGtkTreeViewを使うとアイテムをリストにして表示したりできます。
他には指定のパスのフォルダ構造を再帰的に表示するということもできます。
これはエディタやWindowsのエクスプローラーなどでよく見るファイルシステムのツリー表示です。

ググったんですがこれぞ! というコードが見つからずけっこうハマりました。
なにか参考になれば幸いです。

適度置き換えてください。

/**  
 * 再帰的にstoreにデータをセットする  
 */  
static void  
re_tree(  
    GtkTreeStore *store,  // モデル  
    const char *path,  // 処理するディレクトリのパス  
    GtkTreeIter *parent  // 親のイテレーター  
) {  
    // フォルダを開く  
    PadDir *dir = PadDir_Open(path);  
    if (!dir) {  
        g_error("フォルダの読み込みに失敗しました。 %s", path);  
        return;  
    }  

    GtkTreeIter current;  

    // フォルダの中を走査する  
    for (PadDirNode *node; (node = PadDir_Read(dir)); ) {  
        // ノードの名前(ファイル名 or フォルダ名)  
        const char *n_name_ = PadDirNode_Name(node);  

        // Windows環境ではノード名がCP932になっている  
        // そのためここでCP932をUTF8に変換する  
        gchar *n_name = g_convert(  
            n_name_, -1, "UTF8", "CP932", NULL, NULL, NULL  
        );  
        if (!n_name) {  
            // 変換に失敗したらcontinue  
            g_warning("failed to conv cp932 to utf8: [%s]", n_name_);  
            continue;  
        }  

        // ノードのタイプ  
        PadDirNodeType n_type = PadDirNode_Type(node);  

        if (n_type == PAD_DIR_NODE_TYPE__DIR) {  
            // ノードがフォルダだったら  
            // カレントと親フォルダは除く  
            if (!strcmp(n_name, ".") || !strcmp(n_name, "..")) {  
                continue;  
            }  

            // ノードからパスを生成する  
            char dir_path[1024];  
            snprintf(dir_path, sizeof dir_path, "%s/%s", path, n_name);  

            // モデルにデータを追加  
            // 0カラム目にn_name, 隠し要素の1カラム目にパスをセットする  
            gtk_tree_store_append (store, &current, parent);  
            gtk_tree_store_set (store, &current,  
                                0, n_name,  
                                1, dir_path,  
                                -1);  

            // 再帰呼び出し  
            // currentを親にする  
            re_tree(store, dir_path, &current);  
        } else {  
            // ノードがフォルダ以外だったら  
            // ファイルのパスを生成する  
            char file_path[1024];  
            snprintf(file_path, sizeof file_path, "%s/%s", path, n_name);  

            // モデルにデータを追加  
            // 0カラム目にn_name, 隠し要素の1カラム目にパスをセットする  
            gtk_tree_store_append (store, &current, parent);  
            gtk_tree_store_set (store, &current,  
                                0, n_name,  
                                1, file_path,  
                                -1);  
        }  

        g_free(n_name);  
    }  

    // フォルダを閉じる  
    PadDir_Close(dir);  
}  

/**  
 * dir_pathを解析してツリービューにフォルダ構造を表示する  
 */  
static void  
analyze_dir(const char *dir_path) {  
    // ツリービューを取得  
    GtkTreeView *view = get_tree_view();  

    // ツリービューのヘッダーを設定  
    GtkCellRenderer *renderer = gtk_cell_renderer_text_new();  
    gtk_tree_view_insert_column_with_attributes(  
        GTK_TREE_VIEW (view),  
        -1,        
        "フォルダ一覧",  // ヘッダーのカラムに表示するテキスト  
        renderer,  
        "text", 0,  
        NULL  
    );  

    // モデルをセットする  
    GtkTreeStore *store = gtk_tree_store_new(  
        2,  
        G_TYPE_STRING,  // アイテムの名前  
        G_TYPE_STRING   // アイテムのパス (hidden)  
    );  
    GtkTreeIter top_level;  

    // フォルダのパスからベース名を取得  
    // このベース名がルートのアイテムのテキストになる  
    char top_dir_name[PAD_FILE__NPATH];  
    PadFile_BaseName(top_dir_name, sizeof top_dir_name, dir_path);  

    // モデルにルートのアイテムを設定  
    gtk_tree_store_clear(store);  
    gtk_tree_store_append(store, &top_level, NULL);  
    gtk_tree_store_set(store, &top_level, 0, top_dir_name, -1);  

    // 再帰的にツリーを構築  
    re_tree(store, dir_path, &top_level);  

    // ツリービューにモデルをセット  
    GtkTreeModel *model = GTK_TREE_MODEL(store);  
    gtk_tree_view_set_model(GTK_TREE_VIEW(view), model);  
    g_object_unref(model);  
}