七、Gtk4-Defining a final class

文章讲述了如何将一个简单的文件查看器转换为一个具有文本保存功能的编辑器,通过创建GtkTextView的子类TfeTextView来存储GFile指针,并介绍了如何处理窗口关闭前的保存操作。此外,还涉及到了GObject系统的使用和子类化的概念。

1 定义一个最终类

1.1 一个非常简单的编辑器

在上一节中,我们创建了一个非常简单的文件查看器。现在我们继续重写它,并将其转换为非常简单的编辑器。它的源文件是tfe目录下的tfe1.c(文本文件编辑器1)。

GtkTextView是一个多行编辑器。因此,我们不需要从头开始编写编辑器。我们只需要在文件查看器中添加两件事:

  • 指向GFile实例的指针。
  • 文本保存功能。

有两种方法可以存储指针。

  • 使用全局变量
  • 创建一个GtkTextView的子类,它的每个实例都保存一个指向GFile实例的指针。

使用全局变量很容易实现。定义一个指向GFile的指针数组。例如,

GFile * f [20];

变量f[i]对应于与第i个GtkNotebookPage关联的文件。

然而,有两个问题。第一个是数组的大小。如果用户提供了太多的参数(在上面的例子中超过20个),则不可能存储所有指向GFile实例的指针。二是程序维护困难。到目前为止,我们有一个小程序。但是,你开发的程序越多,它的规模就越大。一般来说,在大型程序中维护全局变量是非常困难的。在检查全局变量时,需要检查使用该变量的所有代码。

从维护的角度来看,创建子类是个好主意。我们更喜欢它而不是一个全局变量。

请注意,我们考虑的是“子类”,而不是“子构件”。子类和子部件完全不同。类是GObject系统的一个术语。如果你不熟悉GObject,请参阅:

  • GObject API reference
  • GObject tutorial for beginners

子类继承了父类的一切,而且还扩展了它的性能。我们将TfeTextView定义为GtkTextView的一个子类。它拥有GtkTextView拥有的一切,并添加了一个指向GFile的指针。

在这里插入图片描述

1.2 如何定义一个GtkTextView的子类

你需要了解GObject系统约定。首先,看看下面的程序。

#define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()
G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)

struct _TfeTextView
{
   
   
  GtkTextView parent;
  GFile *file;
};

G_DEFINE_TYPE (TfeTextView, tfe_text_view, GTK_TYPE_TEXT_VIEW);

static void
tfe_text_view_init (TfeTextView *tv) {
   
   
}

static void
tfe_text_view_class_init (TfeTextViewClass *class) {
   
   
}

void
tfe_text_view_set_file (TfeTextView *tv, GFile *f) {
   
   
  tv -> file = f;
}

GFile *
tfe_text_view_get_file (TfeTextView *tv) {
   
   
  return tv -> file;
}

GtkWidget *
tfe_text_view_new (void) {
   
   
  return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, NULL));
}
  • TfeTextView分为两部分。Tfe和TextView。Tfe称为前缀(prefix)或命名空间(namespace)。TextView被称为object。
    有三种不同的标识符模式。TfeTextView(驼峰式大小写),tfe_text_view(经常用于函数)和TFE_TEXT_VIEW(用于将对象转换为TfeTextView)。
  • 首先,定义TFE_TYPE_TEXT_VIEW宏为tfe_text_view_get_type()。名称总是(prefix)TYPE(object),并且字母都是大写。替换文本总是(prefix)_(object)_get_type(),字母都是小写。该定义放在G_DECLARE_FINAL_TYPE宏之前。
  • G_DECLARE_FINAL_TYPE宏的参数是驼峰式的子类名、小写带下划线、前缀(大写)、对象(大写带下划线)和父类名(驼峰式)。在该宏的扩展中声明了下列两个C语言结构。
    • typedef struct _TfeTextView TfeTextView
    • typedef struct {GtkTextViewClass parent_class;} TfeTextViewClass;
      这些声明告诉我们TfeTextView和TfeTextViewClass是C结构体。“TfeTextView”有两个含义,类名和C结构名。C语言结构体TfeTextView被称为object。类似地,TfeTextViewClass被称为class。
  • 声明结构体_TfeTextView。下划线是必要的。第一个成员是父对象(C结构)。注意,这不是一个指针,而是对象本身。第二个成员和后面的成员是子对象的成员。TfeTextView结构有一个指向GFile实例的指针作为成员。
  • G_DEFINE_TYPE宏。参数是子对象名称(驼峰大小写),带有下划线的小写和父对象类型(prefix)TYPE(module)。这个宏主要用于向类型系统注册新类。类型系统是GObject的基础系统。每个类都有自己的类型。GObject、GtkWidget和TfeTextView的类型分别是G_TYPE_OBJECT、GTK_TYPE_WIDGET和TFE_TYPE_TEXT_VIEW。这样的类型(例如,TFE_TYPE_TEXT_VIEW)是一个宏,它被扩展为一个函数(tfe_text_view_get_type())。它返回一个在所有GObject系统类中唯一的整数。
  • 实例init函数(tfe_text_view_init)在创建实例时被调用。它与其他面向对象语言中的构造函数相同。
    类init函数(tfe_text_view_class_init)在创建类时被调用。
  • 两个函数tfe_text_view_set_file和tfe_text_view_get_file是公共函数。公共函数是开放的,你可以在任何地方调用它们。它们与其他面向对象语言中的public方法相同。tv是一个指向TfeTextView对象(C结构)的指针。它有一个成员file,它是被tv->file指向。
  • TfeTextView实例创建函数是tfe_text_view_new。它的名字是(prefix)_(object)_new。它使用g_object_new函数创建实例。参数是(prefix)TYPE(object)、初始化属性的列表和NULL。NULL是属性列表的结束标记。这里没有初始化任何属性。返回值转换为GtkWidget。

这个程序展示了如何定义子类的大纲。

1.3 Close-request信号

假设您正在使用这个编辑器。首先,带着参数运行编辑器。参数是文件名。编辑器读取文件并显示一个包含文件文本的窗口。然后编辑文本。完成编辑后,退出编辑器。编辑器会在窗口关闭前更新文件。

GtkWindow在关闭之前发出"close-request"信号。我们将在before_close之前连接信号和处理程序。(处理程序是一个连接到信号的C函数。)before_close函数会在发出"close-request"信号时被调用。

g_signal_connect (win, "close-request"G_CALLBACK (before_close)NULL);

参数win是一个GtkApplicationWindow,其中定义了"close-request"信号,before_close是处理程序。G_CALLBACK转换对处理程序是必要的。before_close的程序如下所示。

 1 static gboolean
 2 before_close (GtkWindow *win, GtkWidget *nb) {
   
   
 3   GtkWidget *scr;
 4   GtkWidget *tv;
 5   GFile *file;
 6   char *pathname;
 7   GtkTextBuffer *tb;
 8   GtkTextIter start_iter;
 9   GtkTextIter end_iter;
10   char *contents;
11   unsigned int n;
12   unsigned int i;
13 
14   n = gtk_notebook_get_n_pages (GTK_NOTEBOOK (nb
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值