保存应用程序状态

本课程的目标是说明如何从其模式定义新的设置,并将它们绑定到窗口上的属性,以便在不同的会话中保存和恢复窗口的大小和状态。

向设置模式添加新的键

设置存储在数据库中,每个键都在模式中描述;模式包含与键关联的值的类型,以及键的默认值。

  1. 打开 com.example.TextViewer.gschema.xml 文件,该文件位于 data 目录中

  2. 在模式中添加 window-widthwindow-heightwindow-maximized 键,分别包括它们的默认值 600、400 和 false

<schemalist gettext-domain="text-viewer">
  <schema id="com.example.TextViewer" path="/com/example/TextViewer/">
    <key name="window-width" type="i">
      <default>600</default>
    </key>
    <key name="window-height" type="i">
      <default>400</default>
    </key>
    <key name="window-maximized" type="b">
      <default>false</default>
    </key>
  </schema>
</schemalist>

注意

在构建应用程序时,模式将自动安装到预期的目录中。这意味着应用程序只能在安装完成后才能运行。

使用 GSettings

GSettings 是监视特定模式 ID 的键的对象。您可以使用 GSettings API 访问键的值,以及获取设置更改的通知。

  1. 打开 text-viewer-window.c 文件

  2. 修改 TextViewerWindow 实例结构,以包含一个 GSettings 实例

struct _TextViewerWindow
{
  AdwApplicationWindow  parent_instance;

  GSettings *settings;

  /* Template widgets */
  AdwHeaderBar *header_bar;
  GtkTextView *main_text_view;
  GtkButton *open_button;
  GtkLabel *cursor_pos;
};
  1. 修改 TextViewerWindow 的实例初始化函数 text_viewer_window_init,以创建用于 com.example.TextViewer 模式 ID 的 GSettings 实例

static void
text_viewer_window_init (TextViewerWindow *self)
{
  gtk_widget_init_template (GTK_WIDGET (self));

  g_autoptr (GSimpleAction) open_action = g_simple_action_new ("open", NULL);
  g_signal_connect (open_action, "activate", G_CALLBACK (text_viewer_window__open_file_dialog), self);
  g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (open_action));

  g_autoptr (GSimpleAction) save_action = g_simple_action_new ("save-as", NULL);
  g_signal_connect (save_action, "activate", G_CALLBACK (text_viewer_window__save_file_dialog), self);
  g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (save_action));

  GtkTextBuffer *buffer = gtk_text_view_get_buffer (self->main_text_view);
  g_signal_connect (buffer,
                    "notify::cursor-position",
                    G_CALLBACK (text_viewer_window__update_cursor_position),
                    self);

  self->settings = g_settings_new ("com.example.TextViewer");
}
  1. 修改 TextViewerWindow 的类初始化函数 text_viewer_window_class_init,以包含一个最终化函数;当 TextViewerWindow 实例即将被释放时,将调用 text_viewer_window_finalize 函数

static void
text_viewer_window_class_init (TextViewerWindowClass *klass)
{
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);

  gobject_class->finalize = text_viewer_window_finalize;

  gtk_widget_class_set_template_from_resource (widget_class, "/com/example/TextViewer/text-viewer-window.ui");
  gtk_widget_class_bind_template_child (widget_class, TextViewerWindow, header_bar);
  gtk_widget_class_bind_template_child (widget_class, TextViewerWindow, main_text_view);
  gtk_widget_class_bind_template_child (widget_class, TextViewerWindow, open_button);
  gtk_widget_class_bind_template_child (widget_class, TextViewerWindow, cursor_pos);
}
  1. 添加 text_viewer_window_finalize 函数,该函数清除 GSettings 实例并链接到父实现

static void
text_viewer_window_finalize (GObject *gobject)
{
  TextViewerWindow *self = TEXT_VIEWER_WINDOW (gobject);

  g_clear_object (&self->settings);

  G_OBJECT_CLASS (text_viewer_window_parent_class)->finalize (gobject);
}

将设置绑定到窗口状态属性

模式中的键可以绑定到 GObject 属性;绑定的属性将在其更改时自动保存到设置数据库中,并在创建时恢复。

  1. 修改 TextViewerWindow 实例初始化函数,将 window-widthwindow-heightwindow-maximize 键绑定到 default-widthdefault-heightmaximized 属性,分别对应

static void
text_viewer_window_init (TextViewerWindow *self)
{
  gtk_widget_init_template (GTK_WIDGET (self));

  g_autoptr (GSimpleAction) open_action = g_simple_action_new ("open", NULL);
  g_signal_connect (open_action, "activate", G_CALLBACK (text_viewer_window__open), self);
  g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (open_action));

  g_autoptr (GSimpleAction) save_action = g_simple_action_new ("save-as", NULL);
  g_signal_connect (save_action, "activate", G_CALLBACK (text_viewer_window__save), self);
  g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (save_action));

  GtkTextBuffer *buffer = gtk_text_view_get_buffer (self->main_text_view);
  g_signal_connect (buffer,
                    "notify::cursor-position",
                    G_CALLBACK (text_viewer_window__cursor_position),
                    self);

  self->settings = g_settings_new ("com.example.TextViewer");

  g_settings_bind (self->settings, "window-width",
                   G_OBJECT (self), "default-width",
                   G_SETTINGS_BIND_DEFAULT);
  g_settings_bind (self->settings, "window-height",
                   G_OBJECT (self), "default-height",
                   G_SETTINGS_BIND_DEFAULT);
  g_settings_bind (self->settings, "window-maximized",
                   G_OBJECT (self), "maximized",
                   G_SETTINGS_BIND_DEFAULT);
}

在本课程中,您添加了与应用程序关联的 GSettings 模式中的键;通过将其与应用程序窗口关联来管理 GSettings 实例的生命周期;并将 GSettings 数据库中的键绑定到应用程序窗口的状态属性。