如何在GTK中创建项目目录树视图和树存储?

时间:2018-09-25 21:20:32

标签: c gtk gtk3

我最近一直在尝试在GTK中创建项目视图时遇到问题。问题是我的程序不断删除文件并将文件添加到项目目录,但是要考虑到这些更改,需要清除并重新填充项目树视图的TreeStore。清除并重新填充TreeStore后,项目TreeView将折叠其所有标头。请看以下示例:

enter image description here

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

以下是项目视图: enter image description here

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

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

String input = io.readInput();
int[] arr = new int[5];

if(input.length() >= 5){
    String[] c = input.split(" ");
    for(int i = 0; i < c.length(); i++){
        arr[i] = Integer.parseInt(c[i]);
    }
}

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

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);
}

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

谢谢你, 维卡斯

1 个答案:

答案 0 :(得分: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);

希望这可以帮助遇到相同问题的任何人。