GTK开发:如何以编程方式从GSchema枚举获取昵称及对应值
从GSettings读取枚举元数据初始化ComboBoxText
首先修正配置中的命名不一致问题:
你提供的XML中,枚举定义的ID是com.example.unit.temperature,但unit-of-temperature键的enum属性引用的是com.example.corefreqgtk.unit.temperature,两者不匹配会导致GSchema编译失败,需要将两个ID对齐,要么修改枚举定义的ID,要么修改键的enum属性值。
实现原理
不需要手动解析原始XML,也不需要在代码中重复定义枚举的所有取值。GSchema编译为二进制格式后,枚举的所有合法值、nick与数值的映射关系,都会存储在GIO的Schema元数据中,可以直接通过官方提供的API读取,完全避免XML定义和代码硬编码不同步的问题。
核心用到的API逻辑:
- 从默认Schema源中加载对应应用的
GSettingsSchema对象 - 获取目标键的
GSettingsSchemaKey对象 - 调用该对象的
get_range()方法,返回当前键的合法取值范围,对于枚举类型的键,返回值会包含所有[数值, nick]的映射列表
代码示例
Python (PyGObject) 实现
from gi.repository import Gtk, Gio # 初始化ComboBoxText控件 temp_unit_combo = Gtk.ComboBoxText() # 加载对应应用的GSettings Schema元数据 settings_schema = Gio.SettingsSchemaSource.get_default().lookup( "com.example.corefreqgtk", True ) # 获取温度单位键的Schema对象 unit_key = settings_schema.get_key("unit-of-temperature") # 读取键的合法取值范围 range_type, range_data = unit_key.get_range() # 确认当前键为枚举类型 assert range_type == "enum" # 遍历所有枚举项填充ComboBox for value, nick in range_data: temp_unit_combo.append(id=str(value), text=nick) # 绑定当前已存储的配置值 settings = Gio.Settings.new("com.example.corefreqgtk") current_active = settings.get_enum("unit-of-temperature") temp_unit_combo.set_active_id(str(current_active)) # 联动配置,修改下拉选项时自动写入GSettings temp_unit_combo.connect("changed", lambda widget: settings.set_enum( "unit-of-temperature", int(widget.get_active_id()) ))
Vala 实现
// 初始化ComboBoxText控件 var temp_unit_combo = new Gtk.ComboBoxText(); // 加载Schema元数据 var schema_source = Gio.SettingsSchemaSource.get_default(); var settings_schema = schema_source.lookup("com.example.corefreqgtk", true); var unit_key = settings_schema.get_key("unit-of-temperature"); // 读取合法取值范围 string range_type; Variant range_data; unit_key.get_range(out range_type, out range_data); assert(range_type == "enum"); // 遍历填充下拉选项 var enum_entries = range_data.get_child_value(0); for (int i = 0; i < enum_entries.n_children(); i++) { var entry = enum_entries.get_child_value(i); int value = entry.get_child_value(0).get_int32(); string nick = entry.get_child_value(1).get_string(); temp_unit_combo.append(value.to_string(), nick); } // 绑定现有配置值 var settings = new Gio.Settings("com.example.corefreqgtk"); int current_val = settings.get_enum("unit-of-temperature"); temp_unit_combo.set_active_id(current_val.to_string()); // 联动写入配置 temp_unit_combo.changed.connect((widget) => { int active_val = int.parse(widget.active_id); settings.set_enum("unit-of-temperature", active_val); });
注意事项
- 必须先将修改后的GSchema XML通过
glib-compile-schemas命令编译,放到系统或用户本地的Schema存储目录下,否则API无法读取到元数据。 - 后续如果需要新增温度单位,只需要修改XML中的枚举定义、重新编译安装即可,不需要修改业务代码,下拉框会自动加载新的选项。
内容的提问来源于stack exchange,提问作者Roberto Leinardi
相关产品推荐
相关产品推荐

