保存应用程序状态¶
本课程的目标是说明如何从其模式定义新的设置,并将它们绑定到窗口上的属性,以便在不同的会话中保存和恢复窗口的大小和状态。
向设置模式添加新的键¶
设置存储在数据库中,每个键都在模式中描述;模式包含与键关联的值的类型,以及键的默认值。
打开
com.example.TextViewer.gschema.xml文件,该文件位于data目录中在模式中添加 window-width、window-height 和 window-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 访问键的值,以及获取设置更改的通知。
打开
text-viewer-window.c文件修改 TextViewerWindow 实例结构,以包含一个 GSettings 实例
struct _TextViewerWindow
{
AdwApplicationWindow parent_instance;
GSettings *settings;
/* Template widgets */
AdwHeaderBar *header_bar;
GtkTextView *main_text_view;
GtkButton *open_button;
GtkLabel *cursor_pos;
};
修改 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");
}
修改 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);
}
添加
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);
}
打开
window.py文件修改 TextViewerWindow 的实例初始化函数,以创建用于
com.example.TextViewer模式 ID 的 GSettings 实例
def __init__(self, **kwargs):
super().__init__(**kwargs)
open_action = Gio.SimpleAction(name="open")
open_action.connect("activate", self.open_file_dialog)
self.add_action(open_action)
save_action = Gio.SimpleAction(name="save-as")
save_action.connect("activate", self.save_file_dialog)
self.add_action(save_action)
buffer = self.main_text_view.get_buffer()
buffer.connect("notify::cursor-position", self.update_cursor_position)
self.settings = Gio.Settings(schema_id="com.example.TextViewer")
打开
window.vala文件修改 TextViewer.Window 类,以包含一个 Settings 属性,并使用
com.example.TextViewer模式 ID 初始化它
namespace TextViewer {
public class Window : Adw.ApplicationWindow {
// ...
private Settings settings = new Settings ("com.example.TextViewer");
// ...
}
}
打开
window.js文件修改 TextViewerWindow 类,以包含一个 _settings 属性,并使用
com.example.TextViewer模式 ID 初始化它
export const TextViewerWindow = GObject.registerClass({
GTypeName: 'TextViewerWindow',
Template: 'resource:///com/example/TextViewer/window.ui',
InternalChildren: ['main_text_view', 'open_button', 'cursor_pos'],
}, class TextViewerWindow extends Adw.ApplicationWindow {
_settings = new Gio.Settings({ schemaId: 'com.example.TextViewer' });
constructor() {
// ...
}
// ...
);
将设置绑定到窗口状态属性¶
模式中的键可以绑定到 GObject 属性;绑定的属性将在其更改时自动保存到设置数据库中,并在创建时恢复。
修改 TextViewerWindow 实例初始化函数,将 window-width、window-height 和 window-maximize 键绑定到 default-width、default-height 和 maximized 属性,分别对应
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);
}
def __init__(self, **kwargs):
super().__init__(**kwargs)
open_action = Gio.SimpleAction(name="open")
open_action.connect("activate", self.open_file_dialog)
self.add_action(open_action)
save_action = Gio.SimpleAction(name="save-as")
save_action.connect("activate", self.save_file_dialog)
self.add_action(save_action)
buffer = self.main_text_view.get_buffer()
buffer.connect("notify::cursor-position", self.update_cursor_position)
self.settings = Gio.Settings(schema_id="com.example.TextViewer")
self.settings.bind("window-width", self, "default-width",
Gio.SettingsBindFlags.DEFAULT)
self.settings.bind("window-height", self, "default-height",
Gio.SettingsBindFlags.DEFAULT)
self.settings.bind("window-maximized", self, "maximized",
Gio.SettingsBindFlags.DEFAULT)
namespace TextViewer {
public class Window : Adw.ApplicationWindow {
// ...
public Window (Gtk.Application app) {
Object (application: app);
}
construct {
var open_action = new SimpleAction ("open", null);
open_action.activate.connect (this.open_file_dialog);
this.add_action (open_action);
var save_action = new SimpleAction ("save-as", null);
save_action.activate.connect (this.save_file_dialog);
self.add_action (save_action);
Gtk.TextBuffer buffer = this.text_view.buffer;
buffer.notify["cursor-position"].connect (this.update_cursor_position);
this.settings.bind ("window-width", this, "default-width", SettingsBindFlags.DEFAULT);
this.settings.bind ("window-height", this, "default-height", SettingsBindFlags.DEFAULT);
this.settings.bind ("window-maximized", this, "maximized", SettingsBindFlags.DEFAULT);
}
}
}
export const TextViewerWindow = GObject.registerClass({
GTypeName: 'TextViewerWindow',
Template: 'resource:///com/example/TextViewer/window.ui',
InternalChildren: ['main_text_view', 'open_button', 'cursor_pos'],
}, class TextViewerWindow extends Adw.ApplicationWindow {
_settings = new Gio.Settings({ schemaId: 'com.example.TextViewer' });
constructor(application) {
super({ application });
// ...
this._settings.bind(
"window-width", this, "default-width", Gio.SettingsBindFlags.DEFAULT);
this._settings.bind(
"window-height", this, "default-height", Gio.SettingsBindFlags.DEFAULT);
this._settings.bind(
"window-maximized", this, "maximized", Gio.SettingsBindFlags.DEFAULT);
}
// ...
});
在本课程中,您添加了与应用程序关联的 GSettings 模式中的键;通过将其与应用程序窗口关联来管理 GSettings 实例的生命周期;并将 GSettings 数据库中的键绑定到应用程序窗口的状态属性。