十三、Gtk4

编程入门 行业动态 更新时间:2024-10-27 22:31:58

十三、Gtk4

十三、Gtk4

TfeTextView相关函数在这一章节介绍

1 tfetextview.h

头文件tfetextview.h提供了:

  • TfeTextView的类型,是TFE_TYPE_TEXT_VIEW。
  • G_DECLARE_FINAL_TYPE的扩展包含了一些有用的宏。
  • 定义了open-response信号的常量。
  • tfetextview.c的公共函数被声明。

因此,任何使用TfeTextView的程序都需要包含TfeTextView .h。

 1 #ifndef __TFE_TEXT_VIEW_H__2 #define __TFE_TEXT_VIEW_H__3 4 #include <gtk/gtk.h>5 6 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()7 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)8 9 /* "open-response" signal response */
10 enum TfeTextViewOpenResponseType
11 {
12   TFE_OPEN_RESPONSE_SUCCESS,
13   TFE_OPEN_RESPONSE_CANCEL,
14   TFE_OPEN_RESPONSE_ERROR
15 };
16 
17 GFile *
18 tfe_text_view_get_file (TfeTextView *tv);
19 
20 void
21 tfe_text_view_open (TfeTextView *tv, GtkWindow *win);
22 
23 void
24 tfe_text_view_save (TfeTextView *tv);
25 
26 void
27 tfe_text_view_saveas (TfeTextView *tv);
28 
29 GtkWidget *
30 tfe_text_view_new_with_file (GFile *file);
31 
32 GtkWidget *
33 tfe_text_view_new (void);
34 
35 #endif /* __TFE_TEXT_VIEW_H__ */
 1 #ifndef __TFE_TEXT_VIEW_H__2 #define __TFE_TEXT_VIEW_H__3 4 #include <gtk/gtk.h>5 6 #define TFE_TYPE_TEXT_VIEW tfe_text_view_get_type ()7 G_DECLARE_FINAL_TYPE (TfeTextView, tfe_text_view, TFE, TEXT_VIEW, GtkTextView)8 9 /* "open-response" signal response */
10 enum TfeTextViewOpenResponseType
11 {
12   TFE_OPEN_RESPONSE_SUCCESS,
13   TFE_OPEN_RESPONSE_CANCEL,
14   TFE_OPEN_RESPONSE_ERROR
15 };
16 
17 GFile *
18 tfe_text_view_get_file (TfeTextView *tv);
19 
20 void
21 tfe_text_view_open (TfeTextView *tv, GtkWindow *win);
22 
23 void
24 tfe_text_view_save (TfeTextView *tv);
25 
26 void
27 tfe_text_view_saveas (TfeTextView *tv);
28 
29 GtkWidget *
30 tfe_text_view_new_with_file (GFile *file);
31 
32 GtkWidget *
33 tfe_text_view_new (void);
34 
35 #endif /* __TFE_TEXT_VIEW_H__ */
  • 1、2、35:由于这三行代码,下面几行代码只包含一次。你可以使用#pragma once来代替它们。它是非标准的,但被广泛使用。
  • 4:包含gtk4头文件。头文件gtk4也有相同的机制来避免多次包含它。
  • 6-7:这两行定义了TfeTextView类型、它的类结构和一些有用的宏。
    • TfeTextView和TfeTextViewClass被声明为C结构的typedef。
  • 稍后你需要定义一个结构体_TfeTextView。
  • 类结构_TfeTextViewClass在这里定义。你不需要自己定义它。
  • 定义了方便转换的函数TFE_TEXT_VIEW()和用于类型检查的函数TFE_IS_TEXT_VIEW。
  • 9-15:“open-response”信号参数值的定义。
  • 17-33:在TfeTextView上声明公有函数。

2 Instance creation Functions

tfe_text_view_new或tfe_text_view_new_with_file创建了一个TfeTextView实例。

GtkWidget *tfe_text_view_new (void);

tfe_text_view_new只是创建一个新的TfeTextView实例并返回指向新实例的指针。

GtkWidget *tfe_text_view_new_with_file (GFile *file);

tfe_text_view_new_with_file是一个Gfile对象作为参数,它将文件加载到GtkTextBuffer实例中,然后返回指向新实例的指针。如果在创建过程中发生错误,则返回NULL。

