GTK 使用 Glade 将用户数据传递给回调

Sco*_*ott 3 c gtk signals glade callback

我注意到 Glade 只允许您设置要在 GTK 回调的用户数据部分中传递的对象。

有什么方法可以传递整数值吗?

我有一组菜单项,我想将它们指向同一个回调函数,但是对于一小部分代码,我需要确定哪个菜单项是调用回调的菜单项。

注意:我的所有信号都是使用glade_xml_signal_autoconnect自动设置的,我更愿意保持这种方式。

use*_*332 5

在我看来,关于空地和回调,我们必须告别仅将一个元素传递给回调的概念。因此停止使用glade以配置传递给特定回调的用户数据。

\n\n

我习惯于App向所有回调传递一个名为的结构,该结构包含指向从 ui 定义文件加载并已由 实例化的每个 ui 元素的指针GtkBuilderglade这也停止了在小部件之间来回单击以设置回调的用户数据的繁琐任务。除了 ui 元素之外,大多数情况下,此结构还包含在应用程序级别运行时很重要的其他元素。

\n\n

这种方法的一个好处是,您不会想考虑如何实现应该对多个元素执行操作的单独回调(通常情况下)。有些人通过将感兴趣的小部件分组到容器中来解决这个问题。为了将所有小部件传递给回调,它们只需传递容器。然后在回调中,他们通过调用gtk_container_get_children或类似的函数来获取小部件。这种方法使回调难以辨认,并减少了编辑代码时的乐趣。

\n\n

如果每个回调都具有应在运行时操作的所有可用元素,则您不必关心实现单个回调,因为每个回调共享相同的结构。

\n\n

此外,我创建了一个辅助宏,它定义了一个指向已实例化元素的指针,其名称为空地 ID。这样,代码中的元素定义始终与空地中显示的元素定义保持同步。这使得小部件的重命名变得非常容易(替换所有源中的名称+空地文件)。

\n\n

为了说明这种方法,我附加了示例程序的文件。不要害怕文件的数量。将程序划分为逻辑单元/模块使编程变得更加简单。为了快速查看整个项目,我在 github 上创建了一个 git 存储库:

\n\n
\n

https://github.com/o8i12398z12h9h/gtk-sample-app

\n
\n\n

只需将我的callbacks.c回调文件与您的回调文件进行比较即可。我很想知道它们在易读性和结构方面的比较,并考虑到您可能glade仍然记得元素 ID。

\n\n
\n\n

callbacks.c:

\n\n
#include "app.h"\n\nvoid\nbutton1_clicked_cb (GtkButton * button, App * app)\n{\n    GET_UI_ELEMENT (GtkEntry, entry1);\n\n    if (gtk_entry_get_text_length (entry1) == 0)\n        gtk_entry_set_text (entry1, "test");\n    else\n        gtk_entry_set_text (entry1, "");\n}\n\nvoid\nbutton2_clicked_cb (GtkButton * button, App * app)\n{\n    gboolean active;\n\n    GET_UI_ELEMENT (GtkSpinner, spinner1);\n    GET_UI_ELEMENT (GtkWidget, eventbox1);\n\n    g_object_get (G_OBJECT (spinner1), "active", &active,\n                  NULL);\n\n    if (active) {\n        gtk_spinner_stop (spinner1);\n        gtk_widget_override_background_color (eventbox1,\n                                              GTK_STATE_FLAG_NORMAL,\n                                              app->\n                                              active_color);\n    }\n    else {\n        gtk_spinner_start (spinner1);\n        gtk_widget_override_background_color (eventbox1,\n                                              GTK_STATE_FLAG_NORMAL,\n                                              app->\n                                              inactive_color);\n    }\n}\n\nvoid\nbutton3_clicked_cb (GtkButton * button, App * app)\n{\n    GdkRGBA bg = { 0, 0, 1, 1 };\n\n    GET_UI_ELEMENT (GtkWidget, eventbox1);\n\n    gtk_widget_override_background_color (eventbox1,\n                                          GTK_STATE_FLAG_NORMAL,\n                                          &bg);\n}\n\nvoid\nbutton4_clicked_cb (GtkButton * button, App * app)\n{\n    const gchar *str;\n\n    GET_UI_ELEMENT (GtkLabel, label1);\n\n    str = gtk_label_get_text (label1);\n\n    if (strcmp (str, "label") == 0) {\n        gtk_label_set_text (label1, "NewText");\n    }\n    else {\n        gtk_label_set_text (label1, "label");\n    }\n}\n\nvoid\nbutton5_clicked_cb (GtkButton * button, App * app)\n{\n    GET_UI_ELEMENT (GtkWidget, button1);\n    GET_UI_ELEMENT (GtkWidget, button2);\n    GET_UI_ELEMENT (GtkWidget, button4);\n\n    g_signal_emit_by_name (button1, "clicked", app);\n    g_signal_emit_by_name (button2, "clicked", app);\n    g_signal_emit_by_name (button4, "clicked", app);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

