六、Gtk4-Widgets (3)

1 Open 信号

1.1 G_APPLICATION_HANDLES_OPEN flag

在上一节中,我们使用GtkTextView、GtkTextBuffer和GtkScrolledWindow创建了一个非常简单的编辑器。我们将为程序添加文件读取功能,并将其改进为文件查看器。

要给出文件名,最简单的方法是使用命令行参数。

$ ./a.out filename

该程序将打开文件并将其内容插入GtkTextBuffer。

为此,我们需要知道GtkApplication(或GApplication)如何识别参数。这在GIO API参考-应用程序中描述。

当创建GtkApplication时,一个标志(GApplicationFlags)作为参数给出。

GtkApplication *
gtk_application_new (const gchar *application_id, GApplicationFlags flags);

本教程只解释两个标志,G_APPLICATION_DEFAULT_FLAGSG_APPLICATION_HANDLES_OPEN。(在GIO version2.73.3之前使用了G_APPLICATION_FLAGS_NONE而不是G_APPLICATION_DEFAULT_FLAGS (GLib 2.73.3 5/Aug/2022)。有些GTK 4应用程序仍然使用G_APPLICATION_FLAGS_NONE。但现在已弃用,建议使用G_APPLICATION_DEFAULT_FLAGS。)如果你想处理命令行参数,G_APPLICATION_HANDLES_COMMAND_LINE标志就是你所需要的。

有关更多信息,请参阅GIO API Reference——ApplicationFlags和GIO API Reference——g_application_run。

我们已经使用了G_APPLICATION_DEFAULT_FLAGS,因为它是最简单的选项,并且不允许任何命令行参数。如果你提供了参数,就会发生错误。

第二简单的选项是G_APPLICATION_HANDLES_OPEN标志。它允许参数,但只允许文件。应用程序假定所有参数都是文件名。

app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPEN);

1.2 open 信号

在G_APPLICATION_HANDLES_OPEN标志提供给应用程序时,有两个信号可用。

  • activate signal——这个信号在没有参数时发出。
  • open signal——当至少有一个参数时,该信号被触发。

“open”信号的处理程序定义如下。

void
open (
  GApplication* self,
  gpointer files,
  gint n_files,
  gchar* hint,
  gpointer user_data
)

参数有:

  • self——应用程序实例(通常是GtkApplication)
  • files——一个gfile数组。[array length=n_files][element-type GFile]
  • n_files——文件元素的数目
  • hint——由调用实例提供的提示(通常可以忽略)
  • user_data——连接信号处理程序时的用户数据集。

2 开发一个文件查看器

2.1 什么是一个文件查看器

文件查看器是一个显示文本文件的程序。我们的文件查看器将按如下方式工作。

  • 当给出参数时,它将第一个参数识别为文件名并打开它。
  • 第二个参数和后面的参数会被忽略。
  • 如果没有参数,它会显示一条错误消息并退出。
  • 如果它成功打开文件,它读取文件的内容,将它们插入 GtkTextBuffer并显示窗口。
  • 如果打开文件失败,它会显示一个错误消息并退出。

程序如下所示。

 1 #include <gtk/gtk.h>
 2 
 3 static void
 4 app_activate (GApplication *app) {
 5   g_printerr ("You need a filename argument.\n");
 6 }
 7 
 8 static void
 9 app_open (GApplication *app, GFile ** files, int n_files, char *hint) {
10   GtkWidget *win;
11   GtkWidget *scr;
12   GtkWidget *tv;
13   GtkTextBuffer *tb;
14   char *contents;
15   gsize length;
16   char *filename;
17 
18   win = gtk_application_window_new (GTK_APPLICATION (app));
19   gtk_window_set_default_size (GTK_WINDOW (win), 400, 300);
20 
21   scr = gtk_scrolled_window_new ();
22   gtk_window_set_child (GTK_WINDOW (win), scr);
23 
24   tv = gtk_text_view_new ();
25   tb = gtk_text_view_get_buffer (GTK_TEXT_VIEW (tv));
26   gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (tv), GTK_WRAP_WORD_CHAR);
27   gtk_text_view_set_editable (GTK_TEXT_VIEW (tv), FALSE);
28   gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scr), tv);
29 
30   if (g_file_load_contents (files[0], NULL, &contents, &length, NULL, NULL)) {
31     gtk_text_buffer_set_text (tb, contents, length);
32     g_free (contents);
33     if ((filename = g_file_get_basename (files[0])) != NULL) {
34       gtk_window_set_title (GTK_WINDOW (win), filename);
35       g_free (filename);
36     }
37     gtk_window_present (GTK_WINDOW (win));
38   } else {
39     if ((filename = g_file_get_path (files[0])) != NULL) {
40       g_printerr ("No such file: %s.\n", filename);
41       g_free (filename);
42     } else
43       g_printerr ("File can't be opened.\n");
44     gtk_window_destroy (GTK_WINDOW (win));
45   }
46 }
47 
48 int
49 main (int argc, char **argv) {
50   GtkApplication *app;
51   int stat;
52 
53   app = gtk_application_new ("com.github.ToshioCP.tfv3", G_APPLICATION_HANDLES_OPEN);
54   g_signal_connect (app, "activate", G_CALLBACK (app_activate), NULL);
55   g_signal_connect (app, "open", G_CALLBACK (app_open), NULL);
56   stat = g_application_run (G_APPLICATION (app), argc, argv);
57   g_object_unref (app);
58   return stat;
59 }

