十二、Gtk4-信号

文章介绍了在Gtk程序中,如何使用GObject的信号机制进行对象间的通信。信号注册在类初始化时完成,通过`g_signal_new`函数创建,例如“change-file”和“open-response”。信号连接使用`g_signal_connect`,并在需要时通过`g_signal_emit`发射。信号提供了一种对象主动通知其他部分的方式,替代全局变量,增强程序的模块性和可维护性。
摘要由CSDN通过智能技术生成

1 信号

每个对象都封装在Gtk程序中。而且不推荐使用全局变量,因为它们容易使程序变得复杂。因此,我们需要一些东西来在对象之间通信。有两种方法可以做到这一点。

  • 函数。例如,tb = gtk_text_view_get_buffer (tv)。调用者请求tv提供tb,这是一个连接到tv的GtkTextBuffer实例。
  • 信号。例如,在GApplication对象上的activate信号。当应用程序被启动时,就会发出信号。这时,连接到该信号的处理程序会被调用。

函数的调用者或连接到信号的处理程序通常位于对象之外。这两者之间的区别之一是对象是主动的或被动的。在函数中,对象被动地响应调用者。对象主动向处理程序发送信号。

GObject信号被注册、连接和发射。

  1. 信号注册到发出信号的对象类型。注册通常在对象类初始化时完成。
  2. 信号通过g_connect_signal或其族函数连接到处理程序。连接通常是在对象之外完成的。
  3. 在发射信号时,调用连接的处理程序。信号在对象的实例上发出。

2 信号注册

在TfeTextView中,注册了两个信号。

  • “change-file”信号。当tv->file发生改变时,发出此信号。
  • “open-response”信号。tfe_text_view_open函数不能返回状态,因为它使用了GtkFileChooserDialog。发出这个信号而不是函数的返回值。

一个静态变量或数组用于存储信号ID。

enum {
  CHANGE_FILE,
  OPEN_RESPONSE,
  NUMBER_OF_SIGNALS
};

static guint tfe_text_view_signals[NUMBER_OF_SIGNALS];

信号注册在类初始化函数中。

 1 static void
 2 tfe_text_view_class_init (TfeTextViewClass *class) {
 3   GObjectClass *object_class = G_OBJECT_CLASS (class);
 4 
 5   object_class->dispose = tfe_text_view_dispose;
 6   tfe_text_view_signals[CHANGE_FILE] = g_signal_new ("change-file",
 7                                  G_TYPE_FROM_CLASS (class),
 8                                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
 9                                  0 /* class offset */,
10                                  NULL /* accumulator */,
11                                  NULL /* accumulator data */,
12                                  NULL /* C marshaller */,
13                                  G_TYPE_NONE /* return_type */,
14                                  0     /* n_params */
15                                  );
16   tfe_text_view_signals[OPEN_RESPONSE] = g_signal_new ("open-response",
17                                  G_TYPE_FROM_CLASS (class),
18                                  G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS,
19                                  0 /* class offset */,
20                                  NULL /* accumulator */,
21                                  NULL /* accumulator data */,
22                                  NULL /* C marshaller */,
23                                  G_TYPE_NONE /* return_type */,
24                                  1     /* n_params */,
25                                  G_TYPE_INT
26                                  );
27 }
  • 6-15:注册“change-file”信号。g_signal_new函数被使用。信号“change-file”没有默认处理程序(object method handler),因此偏移量(第9行)设置为零。通常不需要默认处理程序。如果需要,请使用g_signal_new_class_handler函数而不是g_signal_new。更多信息请参见GObject API参考。
  • g_signal_new的返回值是信号id。signal id的类型是guint,与unsigned int相同。它在函数g_signal_emit中使用。
  • 16-26:表示“open-response”信号。这个信号有一个参数。
  • 24:参数个数。“open-response”信号只有一个参数。
  • 25:参数类型。G_TYPE_INT是整数类型。这些基本类型在GObject参考手册中有描述。

处理程序声明如下。

/* "change-file" signal handler */
void
user_function (TfeTextView *tv,
               gpointer user_data)

/* "open-response" signal handler */
void
user_function (TfeTextView *tv,
               TfeTextViewOpenResponseType response-id,
               gpointer user_data)
  • 因为“change-file”信号没有参数,所以处理程序的参数是一个TfeTextView实例和用户数据。
  • 因为“open-response”信号只有一个参数,所以处理程序的参数是一个TfeTextView实例、信号的参数和用户数据。
  • tv是发射信号的对象实例。
  • user_data来自g_signal_connect的第四个参数。
  • parameter来自g_signal_emit的第四个参数。

参数的值在tfetextview.h中定义,因为它们是公有的。

/* "open-response" signal response */
enum
{
  TFE_OPEN_RESPONSE_SUCCESS,
  TFE_OPEN_RESPONSE_CANCEL,
  TFE_OPEN_RESPONSE_ERROR
};
  • 当tfe_text_view_open成功打开并读取文件时,该参数设置为TFE_OPEN_RESPONSE_SUCCESS。
  • 当用户取消时,该参数设置为TFE_OPEN_RESPONSE_CANCEL。
  • 当发生错误时,该参数设置为TFE_OPEN_RESPONSE_ERROR。

3 信号连接

信号和处理程序通过函数g_signal_connect连接起来。还有一些类似的函数,如g_signal_connect_after、g_signal_connect_等。但g_signal_connect是最常见的。信号“change-file”连接到TfeTextView对象外的回调函数。以同样的方式,信号“open-response”连接到TfeTextView对象外的回调函数。这些回调函数由用户定义。

在程序tfe中,回调函数定义在tfenotebook.c中。它们的名字是file_changed和open_response。稍后会解释。

g_signal_connect (GTK_TEXT_VIEW (tv), "change-file", G_CALLBACK (file_changed), nb);

g_signal_connect (TFE_TEXT_VIEW (tv), "open-response", G_CALLBACK (open_response), nb);

4 信号发射

信号是在实例上发出的。该实例的类型是g_signal_new的第二个参数。信号和对象类型之间的关系在信号注册时确定。

函数g_signal_emit用于发出信号。下面几行是从tfetextview.c中提取的。每一行都来自不同的一行。

g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_SUCCESS);
g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_CANCEL);
g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
  • 第一个参数是发出信号的实例。
  • 第二个参数是信号id。
  • 第三个参数是信号的细节。“change-file”信号和“open-response”信号没有细节,当没有细节时参数为0。
  • “change-file”信号没有参数,所以没有第四个参数。
  • “open-response”信号只有一个参数。第四个参数是传向回调函数的变量。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值