GTK3自定义单元格渲染器,输出小部件

编程入门 行业动态 更新时间:2024-10-26 18:23:25
本文介绍了GTK3自定义单元格渲染器,输出小部件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我正在寻找一种在TreeView单元中输出随机窗口小部件的方法.

I'm looking for a way to output random widgets in the TreeView cells.

这些小部件的生命周期是由我在父级TreeView外部手动控制的100%.到目前为止,您无需担心键盘导航和可访问性.我现在得到的是经过修改的官方示例.

The lifecycle of these widgets is 100% controlled by me manually outside of the parent TreeView. Don't care about keyboard navigation and accessibility (so far). What I got by now is a modified official example.

标题:

#include <gtk/gtk.h> #define TYPE_RECKLESS_CELL_RENDERER (reckless_cell_renderer_get_type()) #define RECKLESS_CELL_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), TYPE_RECKLESS_CELL_RENDERER, RecklessCellRenderer)) #define RECKLESS_CELL_RENDERER_CLASS(clz) (G_TYPE_CHECK_CLASS_CAST ((clz), TYPE_RECKLESS_CELL_RENDERER, RecklessCellRendererClass)) #define IS_CELL_PROGRESS_PROGRESS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_RECKLESS_CELL_RENDERER)) #define IS_CELL_PROGRESS_PROGRESS_CLASS(clz) (G_TYPE_CHECK_CLASS_TYPE ((clz), TYPE_RECKLESS_CELL_RENDERER)) #define RECKLESS_CELL_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_RECKLESS_CELL_RENDERER, RecklessCellRendererClass)) typedef struct _RecklessCellRenderer RecklessCellRenderer; typedef struct _RecklessCellRendererClass RecklessCellRendererClass; struct _RecklessCellRenderer { GtkCellRenderer parent; GtkWidget *cell; }; struct _RecklessCellRendererClass { GtkCellRendererClass parent_class; }; GType reckless_cell_renderer_get_type(void); GObject* reckless_cell_renderer_new(void);

Impl:

#include "reckless_cell_renderer.h" static void reckless_cell_renderer_init(RecklessCellRenderer *cell); static void reckless_cell_renderer_class_init(RecklessCellRendererClass *clz); static void reckless_cell_renderer_get_property(GObject *object, guint param_id, GValue *value, GParamSpec *pspec); static void reckless_cell_renderer_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec); static void reckless_cell_renderer_finalize(GObject *gobject); static void reckless_cell_renderer_get_size(GtkCellRenderer *cell, GtkWidget *widget, const GdkRectangle *cell_area, gint *x_offset, gint *y_offset, gint *width, gint *height); static void reckless_cell_renderer_render(GtkCellRenderer *cell, cairo_t *ctx, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState state); enum { PROP_CELL = 1, }; static gpointer parent_class; GType reckless_cell_renderer_get_type(void) { static GType cell__type = 0; if (cell__type) return cell__type; if (1) { static const GTypeInfo cell__info = { sizeof(RecklessCellRendererClass), NULL, NULL, (GClassInitFunc) reckless_cell_renderer_class_init, NULL, NULL, sizeof(RecklessCellRenderer), 0, (GInstanceInitFunc) reckless_cell_renderer_init, }; cell__type = g_type_register_static(GTK_TYPE_CELL_RENDERER, "RecklessCellRenderer", &cell__info, 0); } return cell__type; } static void reckless_cell_renderer_init(RecklessCellRenderer *cellrenderer) { } static void reckless_cell_renderer_class_init(RecklessCellRendererClass *clz) { GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(clz); GObjectClass *object_class = G_OBJECT_CLASS(clz); parent_class = g_type_class_peek_parent(clz); object_class->finalize = reckless_cell_renderer_finalize; object_class->get_property = reckless_cell_renderer_get_property; object_class->set_property = reckless_cell_renderer_set_property; cell_class->get_size = reckless_cell_renderer_get_size; cell_class->render = reckless_cell_renderer_render; g_object_class_install_property(object_class, PROP_CELL, g_param_spec_pointer("cell", "Cell", "Widget to display", G_PARAM_READWRITE)); } static void reckless_cell_renderer_finalize(GObject *object) { /* RecklessCellRenderer *cellrenderer = RECKLESS_CELL_RENDERER(object); */ (*G_OBJECT_CLASS(parent_class)->finalize)(object); } static void reckless_cell_renderer_get_property(GObject *object, guint param_id, GValue *value, GParamSpec *psec) { RecklessCellRenderer *cell = RECKLESS_CELL_RENDERER(object); switch (param_id) { case PROP_CELL: g_value_set_pointer(value, cell->cell); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, psec); break; } } static void reckless_cell_renderer_set_property(GObject *object, guint param_id, const GValue *value, GParamSpec *pspec) { RecklessCellRenderer *cell = RECKLESS_CELL_RENDERER(object); switch (param_id) { case PROP_CELL: cell->cell = g_value_get_pointer(value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, param_id, pspec); break; } } GObject* reckless_cell_renderer_new(void) { return g_object_new(TYPE_RECKLESS_CELL_RENDERER, NULL); } static void reckless_cell_renderer_get_size(GtkCellRenderer *cell, GtkWidget *widget, const GdkRectangle *cell_area, gint *x_offset, gint *y_offset, gint *width, gint *height) { gint calc_width; gint calc_height; RecklessCellRenderer *rc = RECKLESS_CELL_RENDERER(cell); gtk_widget_get_size_request(rc->cell, &calc_width, &calc_height); if (width) { *width = calc_width; } if (height) { *height = calc_height; } if (cell_area) { if (x_offset) { *x_offset = (cell_area->width - *width); *x_offset = MAX(*x_offset, 0); } if (y_offset) { *y_offset = (cell_area->height - *height); *y_offset = MAX(*y_offset, 0); } } } static void reckless_cell_renderer_render(GtkCellRenderer *cell, cairo_t *ctx, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState state) { RecklessCellRenderer *rc = RECKLESS_CELL_RENDERER(cell); gtk_widget_size_allocate(rc->cell, cell_area); gtk_widget_draw(rc->cell, ctx); }