每个函数定义如下。

 1 GtkWidget *2 tfe_text_view_new_with_file (GFile *file) {3   g_return_val_if_fail (G_IS_FILE (file), NULL);4 5   GtkWidget *tv;6   GtkTextBuffer *tb;7   char *contents;8   gsize length;9 
10   if (! g_file_load_contents (file, NULL, &contents, &length, NULL, NULL)) /* read error */
11     return NULL;
12 
13   if ((tv = tfe_text_view_new()) != NULL) {
14     tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
15     gtk_text_buffer_set_text (tb, contents, length);
16     TFE_TEXT_VIEW (tv)->file = g_file_dup (file);
17     gtk_text_buffer_set_modified (tb, FALSE);
18   }
19   g_free (contents);
20   return tv;
21 }
22 
23 GtkWidget *
24 tfe_text_view_new (void) {
25   return GTK_WIDGET (g_object_new (TFE_TYPE_TEXT_VIEW, "wrap-mode", GTK_WRAP_WORD_CHAR, NULL));
26 }
  • 23-25: tfe_text_view_new函数。只返回函数g_object_new的值,但将其强制转换为指向GtkWidget的指针。函数g_object_new创建其子类的任何实例。参数是类的类型、属性列表和NULL。Null是属性列表的结束标记。TfeTextView的“wrap-mode”属性的默认值为GTK_WRAP_WORD_CHAR。
  • 1-21: tfe_text_view_new_with_file函数。
  • 3: g_return_val_if_fail在GLib API Reference——g_return_val_if_fail中描述。还有GLib API Reference – Message Logging。它测试参数file是否为指向GFile的指针。如果结果为true,程序继续执行下一行代码。如果为false,则立即返回NULL(第二个参数)。与此同时,它会打印出错误信息(通常日志输出到stderr或stdout)。这个函数用于检查程序的错误。如果发生错误,解决方案通常是更改(调用者)程序并修复错误。你需要区分程序错误和运行时错误。你不应该使用这个函数来查找运行时错误。
  • 10-11:如果读取文件时发生错误,则函数返回NULL。
  • 13:调用函数tfe_text_view_new。该函数创建TfeTextView实例并返回指向该实例的指针。如果在tfe_text_view_new中发生错误,则返回NULL。
  • 14:获取tv对应的GtkTextBuffer的指针。该指针赋值给tb
  • 15:将从文件读取的内容赋值给以tb为指针的GtkTextBuffer。
  • 16:复制文件(最后需要释放)并设置tv->file指向它。
  • 17:函数gtk_text_buffer_set_modified (tb, FALSE)设置tb的修改标志为FALSE。modification标志表示缓冲区的内容已经修改。它在保存内容时使用。如果修改标志为FALSE(内容修改完成),则不需要保存contens。
  • 19:释放contents指向的内存。
  • 20:返回tv,它是一个指针,指向新创建的TfeTextView实例。如果发生错误,则返回NULL。

3 Save related functions

Save和saveas函数将GtkTextBuffer中的内容写入文件。

void tfe_text_view_save (TfeTextView *tv)

函数tfe_text_view_save将GtkTextBuffer中的内容,写入到tv->file指定的文件中。如果tv->file为NULL,那么它将显示GtkFileChooserDialog并提示用户选择要保存的文件。然后它将内容保存到文件中,并设置tv->file为该文件指向GFile实例。

void tfe_text_view_saveas (TfeTextView *tv)

该函数使用GtkFileChooserDialog并提示用户选择一个已存在的文件或指定一个新文件来保存。然后,该函数修改tv->file,并将内容保存到指定文件中。如果发生错误,将通过消息对话框显示给用户。该错误仅在TfeTextView中进行管理,没有任何信息被通知给调用方。

