十三、Gtk4-TfeTextView函数

news2025/1/21 12:14:21

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源代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/161105.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

「布道人生」第一期:阿里云DevOps资深专家章屹

本期嘉宾——章 屹 阿里云 DevOps 资深专家。2012 年加入阿里巴巴&#xff0c;十年如一日专注在 DevOps 领域的理论、咨询、解决方案和产品技术工作上。作为 CIO 学院和阿里云大学的讲师&#xff0c;为众多大型企业管理高层讲授 DevOps 课程&#xff0c;探讨通过 DevOps 提升企…

drawCell | 不会画细胞结构图就用这个R包吧~ Super Nice!~

1写在前面 我们在paper中经常需要画到细胞结构图&#xff0c;新手ppt一点一点画&#xff0c;高手可能会用AI手搓&#xff0c;土豪直接使用BioRender。&#x1f912; 今天给大家大家分享一个代码画细胞结构图的R包&#xff0c;如果你觉得自己不会写代码&#xff0c;不想看了&…

python基础篇之元组、字典(增删改查)

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a;lqj_本人的博客_CSDN博客-微信小程序,前端,vue领域博主lqj_本人擅长微信小程序,前端,vue,等方面的知识https://blog.csdn.net/lbcyllqj?spm1000.2115.3001.5343 哔哩哔哩欢迎关注&…

震旦ad188复印机报机器故障维修召唤c0211

故障现象: 手送走纸的机器出现嗒嗒的异响,走几张还会跳0211,经常出现卡纸等现象,或者报C0211; 故障分析: 维修召唤C0211可能是感光鼓和载体寿命到期࿰

云原生|Java二级高速缓存架构设计

为什么使用缓存 缓存&#xff0c;主要有两个用途&#xff1a;提高服务性能和并发。 缓存是提高服务响应速度最快的方式之一。 我们设计缓存的目的是减少用户直接访问磁盘、访问网络带来的性能损耗&#xff0c;把磁盘、网络请求的内容存在在内存中&#xff0c;提升应用程序的…

【Doris】Doris数据库最新版安装方法,详细图文教程

环境安装 Doris 作为一款开源的 MPP 架构 OLAP 数据库&#xff0c;能够运行在绝大多数主流的商用服务器上。为了能够充分运用 MPP 架构的并发优势&#xff0c;以及 Doris 的高可用特性&#xff0c;我们建议 Doris 的部署遵循以下需求&#xff1a; Linux 操作系统版本需求Linu…

研讨会回顾 | UI自动化测试现场演示

2022年12月6日&#xff0c;龙智与软件测试自动化“领导者”SmartBear联合举办了主题为“如何通过自动化测试实现降本、增效与提质”的在线研讨会。此次研讨会中&#xff0c;龙智技术工程师邱洁玉现场演示了使用UI自动化测试的过程&#xff0c;并简要介绍了API的自动化测试。 软…

时钟频率与时间单位的换算

1. 频率、时间 各自的单位的关系 频率&#xff1a; 1GHz 1000MHz、1MHz 1000KHz、1KHz 1000Hz 1GHz 103MHz 106KHz 109Hz 时间&#xff1a; 1s 1000ms、1ms 1000μs、1μs 1000ns [注]&#xff1a;s (秒)、ms (毫秒)、μs (微秒)、ns (纳秒)。 2. 时间 和 频率 的换…

jsp税务管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 jsp 税务管理系统 是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开 发&#xff0c;数据库为Mysql&#xff0c;使用ja…

【SpringCloud10】OpenFeign服务接口调用

1.概述 1.1OpenFeign是什么 官网 Feign是一个声明式WebService客户端&#xff0c;使用Feign能让编写Web Service客户端更加简单。 它的使用方法是定义一个服务接口然后在上面添加注解&#xff0c;Feign也支持可拔插式的编码器和解码器&#xff0c;Spring Cloud对Feign进行了…

设计模式-JDBC中的桥接模式

