十三、Gtk4-TfeTextView函数

十、Gtk4-Build system 到目前为止,我们已经编译了一个小型编辑器。但一些不好的迹象已经开始出现。这些思想对于管理大型源文件很有用。 阅读详情

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 gboolean
 2 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 void
 2 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 void
 2 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 void
 2 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 void
 2 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 void
 2 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-UI设计工具Cambalache和Drafting Ubuntu 22.04 adm64 (作者在Ubuntu20.04 arm64系统安装过,但是按照Gobject-intro包,会造成啊appindictor错误,无法开机进入桌面,由于知识水平和时间有限,没有寻找原因)文中前一部分重复了第一节Gtk4编译过程(因为Cambalache需要broadway-backend=true) 阅读详情

相关推荐

二、Gtk4-GtkApplication and GtkApplicationWindow

人们编写编程代码来开发应用程序。什么是应用程序?应用程序是使用库运行的软件,其中包括操作系统、框架等。在GTK 4编程中,GTK应用程序是使用GTK库运行的程序(或可执行程序)。编写GtkApplication的基本方法如下。这是所有。非常简单。下面是代表上述方法的C代码。第一行说明这个程序包含Gtk库的头文件。函数main是C语言中的一个启动函数。变量app被定义为一个指向GtkApplication实例的指针。

Creationyang的博客 1777

GObject继承类使用到的几个宏定义的展开内容

GObject 继承类的宏定义展开的内容。

Kalong Room 556

gtk4学习

前几天学习GDB,下载了张老师写的一个GTK图形程序,在我ubuntu机器上运行不了,界面直接死掉了。所以今天准备简单学习一下gtk。

hb_zxl的专栏 1611

1. gobject 类型系统和注册过程

下面是用宏来自动注册,宏自动注册需要遵循命名约定。

随手写下笔记和感悟 880

GTK常用接口——信息对话框、文本选择对话框

信息对话框GtkMessageDialog //创建信息对话框 GtkWidget*  gtk_message_dialog_new           (GtkWindow *parent, GtkDialogFlags flags, GtkMessageType type, GtkButtonsType buttons, gchar *message_format, ...);   pa

zegeyzz的专栏 3176

Gtk4-tutorial:gtk4初学者教程

Gtk4初学者教程 本教程说明了如何使用Gtk4库编写C程序。 它侧重于初学者,因此其内容仅限于基本事物,例如小部件,GObject,信号,菜单和构建系统。 请参考以获取更多主题。 本教程正在开发中,不稳定。 即使使用C语言编写的示例已在gtk4版本4.0上进行了测试,但可能仍存在错误。 如果您在本教程和C示例中发现任何错误,错误或错误,请告诉我。 您可以将其发布到 。 本教程的最新版本位于。 您可以阅读而无需下载。

十一、Gtk4-Instance Initialization and destruction

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

Creationyang的博客 854

S32K3基于EB配置GPT触发WDG的实战解析

本文详细解析了S32K3 MCU基于EB tresos工具配置GPT定时器触发看门狗(WDG)的实战方法。通过分析协同工作机制、MCAL配置步骤及代码实现,帮助开发者构建可靠的硬件监控系统,提升汽车电子系统的安全性与实时性。

f9g0h的博客 202

七、Gtk4-Defining a final class