4 save_file function

 1 static gboolean2 save_file (GFile *file, GtkTextBuffer *tb, GtkWindow *win) {3   GtkTextIter start_iter;4   GtkTextIter end_iter;5   char *contents;6   gboolean stat;7   GtkWidget *message_dialog;8   GError *err = NULL;9 
10   gtk_text_buffer_get_bounds (tb, &start_iter, &end_iter);
11   contents = gtk_text_buffer_get_text (tb, &start_iter, &end_iter, FALSE);
12   stat = g_file_replace_contents (file, contents, strlen (contents), NULL, TRUE, G_FILE_CREATE_NONE, NULL, NULL, &err);
13   if (stat)
14     gtk_text_buffer_set_modified (tb, FALSE);
15   else {
16     // Because error message is displayed here, the caller of 'save_file' doesn't need to do anything about error.
17     message_dialog = gtk_message_dialog_new (win, GTK_DIALOG_MODAL,
18                         GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s.", err->message);
19     g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
20     gtk_widget_show (message_dialog);
21     g_error_free (err);
22   }
23   g_free (contents);
24   return stat;
25 }
  • 函数save_file是由saveas_dialog_response和tfe_text_view_save调用的。该函数将缓冲区的内容保存到作为参数给出的文件中。如果发生错误,就显示错误消息。因此,这个函数的调用者不需要处理错误。这个函数的类是static。因此,只有这个文件(tfetextview.c)中的函数调用这个函数。这样的static函数通常没有g_return_val_if_fail函数。(出现错误内部进行处理,和调用者无关)
  • 10-11:从缓冲区中获取文本内容。
  • 12:函数g_file_replace_contents将内容写入文件并返回状态(true =成功/ false =失败)。它有很多参数,但其中一些几乎总是被赋予相同的值。
    • GFile* file:保存内容的GFile。
    • const char* contents:要保存的内容。该字符串属于调用者。
    • gsize length:内容的长度
    • const char* etag:实体标记。它通常为NULL。
    • gboolean make_backup:如果文件存在,则为true进行备份。 - false不备份。文件将被覆盖。
    • GFileCreateFlags标志:通常G_FILE_CREATE_NONE即可。
    • char ** new_etag:新实体标签。它通常为NULL。
    • GCancellable* cancellable:如果可删除实例被设定,其他线程可以取消此操作。它通常为NULL。
    • GError **错误:如果发生错误,将设置error。
  • 13,14:如果没有错误发生,将修改后的标志设置为FALSE。这意味着缓冲区没有被修改,因为它已经保存了。
  • 15-22:保存失败,提示错误。
  • 17-18:创建消息对话框。参数有:
    • GtkWindow* parent:父窗口(调用消息对话框的窗口)。这允许窗口管理器将对话框保持在父窗口的顶部,或者使对话框居中。可以不给对话框任何父窗口。但是,鼓励家长进行对话。
    • GtkDialogFlags标志位:GTK_DIALOG_MODAL用于模态对话框。模态对话框通常就可以了。
    • GtkMessageType类型:GTK_MESSAGE_ERROR表示错误消息。其他选项有GTK_MESSAGE_INFO、GTK_MESSAGE_WARNING等。
    • GtkButtonsType按钮:GTK_BUTTON_OK是最常用的按钮。其他选项是GTK_BUTTON_YES_NO、GTK_BUTTON_CANCEL等。
    • Const gchar* message_format: gchar等同于char。这种格式与printf相同。消息格式的参数如下。
  • 19:连接“response”信号到gtk_window_destroy,这样当用户点击按钮时对话框就消失了。
  • 20:显示消息对话框。
  • 21:用g_error_free函数释放err。
  • 23:释放contents指向的内存。
  • 24:返回给调用者。

5 saveas_dialog_response function

 1 static void2 saveas_dialog_response (GtkWidget *dialog, gint response, TfeTextView *tv) {3   GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));4   GFile *file;5   GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);6 7   if (response == GTK_RESPONSE_ACCEPT) {8     file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));9     if (! G_IS_FILE (file))
10       g_warning ("TfeTextView: gtk_file_chooser_get_file returns non GFile.\n");
11     else if (save_file(file, tb, GTK_WINDOW (win))) {
12       // The following is complicated. The comments here will help your understanding
13       // G_IS_FILE(tv->file) && tv->file == file  => nothing to do
14       // G_IS_FILE(tv->file) && tv->file != file  => unref(tv->file), tv->file=file, signal emit
15       // tv->file==NULL                           =>                  tv->file=file, signal emit
16       if (G_IS_FILE (tv->file) && (! g_file_equal (tv->file, file)))
17         g_object_unref (tv->file);
18       if (! (G_IS_FILE (tv->file) && g_file_equal (tv->file, file))) {
19         tv->file = file; // The ownership of 'file' moves to TfeTextView.
20         g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
21       }
22       g_object_unref (file);
23     } else
24       g_object_unref (file);
25   }
26   gtk_window_destroy (GTK_WINDOW (dialog));
27 }
  • 函数saveas_dialog_response是GtkFileChooserDialog上“response”信号的信号处理程序。此处理程序分析响应并确定是否保存内容。
  • 7-25:如果响应是GTK_RESPONSE_ACCEPT,则用户单击了Save按钮,内容将被保存。
  • 8:从GtkFileChooserDialog中获取GFile文件。
  • 9-10:如果它没有指向GFile,一条警告消息将输出到日志中。这是意料之外的。
  • 11:否则,调用save_file将内容保存到文件中。
  • 12-22:如果save_file成功保存了内容,则执行以下操作。
    • 如果tv->file是GFile,而file是另一个文件,则unref tv->file。
    • 如果tv->file是GFile,而file指向和tv->file相同,则不需要做任何操作。否则,tv->file = file,并发出“change-file”信号。
  • 22、24:unref file。
  • 26:销毁文件选择器对话框。