一、首先看整个brige模式的结构图。如下&#xff1a;Abstraction — 抽象化角色&#xff1a;定义抽象的接口&#xff0c;包含一个对实现化角色的引用Refined Abstraciotn — 扩展抽象化角色&#xff1a;抽象化角色的子类&#xff0c;实现父类中的业务方法&#xff0c;并通过组合…

录屏专家怎么用?录屏软件使用教程(附下载)

想要更好地录制电脑屏幕可以使用电脑录屏专家&#xff0c;但有很多人在安装录屏专家之后&#xff0c;不知道如何使用。录屏专家怎么用&#xff1f;怎样使用录屏专家录制电脑屏幕&#xff1f;下面小编给您分享录屏软件使用的教程&#xff08;附安装教程&#xff09;&#xff0c;…

RabbitMQ实战:性能和安全

本系列是「RabbitMQ实战&#xff1a;高效部署分布式消息队列」书籍的总结笔记。 前两篇介绍了RabbitMQ在可用性、监控方面的考虑&#xff0c;这是基础保障&#xff0c;因为在某些场景下是不容许丢失消息的&#xff0c;但它和性能往往是对立的&#xff0c;需要根据业务场景做取舍…

JSP SSM众包网站系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 JSP SSM众包网站系统 是一套完善的系统源码&#xff0c;对理解JSP java SrpingMVC mybiats 框架 MVC编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;以及相应配套的设计文档&#xff0c;系统主要采用B/S模式开发。 研究的基本内容…

JUC并发编程学习笔记——CAS个人理解

1. CAS引出 1.1 悲观锁 顾名思义&#xff0c;就是比较悲观的锁&#xff0c;总是假设最坏的情况&#xff0c;每次去拿数据的时候都认为别人会修改&#xff0c;所以每次在拿数据的时候都会上锁&#xff0c;这样别人想拿这个数据就会阻塞直到它拿到锁&#xff08;共享资源每次只…

什么是 HTTP?

什么是 HTTP&#xff1f; 超文本传输协议 (HTTP) 是万维网的基础&#xff0c;用于通过超文本链接加载网页。HTTP 是应用程序层协议&#xff0c;旨在在联网设备之间传输信息&#xff0c;并在网络协议栈的其他层之上运行。HTTP 上的典型流涉及客户端计算机向服务器发出请求&…

2023CUPT第十四题 射流的折射 思路与解法

文章未完首先声明一点&#xff0c;这个题我还没想好最后的答案&#xff0c;欢迎交流&#xff08;备注&#xff1a;博主今年不参加CUPT 博主去做电子设计大赛了&#xff01;有电赛谁还玩CUPT啊&#xff09;声明2&#xff1a;博主没有学过流体力学所以。。声明3&#xff1a;博主的…

[oeasy]python0045_转化为10进制数_int_integrate_integer_entire_整数

转化为10进制 回忆上次内容 上这次总结了四种进制 函数名对应单词进制类型数字事例前缀bin()binary20b11000010boct()octal80o1410ohex()hexadecimal160x610x?decimal1097无 十进制数 可以转化 为 其他进制 的 字符串状态 那反过来 其他进制形态的字符串 可以转化回 10进制…

Qt 自带标题处理方法思路

目录 需求 相关方法也有两种 1.只需要继承QAbstractNativeEventFilter类&#xff0c;从写放nativeEventFilter&#xff0c;并调用安装函数installNativeEventFilter 2.第二种是Qt提供的继承QWidget 重写bool nativeEvent(const QByteArray &eventType, void *message, …

RocketMQ事务消息原理简析

零、业务场景 在项目中&#xff0c;经常遇到这样一个场景&#xff0c;需要保证数据持久化和消息发送要么同时成功&#xff0c;要么同时失败。比如当用户在交易系统下了一个订单&#xff0c;购物车需要消费订单消息清除加购数据、积分系统需要变更用户积分、短信平台需要给买家…