有没有复制 Gtk 小部件的好方法?

发布于 2024-09-04 16:32:01 字数 970 浏览 9 评论 0原文

有没有一种方法,使用 C 中的 Gtk 库来克隆 Gtk 按钮(例如),并将其打包到应用程序中的其他位置。我知道你不能将同一个小部件打包两次。这段代码显然不起作用,但显示了当我尝试按钮的浅拷贝时会发生什么:

GtkButton *a = g_object_new(GTK_TYPE_BUTTON, "label", "o_0", NULL);
GtkButton *b = g_memdup(a, sizeof *a);
gtk_box_pack_start_defaults(GTK_BOX(vbox), GTK_WIDGET(b));

周围的代码创建了一个 vbox 并将其打包在一个窗口中并运行 gtk_main()。这将导致这些难以理解的错误消息:

(main:6044): Gtk-CRITICAL **: gtk_widget_hide: assertion `GTK_IS_WIDGET (widget)' failed

(main:6044): Gtk-CRITICAL **: gtk_widget_realize: assertion `GTK_WIDGET_ANCHORED (widget) || GTK_IS_INVISIBLE (widget)' failed
**
Gtk:ERROR:/build/buildd/gtk+2.0-2.18.3/gtk/gtkwidget.c:8431:gtk_widget_real_map: assertion failed: (GTK_WIDGET_REALIZED (widget))

同样,如果我要编写自己的 GObject(不一定是 Gtk 小部件),是否有一个好的方法来编写复制构造函数。我认为它应该是一个带有可选钩子的接口,并且主要基于属性,以某种方式处理类的层次结构。

我想这样做:

GtkButton *b = copyable_copy(COPYABLE(a));

如果 GtkButton 可以使用理论上的可复制界面。

Is there a way, using the Gtk library in C, to clone a Gtk button (for instance), and pack it somewhere else in the app. I know you can't pack the same widget twice. And that this code obviously wouldn't work, but shows what happens when I attempt a shallow copy of the button:

GtkButton *a = g_object_new(GTK_TYPE_BUTTON, "label", "o_0", NULL);
GtkButton *b = g_memdup(a, sizeof *a);
gtk_box_pack_start_defaults(GTK_BOX(vbox), GTK_WIDGET(b));

There is surrounding code which creates a vbox and packs it in a window and runs gtk_main(). This will result in these hard to understand error messages:

(main:6044): Gtk-CRITICAL **: gtk_widget_hide: assertion `GTK_IS_WIDGET (widget)' failed

(main:6044): Gtk-CRITICAL **: gtk_widget_realize: assertion `GTK_WIDGET_ANCHORED (widget) || GTK_IS_INVISIBLE (widget)' failed
**
Gtk:ERROR:/build/buildd/gtk+2.0-2.18.3/gtk/gtkwidget.c:8431:gtk_widget_real_map: assertion failed: (GTK_WIDGET_REALIZED (widget))

Along the same lines, if I were to write my own GObject (not necessarily a Gtk widget), is there a good way to write a copy constructor. Im thinking it should be an interface with optional hooks and based mostly on the properties, handling the class's hierarchy in some way.

I'd want to do this:

GtkButton *b = copyable_copy(COPYABLE(a));

If GtkButton could use a theoretical copyable interface.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

软糖 2024-09-11 16:32:01

我不这么认为。据我所知,不能保证小部件将其所有状态保留在属性中,以便您可以从外部访问。如果一个小部件通过不导出来“隐藏”状态,那么您就无法从外部复制它。

从技术上讲,小部件可以只在其核心 struct 中包含您从实现外部看不到的字段,因此您甚至无法使用愚蠢的 memcpy() 复制这些位。 code>,除非您愿意通过手动计数并使用文字来指定字节数。

话虽如此,也很可能有足够多的小部件通过属性公开足够的状态,使得副本仍然可以运行,并且可能只出现一些小故障。这肯定是一个非常酷的黑客。我建议直接询问核心 GTK+ 开发人员,也许可以在 gtk-devel-list 上询问邮件列表。

I don't think so. As far as I know, there's no guarantee that widgets keep all their state in properties, that you can access from the outside. If a widget "hides" state by not exporting it, there's no way you can copy it from the outside.

Technically, widgets can just include fields in their core struct that you don't see from outside of the implementation, so you can't even copy the bits using a dumb memcpy(), unless you're willing to specify the byte-count by counting manually and using a literal.

That being said, it's also quite possible that enough widgets expose enough state through properties that a copy would still function, and perhaps only exhibit minor glitches. It would certainly be a pretty cool hack. I would recommend asking the core GTK+ developers directly, perhaps on the gtk-devel-list mailing list.

冰魂雪魄 2024-09-11 16:32:01

通过属性进行克隆是一个可行的解决方案:

GObject *
g_object_clone(GObject *src)
{
    GObject *dst;
    GParameter *params;
    GParamSpec **specs;
    guint n, n_specs, n_params;

    specs = g_object_class_list_properties(G_OBJECT_GET_CLASS(src), &n_specs);
    params = g_new0(GParameter, n_specs);
    n_params = 0;

    for (n = 0; n < n_specs; ++n)
        if (strcmp(specs[n]->name, "parent") &&
            (specs[n]->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE) {
            params[n_params].name = g_intern_string(specs[n]->name);
            g_value_init(¶ms[n_params].value, specs[n]->value_type);
            g_object_get_property(src, specs[n]->name, ¶ms[n_params].value);
            ++ n_params;
        }

    dst = g_object_newv(G_TYPE_FROM_INSTANCE(src), n_params, params);
    g_free(specs);
    g_free(params);

    return dst;
}

克隆小部件并不是那么简单,但上述方法在大多数情况下都是可用的(当然在 GtkButton 上)。

我不关心许多未通过属性公开的状态(所有正确的小部件都应由属性完全定义,以便可与 GtkBuilder 一起使用),但许多极端情况将使健壮的克隆变得相当困难(我首先想到的是接口和容器)。

A clone throught properties is a viable solution:

GObject *
g_object_clone(GObject *src)
{
    GObject *dst;
    GParameter *params;
    GParamSpec **specs;
    guint n, n_specs, n_params;

    specs = g_object_class_list_properties(G_OBJECT_GET_CLASS(src), &n_specs);
    params = g_new0(GParameter, n_specs);
    n_params = 0;

    for (n = 0; n < n_specs; ++n)
        if (strcmp(specs[n]->name, "parent") &&
            (specs[n]->flags & G_PARAM_READWRITE) == G_PARAM_READWRITE) {
            params[n_params].name = g_intern_string(specs[n]->name);
            g_value_init(¶ms[n_params].value, specs[n]->value_type);
            g_object_get_property(src, specs[n]->name, ¶ms[n_params].value);
            ++ n_params;
        }

    dst = g_object_newv(G_TYPE_FROM_INSTANCE(src), n_params, params);
    g_free(specs);
    g_free(params);

    return dst;
}

Cloning a widget is not that trivial though, but the above approach is usable in most cases (on a GtkButton for sure).

I'd not care that much of states not exposed with properties (all proper widgets should be fully defined by properties to be usable with GtkBuilder) but a lot of corner cases will make a robust cloning quite difficult (interfaces and containers being the first ones that come to my mind).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文