Chinaunix首页 | 论坛 | 博客
  • 博客访问: 156331
  • 博文数量: 36
  • 博客积分: 372
  • 博客等级: 一等列兵
  • 技术积分: 282
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-28 17:04
文章分类

全部博文(36)

文章存档

2012年(36)

分类: LINUX

2012-12-21 19:23:22

      转自: http://guoyinghui2012.blog.163.com/blog/static/20871720020127414710886/
     有一种其它类型的内置模型,叫做GtkTreeStore,它组织了一个多行多级的树形结构。也可以用GtkTreeStore树形模型来实现一个列表,但是一般不推荐这么做,因为当对象假定它有一个或者多个孩子的时候,会带来额外的开销。
        Figure 8-5展示了一个树形存储器,它包括两个根节点,每个都有自己的孩子。通过点击一行左边的扩展按钮,您可以显示或者隐藏它的孩子。这和GtkExpander构件提供的功能类似。

8.3 使用GtkTreeStore - 郭映辉 - 郭映辉
 
        用GtkTreeStore实现的GtkTreeView,和GtkListStore实现的唯一区别在于,创建的存储模型不同。添加列和渲染器,在两种 方法中实现方式一样,因为列是视图的一部分,而不属于模型,因此Listing 8-2不包括setup_tree_view()的实现。
        Listing 8-2将原始的Grocery List程序修改了一些,把产品分成类型。这个列表包括两个类型:清洁用品和食物,它们都有自己的孩子。初始化的时候,每类的数量都是零,因为这是实时计算的。

        Listing 8-2 创建一个GtkTreeStore(treestore.c)
        #include

        enum
        {
            BUY_IT = 0,
            QUANTITY,
            PRODUCT,
            COLUMNS
        };

        enum
        {
            PRODUCT_CATEGORY,
            PRODUCT_CHILD
        };

        typedef struct
        {
            gint product_type;
            gboolean buy;
            gint quantity;
            gchar *product;
        } GroceryItem;

        GroceryItem list[] =
        {
            { PRODUCT_CATEGORY, TRUE, 0, "Cleaning Supplies" },
            { PRODUCT_CHILD, TRUE, 1, "Paper Towels" },
            { PRODUCT_CHILD, TRUE, 3, "Toilet Paper" },
            { PRODUCT_CATEGORY, TRUE, 0, "Food" },
            { PRODUCT_CHILD, TRUE, 2, "Bread" },
            { PRODUCT_CHILD, FALSE, 1, "Butter" },
            { PRODUCT_CHILD, TRUE, 1, "Milk" },
            { PRODUCT_CHILD, FALSE, 3, "Chips" },
            { PRODUCT_CHILD, TRUE, 4, "Soda" },
            { PRODUCT_CATEGORY, FALSE, 0, NULL }
        };

        /* The implementation of this function is the same as in Listing 8-1. */
        static void setup_tree_view (GtkWidget*);
        int main (int argc,
                      char *argv[])
        {
            GtkWidget *window, *treeview, *scrolled_win;
            GtkTreeStore *store;
            GtkTreeIter iter, child;
            guint i = 0, j;

            gtk_init (&argc, &argv);

            window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
            gtk_window_set_title (GTK_WINDOW (window), "Grocery List");
            gtk_container_set_border_width (GTK_CONTAINER (window), 10);
            gtk_widget_set_size_request (window, 275, 300);

            treeview = gtk_tree_view_new ();
            setup_tree_view (treeview);

            store = gtk_tree_store_new (COLUMNS, G_TYPE_BOOLEAN, G_TYPE_INT, G_TYPE_STRING);

            while (list[i].product != NULL)
            {
                /* If the product type is a category, count the quantity of all of the products
                * in the category that are going to be bought. */
                if (list[i].product_type == PRODUCT_CATEGORY)
                {
                    j = i + 1;

                    /* Calculate how many products will be bought in the category. */
                    while (list[j].product != NULL && list[j].product_type != PRODUCT_CATEGORY)
                    {
                        if (list[j].buy)
                            list[i].quantity += list[j].quantity;
                        j++;
                    }

                    /* Add the category as a new root element. */
                    gtk_tree_store_append (store, &iter, NULL);
                    gtk_tree_store_set (store, &iter, BUY_IT, list[i].buy,
                                                    QUANTITY, list[i].quantity, PRODUCT, list[i].product, -1);
                }
                /* Otherwise, add the product as a child of the category. */
                else
                {
                    gtk_tree_store_append (store, &child, &iter);
                    gtk_tree_store_set (store, &child, BUY_IT, list[i].buy,
                                                    QUANTITY, list[i].quantity, PRODUCT, list[i].product, -1);
                }

                i++;
            }

            gtk_tree_view_set_model (GTK_TREE_VIEW (treeview), GTK_TREE_MODEL (store));
            gtk_tree_view_expand_all (GTK_TREE_VIEW (treeview));
            g_object_unref (store);

            scrolled_win = gtk_scrolled_window_new (NULL, NULL);
            gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
                                                                GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);

            gtk_container_add (GTK_CONTAINER (scrolled_win), treeview);
            gtk_container_add (GTK_CONTAINER (window), scrolled_win);
            gtk_widget_show_all (window);

            gtk_main ();
            return 0;
        }

        树存储由gtk_tree_store_new()来初始化,它接受和gtk_list_store_new()同样的参数。这些包括列的数据的数量,紧跟着是一个队列,包括每列对应的数据类型。
        向一个树存储器中添加行,与向列表存储中添加行,稍有区别。通过gtk_tree_store_append()向树存储器中添加行,接受两个迭代器,而不是一个。当函数返回时,第一个迭代器指向插入的行位置,第二个迭代器指向新行的父亲的行位置。

        gtk_tree_store_append (store, &iter, NULL);

        在前面的gtk_tree_store_append()调用中,向列表中附加的根元素传递的NULL,它表示父迭代器。迭代器iter用于设置新行的位置。第一个迭代器不需要被重新初始化,因为当函数返回以后,当前内容会被覆盖。
        跟在后面的第二个gtk_tree_store_append()调用,行作为孩子被添加到iter中。接着,在函数返回时,树存储器中的子树迭代器被设置成为新行的当前位置。

        gtk_tree_store_append (store, &child, &iter);

        正如列表存储器,有许多可用的函数可以向树存储器中添加行。这包括gtk_tree_store_insert()、 gtk_tree_store_prepend()和gtk_tree_store_insert_before()等。如果想查看完整的函数列表,您可 以参阅GtkTreeStore API文档。
        在您想树存储器添加一行以后,它只是一个简单的空行。调用gtk_tree_store_set(),给一行添加一行。这个函数和 gtk_list_store_set()的工作方式相同。它接受树存储器,指向行位置的树迭代器,还有一个以-1结束的“列-数据”对。这些列对应的是 那些您设置单元渲染器属性使用的东西。

        gtk_tree_store_set (store, &child, BUY_IT, list[i].buy, QUANTITY, list[i].quantity,
                                        PRODUCT, list[i].product, -1);

        除此之外,还提供了gtk_tree_store_clear(),它可以用于删除树存储器中的所有行。您就剩下一个没有数据的GtkTreeStore。如果这个对象没有其它地方使用,他就会被解引用。
        在Listing 8-2中,调用gtk_main()之前,调用gtk_tree_view_expand_all()来展开所有的行。这是个递归函数,它会展开每个可能 展开的行,当然它只会影响到有父子关系的树模型。除此之外,您可以通过gtk_tree_view_collapse_all()来收起所有的行。默认状 态下,所有的行都是收起的。
阅读(3767) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~