560 字
3 分钟
GTK 学习笔记——事件和信号
2025-04-30

前言#

在 GTK 应用中,事件(Event)是通过信号(Signal)来触发的,类似 JS 前端开发中所使用的 EventListener。在点击控件后,不同的控件会发送不同的信号,例如 BoxListRow 会发送 row-activated 信号,当程序捕捉到此信号后,便可根据信号携带的参数进行对应的操作。

使用方法#

此处以 GtkBoxList 为例。我们新建一个 Gnome 项目,其结构如下:

├── COPYING
├── data
│   ├── icons
│   │   ├── hicolor
│   │   │   ├── scalable
│   │   │   │   └── apps
│   │   │   │       └── com.example.svg
│   │   │   └── symbolic
│   │   │       └── apps
│   │   │           └── com.example-symbolic.svg
│   │   └── meson.build
│   ├── meson.build
│   ├── com.example.desktop.in
│   ├── com.example.gschema.xml
│   ├── com.example.metainfo.xml.in
│   └── com.example.service.in
├── meson.build
├── po
│   ├── LINGUAS
│   ├── meson.build
│   └── POTFILES.in
├── README.md
├── src
│   ├── gtk
│   │   └── help-overlay.ui
│   ├── main.c
│   ├── meson.build
│   ├── example-application.c
│   ├── example-application.h
│   ├── example.gresource.xml
│   ├── example-window.c
│   ├── example-window.h
│   └── example-window.ui
└── com.example.json

example-window.ui 中,我们新增一个 GtkBoxList 控件,并添加若干个 GtkBoxListRow 子控件,同时赋予其 idname 属性。

<object class="GtkListBox" id="box_list">
    <property name="selection-mode">none</property>
    <child>
        <object class="GtkListBoxRow" id="home_btn">
        <property name="child">
            <object class="GtkLabel">
            <property name="label">Home</property>
            </object>
        </property>
        </object>
    </child>
    <child>
        <object class="GtkListBoxRow" id="settings_btn">
        <property name="child">
            <object class="GtkLabel">
            <property name="label">Settings</property>
            </object>
        </property>
        </object>
    </child>
</object>

example-window.c 中,我们需要在 _ExampleWindow 结构体中添加 GtkBoxList 的指针:

struct _ExampleWindow
{
    AdwApplicationWindow parent_instance;
    
    GtkListBox	*box_list;
}

然后在 example_window_class_init 中将其绑定到窗口中:

static void
example_window_class_init(ExampleWindowClass *klass)
{
	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
	
    gtk_widget_class_set_template_from_resource (widget_class, "/com/example/example-window.ui");
    gtk_widget_class_bind_template_child (widget_class, V2raygWindow, box_list);
}

然后我们在写一个事件处理函数,用于实现不同的功能:

static void
on_row_activated (GtkListBox *box, GtkListBoxRow *row, gpointer user_data)
{
    ExampleWindow *self = EXAMPLE_WINDOW (user_data); // EXAMPLE_WINDOW () 是用于强制转换类型的方法,可以将 user_data 转换成 ExampleWindow 类型的变量
    
    int index = gtk_list_box_row_get_index (row); // 获取被点击的 GtkListBoxRow 的行索引,其实就是此控件在 GtkListBox 数组中的位置
    
    switch (index)
    {
        case "0": ...; break;
        case "1": ...; break;
        default:
            return;
    }
    
    ... // 其他处理流程
}

最后,我们需要将信号连接到 on_row_activated 函数中:

static void
example_window_init (ExampleWindow *self)
{
    gtk_widget_init_template (GTK_WIDGET (self));
    
    g_signal_connect (self->box_list, "row-activated", G_CALLBACK (on_row_activated), self);
}

这样我们就可以通过点击 GtkListBoxRow 来实现点击事件了。


简单总结一下:

  1. 将控件绑定到窗口类中
  2. 编写事件处理函数
  3. 将事件处理函数和信号连接在一起
GTK 学习笔记——事件和信号
https://blog.see2night.top/posts/gtk-学习笔记事件和信号/
作者
See-Night
发布于
2025-04-30
许可协议
CC BY-NC-SA 4.0