保存以上代码到tfv3.c,并且编译和运行它。

$ comp tfv3
$ ./a.out tfv3.c

在这里插入图片描述
与前一个版本相比,函数main只有两个变化。

  • G_APPLICATION_DEFAULT_FLAGS替换为 -G_APPLICATION_HANDLES_OPEN
  • 添加g_signal_connect (app, “open”, G_CALLBACK (app_open), NULL)。

在将标志G_APPLICATION_HANDLES_OPEN传递给gtk_application_new函数时,应用程序的行为如下:

  • 如果应用程序在没有命令行参数的情况下运行,它被激活时会发出“activate”信号。
  • 如果应用程序以命令行参数运行,则在激活时发出“open”信号。

处理程序app_activate变得非常简单。它只是输出错误消息并返回给调用者。然后应用程序立即退出,因为没有创建窗口。

主要工作在处理程序app_open中完成。

创建GtkApplicationWindow, GtkScrolledWindow, GtkTextView和GtkTextBuffer,并将它们连接在一起
在GtktextView中设置wrap模式为GTK_WRAP_WORD_CHAR
将GtkTextView设置为不可编辑,因为程序不是编辑器,而是查看器
读取文件并将文本插入GtkTextBuffer(稍后会解释)。
如果文件没有打开,输出一个错误消息并销毁窗口。这会让应用退出。

下面是程序读取文件的部分。

if (g_file_load_contents (files[0], NULL, &contents, &length, NULL, NULL)) {
  gtk_text_buffer_set_text (tb, contents, length);
  g_free (contents);
  if ((filename = g_file_get_basename (files[0])) != NULL) {
    gtk_window_set_title (GTK_WINDOW (win), filename);
    g_free (filename);
  }
  gtk_widget_show (win);
} else {
  if ((filename = g_file_get_path (files[0])) != NULL) {
    g_printerr ("No such file: %s.\n", filename);
    g_free (filename);
  } else
    g_printerr ("File can't be opened.\n");
  gtk_window_destroy (GTK_WINDOW (win));
}

函数g_file_load_contents将文件内容加载到一个临时缓冲区中,该缓冲区是自动分配的,并将内容设置为指向该缓冲区。将缓冲区的长度赋值给length。如果文件内容加载成功,它返回TRUE;如果发生错误,则返回FALSE。如果想了解有关g_file_load_contents的详细信息,请参见g file load contents。

如果成功读取文件,则将内容插入到GtkTextBuffer中,释放由内容指向的临时缓冲区,设置窗口标题,释放由文件名指向的内存,然后显示窗口。如果失败,则输出错误消息并销毁窗口,最后让程序退出。

3 GtkNotebook

GtkNotebook是一个容器部件,可以包含多个带有标签的构件。它一次只显示一个子构建。当单击其标签时,将显示另一个子构件。
在这里插入图片描述大多数更改都发生在app_open函数中。以下项目左侧的数字是源代码中的行号。

  • 11-13:定义了变量nb、lab和nbp。它们分别指向GtkNotebook、GtkLabel和GtkNotebookPage。
  • 23:窗口的标题设置为"file viewer"。
  • 24:窗口默认大小为600x400。
  • 26-27创建了gtnotebook,并将其作为子构件插入到GtkApplicationWindow中。
  • 29-58 for循环。变量files[i]指向第i个GFile,它是由GtkApplication根据第i个命令行参数创建的。
  • 31-36 创建GtkScrollledWindow、GtkTextView。GtkTextBuffer是从GtkTextView获得的。GtkTextView作为子构件连接到GtkScrolledWindow。
  • 38-39将文件的内容插入到GtkTextBuffer中,并释放内容指向的内存。
  • 40-42:如果文件名来自GFile,则使用该文件名创建GtkLabel。字符串filename被释放。
  • 43-44:如果获取文件名失败,则创建空字符串GtkLabel。
  • 45-46:将GtkScrolledWindow作为子构件附加到GtkNotebook。并将GtkLabel设置为子构件的选项卡。同时,GtkNoteBookPage会被自动创建。函数gtk_notebook_get_page返回子构件(GtkScrolledWindow)页面的GtkNotebookPage。
    47: GtkNotebookPage具有“tab-expand”属性。如果设置为TRUE,选项卡就会尽可能地水平展开。如果为FALSE,则选项卡的宽度由标签的大小决定。g_object_set是一个设置对象属性的通用函数。参见GObject API参考——g_object_set。
    48-50:如果读取文件失败,从GFile中取了文件名,则显示“No such file”。文件名被释放。
    51-52:如果filename为NULL,则显示“No valid file is given”。
    54—57:如果至少存在一个页面,则显示该窗口。否则,窗口将被销毁,应用程序将退出。

参考:Gtk4 tutorial Widgets (3)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值