在上一节中,我们创建了一个非常简单的文件查看器。现在我们继续重写它,并将其转换为非常简单的编辑器。它的源文件是tfe目录下的tfe1.c(文本文件编辑器1)。GtkTextView是一个多行编辑器。因此,我们不需要从头开始编写编辑器。我们只需要在文件查看器中添加两件事:有两种方法可以存储指针。使用全局变量很容易实现。定义一个指向GFile的指针数组。例如, 变量f[i]对应于与第i个GtkNotebookPage关联的文件。然而,有两个问题。第一个是数组的大小。如果用户提供了太多的参数(在上面的例子中超过2

Creationyang的博客 1006

手把手教你用LIO-SAM搞定激光雷达和IMU联合标定(附避坑指南)

本文详细介绍了使用LIO-SAM进行激光雷达与IMU联合标定的全流程,包括标定原理、工具选型、硬件配置、数据采集、LI_calib标定步骤及LIO-SAM集成验证。特别提供了避坑指南和参数优化技巧,帮助开发者高效完成传感器标定,提升自动驾驶和机器人定位精度。

hadoop5ranger的博客 994

基于PLC智能立体车库控制系统设计

摘要 本系统设计以三层立体车库为研究对象,通过对立体车库的原理分析、动作流程设计和一系列的软硬件设计,达到立体车库自动化控制的目的。系统采用可编程控制器作为立体车库控制系统的控制单元,实现该系统的工艺要求,通过程序仿真调试,完成系统的各种动作要求,达到自动控制的目的。系统设计分为总体设计、硬件设计以及软件设计。按照立体车库控制系统的控制策略进行图纸设计;重点分析工艺流程图,对立体车库控制系统进行程序编译和MCGS上位机调试,通过系统的调试和修改,达到了基本控制的要求。系统设计明确了工艺要求,确定

DX884164131的博客 3599

二十五、Gtk4-多线程分析

首先回顾一下GLib,GObject,GIO,Gtk的不同,因为下面会涉及到这些概念里面的函数。所有这些都是由Gnome项目开发的库,一般都用于Gnome环境相关的应用程序。

Creationyang的博客 1529

从高德、百度地图下载POI数据?用这个工具5分钟搞定GCJ02/BD09到WGS84的坐标纠偏

本文详细解析了高德、百度地图POI数据坐标偏移问题,并提供了从GCJ02/BD09到WGS84的高效转换方案。通过开源工具如coordtransform和ArcGIS等专业软件,实现毫米级精度的坐标纠偏,适用于商业选址、GIS分析等场景,显著提升数据准确性和工作效率。

weixin_26789847的博客 448

二十二、Gtk4-ListView

GTK 4添加了新的列表对象GtkListView、GtkGridView和GtkColumnView。这个新特性在Gtk API参考—列表小构件概述中有描述。GTK 4还有其他实现列表的方法。它们是GtkListBox和GtkTreeView,它们是从GTK 3接管的。在Gtk开发博客中有一篇关于Matthias Clasen所写的列表小构件的文章。他描述了为什么开发GtkListView来取代GtkListBox和GtkTreeView。

Creationyang的博客 1987

CentOS 7下Oracle 11G RAC静默安装避坑指南:从网络规划到共享存储配置全流程

本文详细介绍了在CentOS 7环境下进行Oracle 11G RAC静默安装的全流程,包括网络规划、共享存储配置和系统参数调优等关键步骤。特别针对静默安装过程中的常见问题提供了实用的避坑指南和优化建议,帮助技术人员高效完成企业级数据库部署。

weixin_29234509的博客 123

Android Profiler实战:如何用CPU分析工具揪出卡顿元凶(附线程状态解读)

本文深入解析Android Profiler中的CPU分析工具,重点聚焦线程活动监控。通过解读线程状态时间轴上的绿、黄、灰三色含义,并结合实战案例,指导开发者精准定位导致界面卡顿的CPU密集型或I/O阻塞代码,有效提升应用性能与用户体验。

weixin_29197699的博客 372

gtk4 使用c语言开发界面之自定义组件

gtk4自定义组件

lopoi的博客 1143

YOLOv11改进 | 引入DEConv细节增强卷积模块:恢复细节信息,提升小目标检测精度

摘要: YOLOv11在目标检测中面临小目标检测精度不足的问题,主要由于细节信息丢失。本文提出引入DEConv(细节增强卷积)模块,通过多分支卷积和残差连接恢复高频细节,提升小目标检测性能。DEConv结合3×3卷积与空洞卷积增强边缘信息,并自适应融合特征,兼容YOLOv11的P3层(小目标关键层)且计算高效。实验表明,该改进在无人机航拍、显微镜图像等密集小目标场景中显著减少漏检,同时保持轻量化和实时性优势。代码实现可直接嵌入现有YOLO架构,仅需替换P3层卷积模块。

走向CTO的路上... 948

学习 gtk4

学个屁,gtk4 的改动有很多问题。很不稳定。 反正 windows 上最好不要。 还是老老实实的使用 gtk3 吧。 来看看bug 不想去研究这个程序的代码看哪里出现了未释放的资源。重复切换 page/1/2/3,你就能看到 内存的飙升。哈哈。 接下来才是恶心人的bug 左3右4 控件丢失背景色啊。可以用 css 解决。但也侧面反映的了 4 的不完善。 https://gitlab.gnome.org/GNOME/gtk/-/issues/4645 渲染器错误,使用 cairo 则会显示正常 鼠标、

(〃'▽'〃) 3641

破盾实录|Vueling航空阿卡迈防护逆向:从503挑战到Cookie生成的全流程拆解

摘要:文章分享了作者在爬取西班牙伏林航空(Vueling)机票数据时,遭遇阿卡迈(Akamai)防护系统的实战经历。起初简单的请求被拦截返回503错误,分析发现阿卡迈通过混淆JS代码实施"挑战-验证"机制,需模拟真实浏览器环境才能获取有效Cookie。作者详细拆解了逆向过程:从抓包分析JS挑战流程,到破解代码混淆和控制流平坦化,最终用Python+Pyppeteer成功模拟浏览器特征,突破防护获取数据。整个过程涉及JS反混淆、环境检测绕过和Cookie生成验证等关键技术点,为类似防护系统

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1641

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Gobject tutorial 三

在GLib中,类型可以分为两种。一种是可以被继承的(derivable),一种是不能被继承的(final)。二者的主要区别是,final 类型对象的类结构中,除了其父类外,再无其他成员。而derivable类型对象的类结构中会存在其他成员, 且derivable类型的类对其衍生类是可见的。对于上篇我们的例子TDouble,就是一个final类。我们在注册时使用的是G_DEFINE_TYPE,实际上还可以使用。

编程是一门艺术 2029

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

sec3-类型系统和注册流程

当我们说“类型”时,它可以是类型系统中的类型或C语言类型。例如,GObject是类型系统中的类型名称。char, int或double是C语言类型。当“类型”这个词在上下文中的意思很清楚时,我们就叫它“类型”。但如果它是模棱两可的,我们称之为“C类型”或“类型系统中的类型”。TDouble对象具有类和实例。类的C类型是TDoubleClass。}TDoubleClass是一个C结构标签名,TDoubleClass是“struct TDoubleClass”。

