设置(Settings)
我们现在已经学会了多种处理状态的方法。 但是,每次我们关闭应用程序时,它都消失了。 让我们学习如何通过在 gio::Settings
中存储 Switch
的状态来使用它。
一开始,我们必须创建一个GSchema
xml 文件,以描述我们的应用程序计划在设置中存储的数据类型。
文件名:listings/settings/1/org.gtk_rs.Settings1.gschema.xml
<?xml version="1.0" encoding="utf-8"?>
<schemalist>
<schema id="org.gtk_rs.Settings1" path="/org/gtk_rs/Settings1/">
<key name="is-switch-enabled" type="b">
<default>false</default>
<summary>Default switch state</summary>
</key>
</schema>
</schemalist>
让我们一步一步来。 这个id
与我们在创建应用程序时使用的应用程序 ID 相同。
文件名:listings/settings/1/main.rs
use gio::Settings;
use gtk::prelude::*;
use gtk::{gio, glib, Align, Application, ApplicationWindow, Switch};
const APP_ID: &str = "org.gtk_rs.Settings1";
fn main() -> glib::ExitCode {
// Create a new application
let app = Application::builder().application_id(APP_ID).build();
// Connect to "activate" signal of `app`
app.connect_activate(build_ui);
// Run the application
app.run()
}
fn build_ui(app: &Application) {
// Initialize settings
let settings = Settings::new(APP_ID);
// Get the last switch state from the settings
let is_switch_enabled = settings.boolean("is-switch-enabled");
// Create a switch
let switch = Switch::builder()
.margin_top(48)
.margin_bottom(48)
.margin_start(48)
.margin_end(48)
.valign(Align::Center)
.halign(Align::Center)
.state(is_switch_enabled)
.build();
switch.connect_state_set(move |_, is_enabled| {
// Save changed switch state in the settings
settings
.set_boolean("is-switch-enabled", is_enabled)
.expect("Could not set setting.");
// Allow to invoke other event handlers
glib::Propagation::Proceed
});
// Create a window
let window = ApplicationWindow::builder()
.application(app)
.title("My GTK App")
.child(&switch)
.build();
// Present window
window.present();
}
path
必须以正斜杠字符 ('/') 开头和结尾,并且不能包含两个连续的斜杠字符。 创建 path
时,我们建议使用id
,将 '.' 替换为 '/',并在开头和结尾添加 '/'。
我们只想存储一个name
为 "is-switch-enabled" 的键。 这是一个布尔值,因此其类型为 "b"(其他选项请参见 GVariant Format Strings)。 我们还将其默认值设为 false
(完整语法请参见 GVariant Text Format)。 最后,我们添加一个摘要。
现在,我们需要复制并编译 schema.
在 Linux 或 macOS 机器上执行以下命令即可安装 schema:
mkdir -p $HOME/.local/share/glib-2.0/schemas cp org.gtk_rs.Settings1.gschema.xml $HOME/.local/share/glib-2.0/schemas/ glib-compile-schemas $HOME/.local/share/glib-2.0/schemas/
或者在 Windows 上运行:
mkdir C:/ProgramData/glib-2.0/schemas/ cp org.gtk_rs.Settings1.gschema.xml C:/ProgramData/glib-2.0/schemas/ glib-compile-schemas C:/ProgramData/glib-2.0/schemas/
我们通过指定应用程序 ID 来初始化 Settings
对象。
文件名:listings/settings/1/main.rs
use gio::Settings;
use gtk::prelude::*;
use gtk::{gio, glib, Align, Application, ApplicationWindow, Switch};
const APP_ID: &str = "org.gtk_rs.Settings1";
fn main() -> glib::ExitCode {
// Create a new application
let app = Application::builder().application_id(APP_ID).build();
// Connect to "activate" signal of `app`
app.connect_activate(build_ui);
// Run the application
app.run()
}
fn build_ui(app: &Application) {
// Initialize settings
let settings = Settings::new(APP_ID);
// Get the last switch state from the settings
let is_switch_enabled = settings.boolean("is-switch-enabled");
// Create a switch
let switch = Switch::builder()
.margin_top(48)
.margin_bottom(48)
.margin_start(48)
.margin_end(48)
.valign(Align::Center)
.halign(Align::Center)
.state(is_switch_enabled)
.build();
switch.connect_state_set(move |_, is_enabled| {
// Save changed switch state in the settings
settings
.set_boolean("is-switch-enabled", is_enabled)
.expect("Could not set setting.");
// Allow to invoke other event handlers
glib::Propagation::Proceed
});
// Create a window
let window = ApplicationWindow::builder()
.application(app)
.title("My GTK App")
.child(&switch)
.build();
// Present window
window.present();
}
然后我们获取设置密钥,并在创建 Switch
时使用它。
文件名:listings/settings/1/main.rs
use gio::Settings;
use gtk::prelude::*;
use gtk::{gio, glib, Align, Application, ApplicationWindow, Switch};
const APP_ID: &str = "org.gtk_rs.Settings1";
fn main() -> glib::ExitCode {
// Create a new application
let app = Application::builder().application_id(APP_ID).build();
// Connect to "activate" signal of `app`
app.connect_activate(build_ui);
// Run the application
app.run()
}
fn build_ui(app: &Application) {
// Initialize settings
let settings = Settings::new(APP_ID);
// Get the last switch state from the settings
let is_switch_enabled = settings.boolean("is-switch-enabled");
// Create a switch
let switch = Switch::builder()
.margin_top(48)
.margin_bottom(48)
.margin_start(48)
.margin_end(48)
.valign(Align::Center)
.halign(Align::Center)
.state(is_switch_enabled)
.build();
switch.connect_state_set(move |_, is_enabled| {
// Save changed switch state in the settings
settings
.set_boolean("is-switch-enabled", is_enabled)
.expect("Could not set setting.");
// Allow to invoke other event handlers
glib::Propagation::Proceed
});
// Create a window
let window = ApplicationWindow::builder()
.application(app)
.title("My GTK App")
.child(&switch)
.build();
// Present window
window.present();
}
最后,我们保证,只要点击开关,开关状态就会保存在设置中。
文件名:listings/settings/1/main.rs
use gio::Settings;
use gtk::prelude::*;
use gtk::{gio, glib, Align, Application, ApplicationWindow, Switch};
const APP_ID: &str = "org.gtk_rs.Settings1";
fn main() -> glib::ExitCode {
// Create a new application
let app = Application::builder().application_id(APP_ID).build();
// Connect to "activate" signal of `app`
app.connect_activate(build_ui);
// Run the application
app.run()
}
fn build_ui(app: &Application) {
// Initialize settings
let settings = Settings::new(APP_ID);
// Get the last switch state from the settings
let is_switch_enabled = settings.boolean("is-switch-enabled");
// Create a switch
let switch = Switch::builder()
.margin_top(48)
.margin_bottom(48)
.margin_start(48)
.margin_end(48)
.valign(Align::Center)
.halign(Align::Center)
.state(is_switch_enabled)
.build();
switch.connect_state_set(move |_, is_enabled| {
// Save changed switch state in the settings
settings
.set_boolean("is-switch-enabled", is_enabled)
.expect("Could not set setting.");
// Allow to invoke other event handlers
glib::Propagation::Proceed
});
// Create a window
let window = ApplicationWindow::builder()
.application(app)
.title("My GTK App")
.child(&switch)
.build();
// Present window
window.present();
}
现在,即使关闭应用程序,Switch
也会保留其状态。 但我们可以做得更好。 开关有一个属性 "active",而 Settings
允许我们将属性与特定设置绑定。 因此,我们就来做这件事。
我们可以删除初始化 Switch
之前的 boolean
调用以及 connect_state_set
调用。 然后,我们通过指定键、对象和属性名称将设置绑定到属性。
文件名:listings/settings/2/main.rs
use gio::Settings;
use gtk::prelude::*;
use gtk::{gio, glib, Align, Application, ApplicationWindow, Switch};
const APP_ID: &str = "org.gtk_rs.Settings2";
fn main() -> glib::ExitCode {
// Create a new application
let app = Application::builder().application_id(APP_ID).build();
// Connect to "activate" signal of `app`
app.connect_activate(build_ui);
// Run the application
app.run()
}
fn build_ui(app: &Application) {
// Initialize settings
let settings = Settings::new(APP_ID);
// Create a switch
let switch = Switch::builder()
.margin_top(48)
.margin_bottom(48)
.margin_start(48)
.margin_end(48)
.valign(Align::Center)
.halign(Align::Center)
.build();
settings
.bind("is-switch-enabled", &switch, "active")
.build();
// Create a window
let window = ApplicationWindow::builder()
.application(app)
.title("My GTK App")
.child(&switch)
.build();
// Present window
window.present();
}
只要有一个属性与一个设置很好地对应,你可能就会想把它绑定到设置上。 在其他情况下,通过 getter 和 setter 方法与设置交互往往是正确的选择。