【问题标题】:How do you create a project directory tree view and tree store in GTK?如何在 GTK 中创建项目目录树视图和树存储?
【发布时间】:2018-09-25 21:20:31
【问题描述】:

我最近在尝试在 GTK 中创建项目视图时遇到了一个问题。问题是我的程序不断删除文件并将其添加到项目目录中,但为了解决这些更改,需要清除并重新填充项目树视图的 TreeStore。当 TreeStore 被清除并重新填充时,TreeView 项目会折叠其所有标题。举个例子:

这是程序在 MainProject 下添加另一个名为“SubProject2”的文件夹之前的项目视图,清除 TreeModel,并用相同的目录重新填充它。

这是之后的项目视图:

请注意,文件夹“SubProject2”已正确添加到“MainProject”下,但 TreeView 折叠了“MainProject”。

我当前用于重新填充 TreeView 的代码如下:

void populate_directory_tree_store(GtkTreeStore *treestore, const char *directory, GtkTreeIter *toplevel) {
    DIR *dir;
    struct dirent *entry;

    GtkTreeIter child;

    if (!(dir = opendir(directory)))
        return;

    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_type == DT_DIR) {
            char path[1024];
            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
                continue;
            snprintf(path, sizeof(path), "%s/%s", directory, entry->d_name);

            gtk_tree_store_append(treestore, &child, toplevel);
            gtk_tree_store_set(treestore, &child,
                0, entry->d_name,
                -1);

            populate_directory_tree_store(treestore, path, &child);
        }
        else {
            gtk_tree_store_append(treestore, &child, toplevel);
            gtk_tree_store_set(treestore, &child,
                0, entry->d_name,
                -1);
        }
    }
    closedir(dir);
}

每次更改项目目录时,我都会这样调用函数:

gtk_tree_store_clear(treestore);
populate_directory_tree_store(treestore, "C:\\Projects", &topIterator);

我曾考虑使用 libfswatch (located here) 之类的库来实时检测目录更改并随每次更改更改项目 TreeView,但它需要多线程。我不知道我是否忽略了 GtkTreeView 中的某些内容,但是这种微不足道的事情应该不会那么困难。如果您有任何问题或反馈,请发布。

谢谢你, 维卡斯

【问题讨论】:

    标签: c gtk gtk3


    【解决方案1】:

    我解决此问题的方法是在清除 TreeView 之前将展开的行存储在数据结构中。我使用了一个键控数据列表来关联扩展行的名称及其对应的深度(行名是键,深度是值)。然后我清除 TreeView 并像往常一样重新填充它。之后,我逐行遍历 TreeModel。如果行名是键控数据列表中的键,并且该行的深度与键控数据列表的深度值相同,我会展开该行。代码如下:

    num
    {
        COL_NAME = 0,
        NUM_COLS
    };
    
    void populate_directory_tree_store(GtkTreeStore *treestore, const char *directory, GtkTreeIter *toplevel) {
        DIR *dir;
        struct dirent *entry;
    
        GtkTreeIter child;
    
        if (!(dir = opendir(directory)))
            return;
    
        while ((entry = readdir(dir)) != NULL) {
            if (entry->d_type == DT_DIR) {
                char path[1024];
                if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
                    continue;
                snprintf(path, sizeof(path), "%s/%s", directory, entry->d_name);
    
                gtk_tree_store_append(treestore, &child, toplevel);
                gtk_tree_store_set(treestore, &child,
                    0, entry->d_name,
                    -1);
    
                populate_directory_tree_store(treestore, path, &child);
            }
            else {
                gtk_tree_store_append(treestore, &child, toplevel);
                gtk_tree_store_set(treestore, &child,
                    0, entry->d_name,
                    -1);
            }
        }
        closedir(dir);
    }
    
    void foreach_expanded_row(GtkTreeView *tree_view, GtkTreePath *path, gpointer user_data) {
        GData **datalist = user_data;
    
        GtkTreeStore *treestore = GTK_TREE_STORE(gtk_tree_view_get_model(tree_view));
    
        GValue key = G_VALUE_INIT;
    
        char *treePathString = gtk_tree_path_to_string(path);
    
        GtkTreeIter treeIter;
        gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(treestore), &treeIter, treePathString);
        gtk_tree_model_get_value(GTK_TREE_MODEL(treestore), &treeIter, COL_NAME, &key);
    
        g_datalist_id_set_data(datalist, g_quark_from_string(g_value_get_string(&key)), GINT_TO_POINTER(gtk_tree_path_get_depth(path)));
    }
    
    gboolean foreach_tree_model_row(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data) {
        struct combined_data {
            GData **datalist;
            GtkTreeView *treeview;
        };
    
        struct combined_data *cd = data;
    
        GData **datalist = cd->datalist;
        GtkTreeView *treeview = cd->treeview;
    
        GValue key = G_VALUE_INIT;
    
        char *treePathString = gtk_tree_path_to_string(path);
    
        GtkTreeIter treeIter;
        gtk_tree_model_get_iter_from_string(model, &treeIter, treePathString);
        gtk_tree_model_get_value(model, &treeIter, COL_NAME, &key);
    
        int depth = g_datalist_get_data(datalist, g_value_get_string(&key));
    
        if (depth && gtk_tree_path_get_depth(path) == depth) {
            gtk_tree_view_expand_row(treeview, path, FALSE);
        }
    
        return FALSE;
    }
    
    void refresh_tree_view(GtkTreeView *treeview, GtkTreeStore *treestore) {
        GData *datalist;
    
        g_datalist_init(&datalist);
    
        gtk_tree_view_map_expanded_rows(treeview, foreach_expanded_row, &datalist);
    
        GtkTreeIter toplevel;
        gtk_tree_store_clear(treestore);
        gtk_tree_store_append(treestore, &toplevel, NULL);
        gtk_tree_store_set(treestore, &toplevel, 0, "MainProject", -1);
    
        populate_directory_tree_store(treestore, "C:\\Projects, &toplevel);
    
        struct combined_data {
            GData **datalist;
            GtkTreeView *treeview;
        };
    
        struct combined_data *cd = malloc(sizeof(struct combined_data));
    
        cd->datalist = &datalist;
        cd->treeview = treeview;
    
        gtk_tree_model_foreach(GTK_TREE_MODEL(treestore), foreach_tree_model_row, cd);
    
        free(cd);
    }
    

    每次我需要用当前目录更新项目视图时,我只需调用

    refresh_tree_view(treeview, treestore);
    

    希望这对遇到同样问题的人有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-18
      • 2023-03-14
      • 2013-08-16
      • 2016-07-05
      • 2010-10-15
      相关资源
      最近更新 更多