main.c:

\n\n
#include "app.h"\n\nint\nmain (int argc, char *argv[])\n{\n    App *app;\n\n    app = (App *) g_new (App, 1);\n\n    gtk_init (&argc, &argv);\n\n    app_init (app);\n\n    GET_UI_ELEMENT (GtkWidget, window1);\n\n    gtk_widget_show_all (window1);\n\n    gtk_main ();\n\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

app.c:

\n\n
#include "app.h"\n\nGObject *\napp_get_ui_element (App * app, const gchar * name)\n{\n    const gchar *s;\n    GSList *list;\n\n    list = app->objects;\n\n    do {\n        s = gtk_buildable_get_name (list->data);\n\n        if (strcmp (s, name) == 0) {\n            return list->data;\n        }\n\n    } while (list = g_slist_next (list));\n\n    return NULL;\n}\n\nvoid\napp_init_colors (App * app)\n{\n    GdkRGBA active_color = { 1, 0, 0, 1 };\n    GdkRGBA inactive_color = { 0, 1, 0, 1 };\n\n    app->active_color = g_new0 (GdkRGBA, 1);\n    app->inactive_color = g_new0 (GdkRGBA, 1);\n\n    app->active_color = gdk_rgba_copy (&active_color);\n    app->inactive_color = gdk_rgba_copy (&inactive_color);\n}\n\n\nvoid\napp_init (App * app)\n{\n    GError *err = NULL;\n\n    app->definitions = gtk_builder_new ();\n\n    gtk_builder_add_from_file (app->definitions,\n                               UI_DEFINITIONS_FILE, &err);\n\n    if (err != NULL) {\n        g_printerr\n            ("Error while loading app definitions file: %s\\n",\n             err->message);\n        g_error_free (err);\n        gtk_main_quit ();\n    }\n\n    gtk_builder_connect_signals (app->definitions, app);\n\n    app->objects = gtk_builder_get_objects (app->definitions);\n\n    app_init_colors (app);\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

app.h:

\n\n
#ifndef __APP__\n#define __APP__\n\n#include <gtk/gtk.h>\n\n#define UI_DEFINITIONS_FILE "ui.glade"\n\n#define GET_UI_ELEMENT(TYPE, ELEMENT)   TYPE *ELEMENT = (TYPE *) \\\n                                            app_get_ui_element(app, #ELEMENT);\n\ntypedef struct app_\n{\n    GtkBuilder *definitions;\n    GSList *objects;\n\n    GdkRGBA *active_color;\n    GdkRGBA *inactive_color;\n\n} App;\n\nvoid app_init (App * );\nGObject * app_get_ui_element (App * , const gchar * );\n\n#endif\n
Run Code Online (Sandbox Code Playgroud)\n\n

ui.glade:

\n\n
<?xml version="1.0" encoding="UTF-8"?>\n<interface>\n  <!-- interface-requires gtk+ 3.0 -->\n  <object class="GtkWindow" id="window1">\n    <property name="can_focus">False</property>\n    <property name="border_width">20</property>\n    <signal name="destroy" handler="gtk_main_quit" swapped="no"/>\n    <child>\n      <object class="GtkGrid" id="grid1">\n        <property name="visible">True</property>\n        <property name="can_focus">False</property>\n        <property name="row_spacing">10</property>\n        <property name="column_spacing">20</property>\n        <child>\n          <object class="GtkSpinner" id="spinner1">\n            <property name="visible">True</property>\n            <property name="can_focus">False</property>\n          </object>\n          <packing>\n            <property name="left_attach">1</property>\n            <property name="top_attach">1</property>\n            <property name="width">2</property>\n            <property name="height">1</property>\n          </packing>\n        </child>\n        <child>\n          <object class="GtkEventBox" id="eventbox1">\n            <property name="height_request">50</property>\n            <property name="visible">True</property>\n            <property name="can_focus">False</property>\n            <child>\n              <placeholder/>\n            </child>\n          </object>\n          <packing>\n            <property name="left_attach">1</property>\n            <property name="top_attach">2</property>\n            <property name="width">2</property>\n            <property name="height">1</property>\n          </packing>\n        </child>\n        <child>\n          <object class="GtkEntry" id="entry1">\n            <property name="visible">True</property>\n            <property name="can_focus">True</property>\n            <property name="invisible_char">\xe2\x80\xa2</property>\n            <property name="invisible_char_set">True</property>\n          </object>\n          <packing>\n            <property name="left_attach">1</property>\n            <property name="top_attach">0</property>\n            <property name="width">2</property>\n            <property name="height">1</property>\n          </packing>\n        </child>\n        <child>\n          <object class="GtkLabel" id="label1">\n            <property name="visible">True</property>\n            <property name="can_focus">False</property>\n            <property name="label" translatable="yes">label</property>\n          </object>\n          <packing>\n            <property name="left_attach">1</property>\n            <property name="top_attach">3</property>\n            <property name="width">2</property>\n            <property name="height">1</property>\n          </packing>\n        </child>\n        <child>\n          <object class="GtkButtonBox" id="buttonbox1">\n            <property name="visible">True</property>\n            <property name="can_focus">False</property>\n            <property name="spacing">10</property>\n            <property name="layout_style">center</property>\n            <child>\n              <object class="GtkButton" id="button1">\n                <property name="label" translatable="yes">toggle entry</property>\n                <property name="use_action_appearance">False</property>\n                <property name="visible">True</property>\n                <property name="can_focus">True</property>\n                <property name="receives_default">True</property>\n                <property name="use_action_appearance">False</property>\n                <signal name="clicked" handler="button1_clicked_cb" swapped="no"/>\n              </object>\n              <packing>\n                <property name="expand">False</property>\n                <property name="fill">True</property>\n                <property name="position">0</property>\n              </packing>\n            </child>\n            <child>\n              <object class="GtkButton" id="button2">\n                <property name="label" translatable="yes">toggle spinner + bg</property>\n                <property name="use_action_appearance">False</property>\n                <property name="visible">True</property>\n                <property name="can_focus">True</property>\n                <property name="receives_default">True</property>\n                <property name="use_action_appearance">False</property>\n                <signal name="clicked" handler="button2_clicked_cb" swapped="no"/>\n              </object>\n              <packing>\n                <property name="expand">False</property>\n                <property name="fill">True</property>\n                <property name="position">1</property>\n              </packing>\n            </child>\n            <child>\n              <object class="GtkButton" id="button3">\n                <property name="label" translatable="yes">set bg</property>\n                <property name="use_action_appearance">False</property>\n                <property name="visible">True</property>\n                <property name="can_focus">True</property>\n                <property name="receives_default">True</property>\n                <property name="use_action_appearance">False</property>\n                <signal name="clicked" handler="button3_clicked_cb" swapped="no"/>\n              </object>\n              <packing>\n                <property name="expand">False</property>\n                <property name="fill">True</property>\n                <property name="position">2</property>\n              </packing>\n            </child>\n            <child>\n              <object class="GtkButton" id="button4">\n                <property name="label" translatable="yes">toggle label</property>\n                <property name="use_action_appearance">False</property>\n                <property name="visible">True</property>\n                <property name="can_focus">True</property>\n                <property name="receives_default">True</property>\n                <property name="use_action_appearance">False</property>\n                <signal name="clicked" handler="button4_clicked_cb" swapped="no"/>\n              </object>\n              <packing>\n                <property name="expand">False</property>\n                <property name="fill">True</property>\n                <property name="position">3</property>\n              </packing>\n            </child>\n            <child>\n              <object class="GtkButton" id="button5">\n                <property name="label" translatable="yes">toggle everything</property>\n                <property name="use_action_appearance">False</property>\n                <property name="visible">True</property>\n                <property name="can_focus">True</property>\n                <property name="receives_default">True</property>\n                <property name="use_action_appearance">False</property>\n                <signal name="clicked" handler="button5_clicked_cb" swapped="no"/>\n              </object>\n              <packing>\n                <property name="expand">False</property>\n                <property name="fill">True</property>\n                <property name="position">4</property>\n              </packing>\n            </child>\n          </object>\n          <packing>\n            <property name="left_attach">0</property>\n            <property name="top_attach">5</property>\n            <property name="width">4</property>\n            <property name="height">1</property>\n          </packing>\n        </child>\n        <child>\n          <object class="GtkSeparator" id="separator1">\n            <property name="visible">True</property>\n            <property name="can_focus">False</property>\n          </object>\n          <packing>\n            <property name="left_attach">0</property>\n            <property name="top_attach">4</property>\n            <property name="width">4</property>\n            <property name="height">1</property>\n          </packing>\n        </child>\n        <child>\n          <placeholder/>\n        </child>\n        <child>\n          <placeholder/>\n        </child>\n        <child>\n          <placeholder/>\n        </child>\n        <child>\n          <placeholder/>\n        </child>\n        <child>\n          <placeholder/>\n        </child>\n        <child>\n          <placeholder/>\n        </child>\n        <child>\n          <placeholder/>\n        </child>\n        <child>\n          <placeholder/>\n        </child>\n      </object>\n    </child>\n  </object>\n</interface>\n
Run Code Online (Sandbox Code Playgroud)\n