6 tfe_text_view_save function

 1 void2 tfe_text_view_save (TfeTextView *tv) {3   g_return_if_fail (TFE_IS_TEXT_VIEW (tv));4 5   GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));6   GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);7 8   if (! gtk_text_buffer_get_modified (tb))9     return; /* no need to save it */
10   else if (tv->file == NULL)
11     tfe_text_view_saveas (tv);
12   else if (! G_IS_FILE (tv->file)) // Unexpected error
13     g_error ("TfeTextView: The pointer tv->file isn't NULL nor GFile.\n");
14   else
15     save_file (tv->file, tb, GTK_WINDOW (win));
16 }
  • 函数tfe_text_view_save将内容写入tv->file指向的文件。它调用tfe_text_view_saveas或save_file。
  • 1-3:函数是公有的,即它对其他对象是开放的。所以,它没有static类型。公有函数应该用g_return_if_fail函数检查参数类型。如果tv不是一个指向TfeTextView实例的指针,那么它记录一个错误消息并立即返回。这个函数类似于g_return_val_if_fail,但是没有返回值,因为tfe_text_view_save没有返回值(void)。
  • 5-6:设置GtkTextBuffer tb和GtkWidget (GtkWindow) win。函数gtk_widget_get_ancestor (widget, type)返回具有类型的widget的第一个父类 。类型是GType。例如,GtkWindow的类型是GTK_TYPE_WINDOW, TfeTextView的类型是TFE_TYPE_TEXT_VIEW。小心些而已。这里的父子关系是构件的父子关系,而不是类的父子关系。顶层窗口可能是GtkApplicationWindow,但它取决于应用程序。因为TfeTextView是一个库,它不能确定顶层窗口类型(GtkWindow或GtkApplicationWindow)。GtkWindow是GtkApplication窗口的父类,因此它更通用。因此,TfeTextView将GtkWindow作为顶层窗口,以便它可以被任何应用程序使用。
  • 8-9:如果缓冲区没有修改,则不需要保存它。
  • 10-11:如果tv->file为NULL,这意味着还没有给出文件,它调用tfe_text_view_saveas提示用户选择一个文件并保存内容。
  • 12-13:如果tv->file没有指向GFile,错误信息会被登出。这是意料之外的。
  • 14 ~ 15:否则调用save_file将内容保存到tv->file中。

7 tfe_text_view_saveas function

 1 void2 tfe_text_view_saveas (TfeTextView *tv) {3   g_return_if_fail (TFE_IS_TEXT_VIEW (tv));4 5   GtkWidget *dialog;6   GtkWidget *win = gtk_widget_get_ancestor (GTK_WIDGET (tv), GTK_TYPE_WINDOW);7 8   dialog = gtk_file_chooser_dialog_new ("Save file", GTK_WINDOW (win), GTK_FILE_CHOOSER_ACTION_SAVE,9                                       "Cancel", GTK_RESPONSE_CANCEL,
10                                       "Save", GTK_RESPONSE_ACCEPT,
11                                       NULL);
12   g_signal_connect (dialog, "response", G_CALLBACK (saveas_dialog_response), tv);
13   gtk_widget_show (dialog);
14 }
  • 函数tfe_text_view_saveas显示GtkFileChooserDialog并提示用户选择一个文件并保存内容。
  • 1-3:检查tv类型,因为调用者可能是其他对象。这个函数是公有的。
  • 6: GtkWidget win被设置为顶级窗口。
  • 8-11:创建GtkFileChooserDialog。它至少有4个参数。
    • const char* title:显示在栏中的对话框的标题。
    • GtkWindow* parent: 父窗口。
    • GtkFileChooserAction action: action是GTK_FILE_CHOOSER_ACTION_OPEN、GTK_FILE_CHOOSER_ACTION_SAVE和GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER中的一个。要保存文件时,可以使用GTK_FILE_CHOOSER_ACTION_SAVE操作。
    • const char* first_button_text:第一个按钮的标签文本。
    • type: 按钮的响应ID。响应ID是GtkReponseType的一种。
    • 接下来是成对的按钮文本和响应ID…
    • NULL放在列表的末尾。
  • GtkFileChooserDialog将有标题“保存文件”,瞬态父赢,保存模式动作,取消和保存按钮。
  • 12:连接response信号和saveas_dialog_response处理程序。
  • 13:显示对话框。

