强制深色主题¶
GNOME 应用程序会尊重系统设置中的浅色或深色主题。但是,你可以在应用程序的 UI 中向用户提供强制深色主题的选择。
将深色模式操作添加到应用程序¶
打开 TextViewApplication 源代码
找到 TextViewApplication 实例初始化函数
创建 dark-mode 状态操作,并连接到其
activate和change-state信号将操作添加到应用程序
static void
text_viewer_application_init (TextViewerApplication *self)
{
g_autoptr (GSimpleAction) dark_action =
g_simple_action_new_stateful ("dark-mode",
NULL,
g_variant_new_boolean (FALSE));
g_signal_connect (dark_action, "activate", G_CALLBACK (toggle_dark_mode), self);
g_signal_connect (dark_action, "change-state", G_CALLBACK (change_color_scheme), self);
g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (dark_action));
from gi.repository import Adw, Gio, GLib, Gtk
from .window import PytextViewerWindow, AboutDialog
class TextViewerApplication(Adw.Application):
def __init__(self):
super().__init__(application_id='com.example.TextViewer',
flags=Gio.ApplicationFlags.FLAGS_NONE)
dark_mode_action = Gio.SimpleAction(name="dark-mode",
state=GLib.Variant.new_boolean(False))
dark_mode_action.connect("activate", self.toggle_dark_mode)
dark_mode_action.connect("change-state", self.change_color_scheme)
self.add_action(dark_mode_action)
namespace TextViewer {
public class Application : Adw.Application {
// ...
public Application () {
Object (application_id: "com.example.TextViewer",
flags: ApplicationFlags.FLAGS_NONE);
}
construct {
var dark_mode_action = new SimpleAction.stateful ("dark-mode", null, new Variant.boolean (false));
dark_mode_action.activate.connect (this.toggle_dark_mode);
dark_mode_action.change_state.connect (this.change_color_scheme);
}
}
}
导入 GLib,因为我们将使用 GLib.Variant
import GObject from 'gi://GObject';
import Gio from 'gi://Gio';
import Gtk from 'gi://Gtk?version=4.0';
import Adw from 'gi://Adw?version=1';
import GLib from 'gi://GLib';
创建并配置 dark-mode 操作
export const TextViewerApplication = GObject.registerClass(
class TextViewerApplication extends Adw.Application {
constructor() {
super({application_id: 'com.example.TextViewer', flags: Gio.ApplicationFlags.FLAGS_NONE});
this.set_accels_for_action('win.open', [ '<Ctrl>o' ]);
this.set_accels_for_action('win.save-as', [ '<Ctrl><Shift>s' ]);
const darkModeAction = Gio.SimpleAction.new_stateful(
'dark-mode', null, GLib.Variant.new_boolean(false));
darkModeAction.connect('activate', this.toggleDarkMode.bind(this));
darkModeAction.connect('change-state', this.changeColorScheme.bind(this));
this.add_action(darkModeAction);
// ...
}
// ...
}
);
添加
toggle_dark_mode回调;此回调在“true”和“false”之间切换 dark-mode 操作的状态
static void
toggle_dark_mode (GSimpleAction *action,
GVariant *parameter G_GNUC_UNUSED,
gpointer user_data G_GNUC_UNUSED)
{
GVariant *state = g_action_get_state (G_ACTION (action));
gboolean old_state = g_variant_get_boolean (state);
gboolean new_state = !old_state;
g_action_change_state (G_ACTION (action), g_variant_new_boolean (new_state));
g_variant_unref (state);
}
def toggle_dark_mode(self, action, _):
state = action.get_state()
old_state = state.get_boolean()
new_state = not old_state
action.change_state(GLib.Variant.new_boolean(new_state))
private void toggle_dark_mode (Action action, Variant? parameter) {
Variant state = action.state;
bool old_state = state.get_boolean ();
bool new_state = !old_state;
action.change_state (new_state);
}
toggleDarkMode (action) {
const oldState = action.state.get_boolean();
const newState = !oldState;
action.change_state(GLib.Variant.new_boolean(newState));
}
添加
change_color_scheme回调;此回调负责使用 AdwStyleManager API 切换应用程序的配色方案
static void
change_color_scheme (GSimpleAction *action,
GVariant *new_state,
TextViewerApplication *self)
{
gboolean dark_mode = g_variant_get_boolean (new_state);
AdwStyleManager *style_manager = adw_style_manager_get_default ();
if (dark_mode)
adw_style_manager_set_color_scheme (style_manager, ADW_COLOR_SCHEME_FORCE_DARK);
else
adw_style_manager_set_color_scheme (style_manager, ADW_COLOR_SCHEME_DEFAULT);
g_simple_action_set_state (action, new_state);
}
def change_color_scheme(self, action, new_state):
dark_mode = new_state.get_boolean()
style_manager = Adw.StyleManager.get_default()
if dark_mode:
style_manager.set_color_scheme(Adw.ColorScheme.FORCE_DARK)
else:
style_manager.set_color_scheme(Adw.ColorScheme.DEFAULT)
action.set_state(new_state)
private void change_color_scheme (SimpleAction action, Variant? new_state) {
bool dark_mode = new_state.get_boolean ();
var style_manager = Adw.StyleManager.get_default ();
if (dark_mode)
style_manager.color_scheme = Adw.ColorScheme.FORCE_DARK;
else
style_manager.color_scheme = Adw.ColorScheme.DEFAULT;
action.set_state (new_state);
}
changeColorScheme(action, newState) {
const isDarkMode = newState.get_boolean();
const styleManager = Adw.StyleManager.get_default();
styleManager.color_scheme = isDarkMode
? Adw.ColorScheme.FORCE_DARK
: Adw.ColorScheme.DEFAULT;
action.set_state (newState);
}
将深色模式状态存储为设置¶
如果你想在会话之间保留所选的配色方案,可以将它存储在 GSettings 中,你已经在 保存应用程序状态 中添加了 GSettings。
在设置模式中添加一个新键¶
打开
com.example.TextViewer.gschema.xml文件添加一个 dark-mode 布尔键
<?xml version="1.0" encoding="UTF-8"?>
<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>
<key name="dark-mode" type="b">
<default>false</default>
</key>
</schema>
</schemalist>
将 GSettings 添加到应用程序¶
将 GSettings 实例添加到 TextViewerApplication
struct _TextViewerApplication
{
GtkApplication parent_instance;
GSettings *settings;
};
在 TextViewerApplication 实例被释放时清除 GSettings 实例
static void
text_viewer_application_dispose (GObject *gobject)
{
TextViewerApplication *self = TEXT_VIEWER_APPLICATION (gobject);
g_clear_object (&self->settings);
G_OBJECT_CLASS (text_viewer_application_parent_class)->dispose (gobject);
}
static void
text_viewer_application_class_init (TextViewerApplicationClass *klass)
{
GApplicationClass *app_class = G_APPLICATION_CLASS (klass);
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
gobject_class->dispose = text_viewer_application_dispose;
与 TextViewerApplication 的其余部分一起初始化 GSettings 实例
static void
text_viewer_application_init (TextViewerApplication *self)
{
self->settings = g_settings_new ("com.example.TextViewer");
g_autoptr (GSimpleAction) quit_action = g_simple_action_new ("quit", NULL);
g_signal_connect_swapped (quit_action, "activate", G_CALLBACK (g_application_quit), self);
g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (quit_action));
将 GSettings 实例添加到你的 TextViewerApplication
class TextViewerApplication(Adw.Application):
def __init__(self):
super().__init__(application_id='com.example.TextViewer',
flags=Gio.ApplicationFlags.FLAGS_NONE)
self.settings = Gio.Settings(schema_id="com.example.TextViewer")
将 Settings 实例添加到你的 TextViewer.Application
namespace TextViewer {
public class Application : Adw.Application {
// ...
private Settings settings = new Settings ("com.example.TextViewer");
public Application () {
Object (application_id: "com.example.TextViewer",
flags: ApplicationFlags.FLAGS_NONE);
}
// ...
}
}
将 Gio.Settings 实例添加到你的 TextViewerApplication
export const TextViewerApplication = GObject.registerClass(
class TextViewerApplication extends Adw.Application {
_settings = new Gio.Settings({ schemaId: 'com.example.TextViewer' });
constructor() {
// ...
}
// ...
}
);
设置配色方案的初始状态¶
检索 dark-mode GSettings 键的值
使用键的值设置配色方案
使用键的值初始化 dark-mode 操作的状态
static void
text_viewer_application_init (TextViewerApplication *self)
{
self->settings = g_settings_new ("com.example.TextViewer");
gboolean dark_mode = g_settings_get_boolean (self->settings, "dark-mode");
AdwStyleManager *style_manager = adw_style_manager_get_default ();
if (dark_mode)
adw_style_manager_set_color_scheme (style_manager, ADW_COLOR_SCHEME_FORCE_DARK);
else
adw_style_manager_set_color_scheme (style_manager, ADW_COLOR_SCHEME_DEFAULT);
g_autoptr (GSimpleAction) dark_action =
g_simple_action_new_stateful ("dark-mode", NULL, g_variant_new_boolean (dark_mode));
g_signal_connect (dark_action, "activate", G_CALLBACK (text_viewer_application_toggle_action), self);
g_signal_connect (dark_action, "change-state", G_CALLBACK (text_viewer_application_dark_mode_changed), self);
g_action_map_add_action (G_ACTION_MAP (self), G_ACTION (dark_action));
class TextViewerApplication(Adw.Application):
def __init__(self):
super().__init__(application_id='com.example.TextViewer',
flags=Gio.ApplicationFlags.FLAGS_NONE)
self.settings = Gio.Settings(schema_id="com.example.TextViewer")
dark_mode = self.settings.get_boolean("dark-mode")
style_manager = Adw.StyleManager.get_default()
if dark_mode:
style_manager.set_color_scheme(Adw.ColorScheme.FORCE_DARK)
else:
style_manager.set_color_scheme(Adw.ColorScheme.DEFAULT)
dark_mode_action = Gio.SimpleAction(name="dark-mode",
state=GLib.Variant.new_boolean(dark_mode))
dark_mode_action.connect("activate", self.toggle_dark_mode)
dark_mode_action.connect("change-state", self.change_color_scheme)
self.add_action(dark_mode_action)
namespace TextViewer {
public class Application : Adw.Application {
// ...
private Settings settings = new Settings ("com.example.TextViewer");
public Application () {
Object (application_id: "com.example.TextViewer",
flags: ApplicationFlags.FLAGS_NONE);
}
construct {
bool dark_mode = this.settings.get_boolean ("dark-mode");
var style_manager = Adw.StyleManager.get_default ();
if (dark_mode)
style_manager.color_scheme = Adw.ColorScheme.FORCE_DARK;
else
style_manager.color_scheme = Adw.ColorScheme.DEFAULT;
var dark_mode_action = new SimpleAction.stateful ("dark-mode", null, new Variant.boolean (dark_mode));
dark_mode_action.activate.connect (this.toggle_dark_mode);
dark_mode_action.change_state.connect (this.change_color_scheme);
this.add_action (dark_mode_action);
}
}
}
export const TextViewerApplication = GObject.registerClass(
class TextViewerApplication extends Adw.Application {
_settings = new Gio.Settings({ schemaId: 'com.example.TextViewer' });
constructor() {
super({application_id: 'com.example.TextViewer', flags: Gio.ApplicationFlags.FLAGS_NONE});
this.set_accels_for_action('win.open', [ '<Ctrl>o' ]);
this.set_accels_for_action('win.save-as', [ '<Ctrl><Shift>s' ]);
const isDarkMode = this._settings.get_boolean('dark-mode');
const styleManager = Adw.StyleManager.get_default();
styleManager.color_scheme = isDarkMode
? Adw.ColorScheme.FORCE_DARK
: Adw.ColorScheme.DEFAULT;
const darkModeAction = Gio.SimpleAction.new_stateful(
'dark-mode', null, GLib.Variant.new_boolean(isDarkMode));
darkModeAction.connect('activate', this.toggleDarkMode.bind(this));
darkModeAction.connect('change-state', this.changeColorScheme.bind(this));
this.add_action(darkModeAction);
// ...
}
// ...
}
);
在配色方案更改时保存它¶
每当 dark-mode 操作的状态发生更改时,使用 dark-mode 操作的状态更新 dark-mode GSettings 键。
static void
change_color_scheme (GSimpleAction *action,
GVariant *value,
TextViewerApplication *self)
{
gboolean dark_mode = g_variant_get_boolean (value);
AdwStyleManager *style_manager = adw_style_manager_get_default ();
if (dark_mode)
adw_style_manager_set_color_scheme (style_manager, ADW_COLOR_SCHEME_FORCE_DARK);
else
adw_style_manager_set_color_scheme (style_manager, ADW_COLOR_SCHEME_DEFAULT);
g_simple_action_set_state (action, value);
g_settings_set_boolean (self->settings, "dark-mode", dark_mode);
}
def change_color_scheme(self, action, new_state):
dark_mode = new_state.get_boolean()
style_manager = Adw.StyleManager.get_default()
if dark_mode:
style_manager.set_color_scheme(Adw.ColorScheme.FORCE_DARK)
else:
style_manager.set_color_scheme(Adw.ColorScheme.DEFAULT)
action.set_state(new_state)
self.settings.set_boolean("dark-mode", dark_mode)
private void change_color_scheme (Action action, Variant? new_state) {
bool dark_mode = new_state.get_boolean ();
var style_manager = Adw.StyleManager.get_default ();
if (dark_mode)
style_manager.color_scheme = Adw.ColorScheme.FORCE_DARK;
else
style_manager.color_scheme = Adw.ColorScheme.DEFAULT;
action.set_state (new_state);
this.settings.set_boolean ("dark-mode", dark_mode);
}
changeColorScheme(action, newState) {
const isDarkMode = newState.get_boolean();
const styleManager = Adw.StyleManager.get_default();
styleManager.color_scheme = isDarkMode
? Adw.ColorScheme.FORCE_DARK
: Adw.ColorScheme.DEFAULT;
action.set_state (newState);
this._settings.set_boolean("dark-mode", isDarkMode);
}
在本课程中,你学习了如何为你的应用程序强制深色主题,以及将其存储为应用程序首选项。