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与他人通信的唯一方式。
- 调用者通过调用tfe_text_view_new获得指向TfeTextView实例的tv指针。
- 调用者连接处理程序(图中左下角)和信号“open-response”。
- 它调用tfe_text_view_open来提示用户从GtkFileChooserDialog中选择一个文件。
- 对话框发出一个信号,并调用处理程序open_dialog_response。
- 处理程序读取文件并将文本插入到GtkTextBuffer中,并发出信号作为响应代码通知状态。
- 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源代码。