使用GtkFileChooserDialog时,需要将程序分成两部分。一个是创建GtkFileChooserDialog的函数,另一个是信号处理程序。该函数创建并显示了GtkFileChooserDialog。其余的工作由处理程序完成。它从GtkFileChooserDialog获取Gfile,并通过调用save_file将缓冲区保存到文件中。

8 Open related functions

打开函数向用户显示GtkFileChooserDialog并提示他们选择一个文件。然后它读取文件并将文本放入GtkTextBuffer中。

void tfe_text_view_open (TfeTextView *tv, GtkWindow *win);

参数win是顶层窗口。当创建对话框时,它将是GtkFileChooserDialog的一个临时父窗口。

这个函数可以在tv创建之后调用。在这种情况下,tv还没有被合并到widget层次结构中。因此,不可能从tv中获得顶层窗口。这就是为什么这个函数需要win参数。

该函数通常在tv的缓冲区为空时调用。然而,即使缓冲区不为空,tfe_text_view_open也不会将其视为错误。如果你想还原缓冲区,调用这个函数是合适的。

打开和读取过程分为两个阶段。一个是显示GtkFileChooserDialog,另一个是其响应处理程序。响应处理程序获取文件名,读取文件内容并将其放入GtkTextBuffer中。

9 open_dialog_response function

 1 static void2 open_dialog_response(GtkWidget *dialog, gint response, TfeTextView *tv) {3   GtkTextBuffer *tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));4   GFile *file;5   char *contents;6   gsize length;7   GtkWidget *message_dialog;8   GError *err = NULL;9 
10   if (response != GTK_RESPONSE_ACCEPT)
11     g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_CANCEL);
12   else if (! G_IS_FILE (file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)))) {
13     g_warning ("TfeTextView: gtk_file_chooser_get_file returns non GFile.\n");
14     g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
15   } else if (! g_file_load_contents (file, NULL, &contents, &length, NULL, &err)) { /* read error */
16     g_object_unref (file);
17     message_dialog = gtk_message_dialog_new (GTK_WINDOW (dialog), GTK_DIALOG_MODAL,
18                         GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", err->message);
19     g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL);
20     gtk_widget_show (message_dialog);
21     g_error_free (err);
22     g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_ERROR);
23   } else {
24     gtk_text_buffer_set_text (tb, contents, length);
25     g_free (contents);
26     gtk_text_buffer_set_modified (tb, FALSE);
27     // G_IS_FILE(tv->file) && tv->file == file => unref(tv->file), tv->file=file, emit response with SUCCESS
28     // G_IS_FILE(tv->file) && tv->file != file => unref(tv->file), tv->file=file, emit response with SUCCESS, emit change-file
29     // tv->file==NULL =>                                           tv->file=file, emit response with SUCCESS, emit change-file
30     // The order is important. If you unref tv->file first, you can't compare tv->file and file anymore.
31     // And open-response signal is emitted after new tv->file is set. Or the handler can't catch the new file.
32     if (! (G_IS_FILE (tv->file) && g_file_equal (tv->file, file)))
33       g_signal_emit (tv, tfe_text_view_signals[CHANGE_FILE], 0);
34     if (G_IS_FILE (tv->file))
35       g_object_unref (tv->file);
36     tv->file = file; // The ownership of 'file' moves to TfeTextView
37     g_signal_emit (tv, tfe_text_view_signals[OPEN_RESPONSE], 0, TFE_OPEN_RESPONSE_SUCCESS);
38   }
39   gtk_window_destroy (GTK_WINDOW (dialog));
40 }
  • 2:处理程序open_dialog_response有三个参数。
    • GtkWidget *dialog: FileChooserDialog,在其上发出“response”信号。
    • gint response:响应ID
    • TfeTextView *tv: textview放入内容
  • 10-11:如果响应不是GTK_RESPONSE_ACCEPT,则用户单击了标题栏上的“取消”按钮或关闭按钮。然后,发射“open-response”信号。信号的参数是TFE_OPEN_RESPONSE_CANCEL。
  • 12-14:通过gtk_file_chooser_get_file获取指向GFile的指针。如果它没有指向GFile,可能发生了错误。不过,这并不在预料之中。然后它发送带有参数TFE_OPEN_RESPONSE_ERROR的“open-response”信号。
  • 15-22:如果读取文件时发生错误,那么它会减少GFile的引用计数,显示一个消息对话框向用户报告错误,并发出带有参数TFE_OPEN_RESPONSE_ERROR的“open-response”信号。
  • 23-38:如果文件读取成功,执行如下操作。(这并不简单。)
    • 文本被插入到GtkTextBuffer中
    • 释放临时缓冲区的内容
    • modify-bit设置为FALSE
    • open-response信号通过TFE_OPEN_REPONSE_SUCCESS发出
    • 如果文件发生了变化,就会发出change-file信号
    • 如果tv->file不是NULL, g_object_unref(tv->le)将被调用
      Tv ->文件被指定为file
  • 39:销毁GtkFileChooserDialog。

