We have now learned multiple ways to handle states.
However, every time we close the application all of it is gone.
Let's learn how to use gio::Settings by storing the state of a Switch in it.
At the very beginning we have to create a GSchema xml file in order to describe the kind of data our application plans to store in the settings.
use gio::Settings;
use gtk::prelude::*;
use gtk::{gio, glib, Align, Application, ApplicationWindow, Switch};
const APP_ID: &str = "org.gtk_rs.Settings1";
fnmain() -> glib::ExitCode {
// Create a new applicationlet app = Application::builder().application_id(APP_ID).build();
// Connect to "activate" signal of `app` app.connect_activate(build_ui);
// Run the application app.run()
}
fnbuild_ui(app: &Application) {
// Initialize settingslet settings = Settings::new(APP_ID);
// Get the last switch state from the settingslet is_switch_enabled = settings.boolean("is-switch-enabled");
// Create a switchlet 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 windowlet window = ApplicationWindow::builder()
.application(app)
.title("My GTK App")
.child(&switch)
.build();
// Present window window.present();
}
The path must start and end with a forward slash character ('/') and must not contain two sequential slash characters.
When creating a path, we advise to take the id, replace the '.' with '/' and add '/' at the front and end of it.
We only want to store a single key with the name "is-switch-enabled".
This is a boolean value so its type is "b" (see GVariant Format Strings for the other options).
We also set its default value to false (see GVariant Text Format for the full syntax).
Finally, we add a summary.
Now we need to copy and compile the schema.
You can install the schema by executing the following commands on a Linux or macOS machine:
use gio::Settings;
use gtk::prelude::*;
use gtk::{gio, glib, Align, Application, ApplicationWindow, Switch};
const APP_ID: &str = "org.gtk_rs.Settings1";
fnmain() -> glib::ExitCode {
// Create a new applicationlet app = Application::builder().application_id(APP_ID).build();
// Connect to "activate" signal of `app` app.connect_activate(build_ui);
// Run the application app.run()
}
fnbuild_ui(app: &Application) {
// Initialize settingslet settings = Settings::new(APP_ID);
// Get the last switch state from the settingslet is_switch_enabled = settings.boolean("is-switch-enabled");
// Create a switchlet 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 windowlet window = ApplicationWindow::builder()
.application(app)
.title("My GTK App")
.child(&switch)
.build();
// Present window window.present();
}
Then we get the settings key and use it when we create our Switch.
use gio::Settings;
use gtk::prelude::*;
use gtk::{gio, glib, Align, Application, ApplicationWindow, Switch};
const APP_ID: &str = "org.gtk_rs.Settings1";
fnmain() -> glib::ExitCode {
// Create a new applicationlet app = Application::builder().application_id(APP_ID).build();
// Connect to "activate" signal of `app` app.connect_activate(build_ui);
// Run the application app.run()
}
fnbuild_ui(app: &Application) {
// Initialize settingslet settings = Settings::new(APP_ID);
// Get the last switch state from the settingslet is_switch_enabled = settings.boolean("is-switch-enabled");
// Create a switchlet 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 windowlet window = ApplicationWindow::builder()
.application(app)
.title("My GTK App")
.child(&switch)
.build();
// Present window window.present();
}
Finally, we assure that the switch state is stored in the settings whenever we click on it.
use gio::Settings;
use gtk::prelude::*;
use gtk::{gio, glib, Align, Application, ApplicationWindow, Switch};
const APP_ID: &str = "org.gtk_rs.Settings1";
fnmain() -> glib::ExitCode {
// Create a new applicationlet app = Application::builder().application_id(APP_ID).build();
// Connect to "activate" signal of `app` app.connect_activate(build_ui);
// Run the application app.run()
}
fnbuild_ui(app: &Application) {
// Initialize settingslet settings = Settings::new(APP_ID);
// Get the last switch state from the settingslet is_switch_enabled = settings.boolean("is-switch-enabled");
// Create a switchlet 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 windowlet window = ApplicationWindow::builder()
.application(app)
.title("My GTK App")
.child(&switch)
.build();
// Present window window.present();
}
The Switch now retains its state even after closing the application.
But we can make this even better.
The Switch has a property "active" and Settings allows us to bind properties to a specific setting.
So let's do exactly that.
We can remove the boolean call before initializing the Switch as well as the connect_state_set call.
We then bind the setting to the property by specifying the key, object and name of the property.
Filename: 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";
fnmain() -> glib::ExitCode {
// Create a new applicationlet app = Application::builder().application_id(APP_ID).build();
// Connect to "activate" signal of `app` app.connect_activate(build_ui);
// Run the application app.run()
}
fnbuild_ui(app: &Application) {
// Initialize settingslet settings = Settings::new(APP_ID);
// Create a switchlet 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 windowlet window = ApplicationWindow::builder()
.application(app)
.title("My GTK App")
.child(&switch)
.build();
// Present window window.present();
}
Whenever you have a property which nicely correspond to a setting, you probably want to bind it to it.
In other cases, interacting with the settings via the getter and setter methods tends to be the right choice.