尽管它不会崩溃,并且单元格指针始终有效(我在客户端代码中明确照顾了它),但未绘制项目.我完全确定我会错过一些非常重要的事情,例如小部件的寿命或绘制周期,但由于缺乏知识,我自己无法克服.

Though it does not crash, and the cell pointer is always valid (I explicitly look after it in the client code), the items are not drawn. I'm totally sure I miss something utterly important like the widget life or draw cycle, but cannot overcome it myself, due to the lack of knowledge.

我在这里想念什么?真的有可能吗?

What do I miss here? Is it actually a possible case at all?

推荐答案

令人惊讶的是,问题中的代码很好.对于代码来说,这些改变是必需的,该代码将"child"初始化为"child". (或更确切地说是"item",请参见下文)小部件.

Surprisingly, the code in the question is fine. The changes are required for the code, that initializes "child" (or rather "item", see below) widgets.

通常,当您使用普通的容器小部件并向其添加子级时,该容器会运行子级的初始化,这是完整功能(即绘图,信号发送等)所必需的.TreeView不是容器,因此其项目"在初始化时需要帮助.这是通过在每个子代上针对父代TreeView手动调用gtk_widget_set_parent()/gtk_widget_unparent()来完成的.但是,有一个陷阱.每次将父级TreeView锚定到窗口并从窗口取消锚定时,也应该调用gtk_widget_set_parent()/gtk_widget_unparent(),通常是通过收听hierarchy-changed信号.

Normally, when you use the normal container widget, adding children to it, the container runs the initialization of a child, required for the full functionality, i.e. drawing, signaling etc. TreeView is not a container, and so its "items" require help on initialization. This is done by manually calling gtk_widget_set_parent()/gtk_widget_unparent() on each child against a parent TreeView. However, there is a catch. gtk_widget_set_parent()/gtk_widget_unparent() should be also called each time the parent TreeView is anchored to the window and deanchored from it, usually via listening to hierarchy-changed signal.

不幸的是,我使用的调用代码是用另一种语言编写的,该语言没有像C语言那样直接利用GTK API,所以我不能在这里提供它.尽管这很简单:收听hierarchy-changed信号,然后根据是否设置了根窗口,调用gtk_widget_set_parent(item_widget, tree_view)或gtk_widget_unparent(item_widget),以及问题中的自定义单元格渲染器.最后但并非最不重要的一点是-项目小部件生命周期管理是您100%的责任,您必须手动检查所有悬空的指针.

Unfortunately, the calling code I use, is written in another language, which does not utilize GTK API directly, as in C, so I cannot provide it here. Though it is trivial: listen to the hierarchy-changed signal, and, depending on whether a root window is set or not, call gtk_widget_set_parent(item_widget, tree_view) or gtk_widget_unparent(item_widget), plus the custom cell renderer from the question. Last, but not least - item widgets lifecycle management is 100% your responsibility, you have to check all the dangling pointers manually.

小更新:在绘制过程中,Cairo上下文必须相应地移动到绘制坐标.因此,这是完整的抽奖程序:

Small update: in the draw procedure the Cairo context has to be shifted accordingly to the draw coordinates. So here is the full draw procedure:

static void reckless_cell_renderer_render(GtkCellRenderer *cell, cairo_t *ctx, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState state) { GdkRectangle allo; cairo_save(ctx); allo.x = cell_area->x; allo.y = cell_area->y; allo.width = cell_area->width; allo.height = cell_area->height; RecklessCellRenderer *rc = RECKLESS_CELL_RENDERER(cell); gtk_widget_size_allocate(rc->cell, &allo); cairo_translate(ctx, allo.x, allo.y); gtk_widget_draw(rc->cell, ctx); cairo_restore(ctx); }

更多推荐

GTK3自定义单元格渲染器,输出小部件

本文发布于:2023-11-23 02:08:02,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1619708.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:自定义   部件   单元格   渲染器

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!