10 tfe_text_view_open function

 1 void2 tfe_text_view_open (TfeTextView *tv, GtkWindow *win) {3   g_return_if_fail (TFE_IS_TEXT_VIEW (tv));4   // 'win' is used for a transient window of the GtkFileChooserDialog.5   // It can be NULL.6   g_return_if_fail (GTK_IS_WINDOW (win) || win == NULL);7 8   GtkWidget *dialog;9 
10   dialog = gtk_file_chooser_dialog_new ("Open file", win, GTK_FILE_CHOOSER_ACTION_OPEN,
11             "Cancel", GTK_RESPONSE_CANCEL, "Open", GTK_RESPONSE_ACCEPT, NULL);
12   g_signal_connect (dialog, "response", G_CALLBACK (open_dialog_response), tv);
13   gtk_widget_show (dialog);
14 }
  • 3-4:检查变量 tv 和 win的类型。公共函数总是需要检查参数。
    10-11:创建GtkFileChooserDialog。
    • 标题是“Open file”。
    • 瞬态父窗口是顶层窗口win。
    • 操作为打开模式。
    • 按钮是“取消”和“打开”。
  • 12:连接response信号和handler处理程序。
  • 13:显示对话框。

调用者和TfeTextView之间的整个过程如下图所示。这真的很复杂。因为signal是GtkFileChooserDialog与他人通信的唯一方式。

  1. 调用者通过调用tfe_text_view_new获得指向TfeTextView实例的tv指针。
  2. 调用者连接处理程序(图中左下角)和信号“open-response”。
  3. 它调用tfe_text_view_open来提示用户从GtkFileChooserDialog中选择一个文件。
  4. 对话框发出一个信号,并调用处理程序open_dialog_response。
  5. 处理程序读取文件并将文本插入到GtkTextBuffer中,并发出信号作为响应代码通知状态。
  6. TfeTextView外的处理程序接收到信号。

11 Getting GFile in TfeTextView

你可以使用tfe_text_view_get_file在TfeTextView实例中获取GFile。这很简单。

1 GFile *
2 tfe_text_view_get_file (TfeTextView *tv) {
3   g_return_val_if_fail (TFE_IS_TEXT_VIEW (tv), NULL);
4 
5   if (G_IS_FILE (tv->file))
6     return g_file_dup (tv->file);
7   else
8     return NULL;
9 }

重要的是复制tv->file。否则,如果调用者释放GFile对象,则tv->file 不再保证指向GFile。使用g_file_dup的另一个原因是,GFile不是线程安全的。如果在不同的线程中使用GFile,则必须进行复制。参见Gio API参考——g_file_dup。

12 The API document and source file of tfetextview.c

参考TfeTextView的API文档。它位于src/tfetextview目录下。

你可以在src/ TfeTextView目录下找到所有的TfeTextView源代码。

更多推荐

十三、Gtk4

本文发布于:2024-03-08 01:20:57,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1719471.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!