Creationyang的博客 1057

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

二十一、Gtk4-Template XML and composite widget

前一节中的tfe程序不太好,因为很多东西都塞到了tfeapplication .c中。以及tfeapplication .c中的许多静态变量。文件tfeapplication.c应该被分成几个文件。首选项对话框由ui文件定义。它有GtkBox, GtkLabel和GtkFontButton。这样的小部件可以定义为复合小部件。子对象下一小节将展示如何构建首选项对话框。

Creationyang的博客 912

Glib之GObject简介(翻译)

GObject GObject库是Glib库的动态类型系统实现,它实现了: 基于引用计数的内存管理 实例的构造和析构 通用的set/get的属性获取方法 简单易用的信号机制 对象实例化 所述g_object_new的功能家族可用于实例化从GObject的基类型继承的任何的GType。所有这些函数都确保类和实例结构已经被GLib的类型系统正确地初始化,然后在一个或另一个地方调用用于的构...

dcldz5007的博客 1002

十二、Gtk4-信号

每个对象都封装在Gtk程序中。而且不推荐使用全局变量,因为它们容易使程序变得复杂。因此,我们需要一些东西来在对象之间通信。有两种方法可以做到这一点。函数的调用者或连接到信号的处理程序通常位于对象之外。这两者之间的区别之一是对象是主动的或被动的。在函数中,对象被动地响应调用者。对象主动向处理程序发送信号。GObject信号被注册、连接和发射。

Creationyang的博客 1033

Windows Rust GTK4安装配置

gtk4 安装过程记录,防踩坑

Lao_gan_ma的博客 2207
上一篇: 十二、Gtk4-信号
下一篇: 十四、Gtk4-Functions in GtkNotebook
李尔阳
博客等级 码龄7年 50粉丝 148原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值