十一、Gtk4-Instance Initialization and destruction

文章详细介绍了TfeTextView的新版本,包括其封装改进,如何组织C源文件和头文件,以及GObject类和子类的结构。重点讨论了TfeTextView实例的初始化,如创建、设置GFile对象和管理引用计数。文章还阐述了对象的销毁过程,特别是dispose和finalize方法在解除对象间依赖和释放资源中的作用。

  文本文件编辑器(tfe)的新版本将在本节和以下四节中编写。它是tfe5。与之前的版本相比,有很多变化。它们位于两个目录中,src/tfe5和src/tfetextview。

1 封装

我们将C源文件分为两部分。但就封装而言,这还不够。

  • tfe.c包含除Tfe TextView之外的所有内容。它至少应该分为两部分,tfeapplication.c和tfenotebook.c。
  • 头文件也需要组织。

然而,首先,我想关注TfeTextView对象。它是GtkTextView的一个子对象,其中有一个新的成员文件。重要的是管理file指向的Gfile对象。

  • 当你创建(或初始化)TfeTextView,对于GFile什么是必须的?
  • 当你销毁TfeTextView,对于GFile什么是必须的?
  • TfeTextView是否应该自己读/写文件?
  • 它如何与其他的对象交流?

在考虑类、实例和信号之前,你至少需要知道它们。我将在本节和下一节中解释它们。之后我会解释:

  • 组织功能(Organizing functions)
  • 如何使用GtkFileChooserDialog

2 GObject and its children

GObject及其子对象都是对象,它们既有class C结构,也有object C结构。首先,考虑实例。一个实例是具有对象结构的内存。下面是TfeTextView的结构。

/* This typedef statement is automatically generated by the macro G_DECLARE_FINAL_TYPE */
typedef struct _TfeTextView TfeTextView;

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

该结构的成员如下:

  • 父类的类型是GtkTextView,这是C结构体。它在gtktextview.h中声明。GtkTextView是TfeTextView的父类。
  • file是一个GFile类型的指针。如果没有文件对应于TfeTextView实例,它可以是NULL。

您可以在GTK和GLib的源文件中找到父类对象结构的声明。下面的代码是从源文件中提取的(不完全相同)。

typedef struct _GObject GObject;
typedef struct _GObject GInitiallyUnowned;
struct  _GObject
{
   
   
  GTypeInstance  g_type_instance;
  volatile guint ref_count;
  GData         *qdata;
};

typedef struct _GtkWidget GtkWidget;
struct _GtkWidget
{
   
   
  GInitiallyUnowned parent_instance;
  GtkWidgetPrivate *priv;
};

typedef struct _GtkTextView GtkTextView;
struct _GtkTextView
{
   
   
  GtkWidget parent_instance;
  GtkTextViewPrivate *priv;
};

在每个结构中,其父元素声明在成员元素的顶部。所以,所有的父类都包含在子对象中。TfeTextView的结构如下图所示。
在这里插入图片描述
派生类(父类)都有它们自己的私有数据区,这些私有数据区不包含在上述结构中。例如,GtkWidget的私有数据为GtkWidgetPrivate (C结构体)。

注意声明(declarations)不是定义(definitions)。因此,在声明C结构体时不会分配内存。在调用tfe_text_view_new函数时,会从堆区域为它们分配内存。同时,对于TfeTetView父类的私有区域也会被分配。它们从TfeTextView隐藏,不能直接访问它们。创建的内存称为实例(instance)。创建TfeTextView实例时,会给它三个数据区域。

  • 实例(C结构体)。
  • GtkWidgetPrivate结构体。
  • GtkTextViewPrivate结构体。

TfeTextView函数只能访问其实例。GtkWidgetPrivate和GtkTextViewPrivate被父类的函数使用。请看下面的例子。

GtkWidget *tv = tfe_text_view_new ();
GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));

父函数gtk_text_view_get_buffer访问GtkTextViewPrivate数据(由tv拥有)。私有区域中有一个指向GtkBuffer的指针,该函数返回该指针。(实际的行为有点复杂。)

TfeTextView实例像这样继承了父类函数。

每次调用tfe_text_view_new函数时,都会创建一个TfeTextView实例。因此,可以存在多个TfeTextView实例。

3 初始化TfeTextView实例

函数tfe_text_view_new创建了一个新的TfeTextView实例。

1 GtkWidget *
2 tfe_text_view_new (void) {
   
   
3   return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, "wrap-mode", GTK_WRAP_WORD_CHAR, NULL));
4 }

调用这个函数时,会创建并初始化一个TfeTextView实例。初始化过程如下。

  • 当创建实例时,也创建了GtkWidgetPrivate和GtkTextViewPrivate结构体。
  • 在TfeTextView实例中初始化GObject (GInitiallyUnowned)部分。
  • 在TfeTextView实例和GtkWidgetPrivate结构中初始化GtkWidget部分(第一个priv)。
  • 初始化GtkTextView部分(第二个priv)在TfeTextView实例和GtkTextViewPrivate结构。
  • 在TfeTextView实例中初始化TfeTextView部分(文件)。

第二到第四步由g_object_init、gtk_widget_init和gtk_text_view_init完成。它们由系统自动调用,你不需要关心它们。第四步是由tfetextview.c中的函数tfe_text_view_init完成的。

1 static void
2 tfe_text_view_init (TfeTextView *tv) {
   
   
3   tv->file = NULL;
4 }

这个函数只是将tv->file初始化为NULL。

4 方法和类

在Gtk中,所有从GObject派生的对象都有类和实例(抽象对象除外)。实例是C结构体的内存,在前两个小节中描述过。每个对象可以有多个实例。这些实例具有相同的结构。实例只有数据。因此,它没有定义对象的行为。我们至少需要两样东西。一个是函数,另一个是类方法。

你已经见过很多函数了。例如,

  • TfeTextView *tfe_text_view_new (void);是一个创建TfeTextView实例的函数。
  • GtkTextBuffer *gtk_text_view_get_buffer (GtkTextView *textview)是一个从GtkTextView获取GtkTextBuffer的函数。

函数是公有的,这意味着它们可以被其他对象使用。它们类似于面向对象语言中的公共方法。

类(C结构体)主要由指向函数指针组成。这些函数被称为类方法,由对象本身或其后代对象使用。例如,GObject类在GLib源文件的GObject .h中声明。

 1 typedef struct _GObjectClass             GObjectClass;
 2 typedef struct _GObjectClass             GInitiallyUnownedClass;
 3 
 4 struct  _GObjectClass
 5 {
   
   
 6   GTypeClass   g_type_class;
 7 
 8   /*< private >*/
 9   GSList      *construct_properties;
10 
11   /*< public >*/
12   /* seldom overridden */
13   GObject
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值