Archive:Development/Tutorials/Using KConfig XT (zh CN): Difference between revisions
(Created page with '{{Template:I18n/Language Navigation Bar|Development/Tutorials/Using_KConfig_XT}} {{TutorialBrowser (zh_CN)| series=KConfig| pre=[[../KConfig|KConfig入门]]<br>[[../CMake|CMake...') |
No edit summary |
||
Line 8: | Line 8: | ||
next=None| | next=None| | ||
name= | name=使用KConfig XT| | ||
reading=[http://api.kde.org/4.0-api/kdelibs-apidocs/kdecore/html/kconfig_compiler.html | reading=[http://api.kde.org/4.0-api/kdelibs-apidocs/kdecore/html/kconfig_compiler.html KDE配置编译器 (KDE 4)]<br>[http://api.kde.org/3.5-api/kdelibs-apidocs/kdecore/html/kconfig_compiler.html KDE配置编译器 (KDE 3)] | ||
}} | }} | ||
== 使用KConfig XT == | == 使用KConfig XT == | ||
''原作者'': Zack Rusin <[mailto:[email protected] [email protected]]> | |||
本教程介绍了Kconfig XT配置框架的主要概念,并演示了如何在应用程序里快速使用它。本文假设读者已经开发过KDE应用程序,并且熟悉KConfig。同时也要求了解XML及XML Schema的概念。 | 本教程介绍了Kconfig XT配置框架的主要概念,并演示了如何在应用程序里快速使用它。本文假设读者已经开发过KDE应用程序,并且熟悉KConfig。同时也要求了解XML及XML Schema的概念。 | ||
Line 34: | Line 34: | ||
{{path}.kcfg}}文件的结构由它的XML Schema描述(kcfg.xsd - 可从[http://www.kde.org/standards/kcfg/1.0/kcfg.xsd 这里]或者[http://websvn.kde.org/trunk/KDE/kdelibs/kdecore/kconfig_compiler/kcfg.xsd?view=markup kdecore库里]下载)。请在继续阅读本教程之前,略读一遍这个小文件。 | {{path}.kcfg}}文件的结构由它的XML Schema描述(kcfg.xsd - 可从[http://www.kde.org/standards/kcfg/1.0/kcfg.xsd 这里]或者[http://websvn.kde.org/trunk/KDE/kdelibs/kdecore/kconfig_compiler/kcfg.xsd?view=markup kdecore库里]下载)。请在继续阅读本教程之前,略读一遍这个小文件。 | ||
首先让我们来创建一个简单的.kcfg文件,请参看下面这段示例,来学习各个步骤。 | |||
首先让我们来创建一个简单的. | |||
<code xml> | <code xml> | ||
Line 73: | Line 72: | ||
* 使用你最爱的文本编辑器打开 your_application_name{{path|.kcfg}} 文件(记得将your_application_name要替换成实际的应用程序名哦~)。 | * 使用你最爱的文本编辑器打开 your_application_name{{path|.kcfg}} 文件(记得将your_application_name要替换成实际的应用程序名哦~)。 | ||
* 首先给该文件添加<kcfgfile>标签,该标签决定了配置项数据存储于哪个KConfig文件中。这里有三种可能: | * 首先给该文件添加<kcfgfile>标签,该标签决定了配置项数据存储于哪个KConfig文件中。这里有三种可能: | ||
*# 如果& | *# 如果<kcfgfile>标签没有任何属性,那么自动生成的代码将使用程序默认的KConfig文件(通常是{{path|$HOME/.kde/config/<appname>rc}})。 | ||
*# ''使用“name”属性可以手动指定一个文件名。如果“name”的值不是绝对路径,那么文件将在KDE默认配置文件夹中存放(一般是在{{path|$HOME/.kde/config/}})。'' | *# ''使用“name”属性可以手动指定一个文件名。如果“name”的值不是绝对路径,那么文件将在KDE默认配置文件夹中存放(一般是在{{path|$HOME/.kde/config/}})。'' | ||
*# ''如果你希望在程序运行时决定配置文件的路径,那么请使用<kcfgfile arg="true">。这个会让生成的代码里的构造函数使用KSharedConfig::Ptr作为参数,这就允许你能够创建多个实例,指向不同的文件。'' | *# ''如果你希望在程序运行时决定配置文件的路径,那么请使用<kcfgfile arg="true">。这个会让生成的代码里的构造函数使用KSharedConfig::Ptr作为参数,这就允许你能够创建多个实例,指向不同的文件。'' | ||
* ''添加可选的<include>标签,以便代码编译阶段计算默认值时,能够包含指定的C++头文件,'' | * ''添加可选的<include>标签,以便代码编译阶段计算默认值时,能够包含指定的C++头文件,'' | ||
* | * XML文件中的其他<entry>由<group>标签来分组,描述了配置文件中的对应分组。 | ||
*# 每个独立的<entry>至少得有一个name属性或者key属性。key属性用作配置文件中的键名。name属性则用来作为代码中的变量名、标识符等。如果不提供key属性,那么name属性将作为配置文件中的键名;如果提供了key属性,但是不提供name属性,那么会自动将key属性的内容去掉空白符后作为name属性值。 | *# 每个独立的<entry>至少得有一个name属性或者key属性。key属性用作配置文件中的键名。name属性则用来作为代码中的变量名、标识符等。如果不提供key属性,那么name属性将作为配置文件中的键名;如果提供了key属性,但是不提供name属性,那么会自动将key属性的内容去掉空白符后作为name属性值。 | ||
*# 务必添加<label>、<tooltip>和<whatsthis>标签来描述您的应用程序里的配置项。<label>标签是简短的表述,而<tooltip>标签和<whatsthis>标签则是详细的描述与说明。''这些标签很重要,例如系统管理员使用KConfigEditor工具在网络上配置机器时就需要这些描述信息。请注意,如果不再你的.kcfgc文件中配置SetUserTexts=true,那这些选项会被忽略(请查阅下面章节)。'' | *# 务必添加<label>、<tooltip>和<whatsthis>标签来描述您的应用程序里的配置项。<label>标签是简短的表述,而<tooltip>标签和<whatsthis>标签则是详细的描述与说明。''这些标签很重要,例如系统管理员使用KConfigEditor工具在网络上配置机器时就需要这些描述信息。请注意,如果不再你的.kcfgc文件中配置SetUserTexts=true,那这些选项会被忽略(请查阅下面章节)。'' | ||
Line 84: | Line 83: | ||
*#* Enum - 枚举类型。可能的枚举类型要在<choices>标签中提供。应用程序以整数型来访问这些枚举值,但以字符串形式存储到配置文件中。即使以后添加更多的枚举值也不会破坏兼容性。 | *#* Enum - 枚举类型。可能的枚举类型要在<choices>标签中提供。应用程序以整数型来访问这些枚举值,但以字符串形式存储到配置文件中。即使以后添加更多的枚举值也不会破坏兼容性。 | ||
*#* IntList - 整数列表。这将使得提供给应用程序的数据格式是QList<int>。在存储QSplitter的位置时很方便。 | *#* IntList - 整数列表。这将使得提供给应用程序的数据格式是QList<int>。在存储QSplitter的位置时很方便。 | ||
*#* PathList - | *#* PathList - 路径列表。没啥好说的。 | ||
*# min和max属性能够用来限制整数型选项的取值范围。 | *# min和max属性能够用来限制整数型选项的取值范围。 | ||
*# ''每个<entry>还可以有个<default> | *# ''每个<entry>还可以有个<default>标签来指定默认值。当任何配置文件中都没有指定该选项的值时就使用这个默认值。默认值将被解释为字面常量。如果某默认值需要被计算,或者它是某个函数调用的返回值,那<default>标签应该包含一个code="true"属性,这样<default>标签里的内容就会当作C++表达式来处理。'' | ||
*# ''若还需要代码来计算默认值,那可在<code>标签中提供。该标签里的内容将被原样插入到代码中。典型的用途是,计算一个通用的默认值,给接下来的多处<entry>使用。'' | *# ''若还需要代码来计算默认值,那可在<code>标签中提供。该标签里的内容将被原样插入到代码中。典型的用途是,计算一个通用的默认值,给接下来的多处<entry>使用。'' | ||
*# ''还可以,给<entry>标签添加hidden属性。可选的值是true和false。'' | *# ''还可以,给<entry>标签添加hidden属性。可选的值是true和false。'' | ||
Line 94: | Line 93: | ||
创建完一个{{path|.kcfg}}文件后,还需要创建一个{{path|.kcfgc}}文件来描述C++代码的生成细节。.kcfgc文件是一个简单的ini格式文件,使用"entry=value"格式。可以按照以下的步骤来创建一个简单的.kcfgc文件: | 创建完一个{{path|.kcfg}}文件后,还需要创建一个{{path|.kcfgc}}文件来描述C++代码的生成细节。.kcfgc文件是一个简单的ini格式文件,使用"entry=value"格式。可以按照以下的步骤来创建一个简单的.kcfgc文件: | ||
# | # 使用你喜欢的文本编辑器打开一个新文件。 | ||
# 首先添加一行"File=your_application_name.kcfg" | # 首先添加一行"File=your_application_name.kcfg",指定你的应用程序的配置选项的位置。 | ||
# 添加一行"ClassName=YourConfigClassName",指明由.kcfg文件生成的代码的类名。请记住,生成的类将继承于KConfigSkeleton类。也请确保这个YourConfigClassName类名未在您的应用程序里使用。将此文件保存为{{path|yourconfigclassname.kcfgc}}。这将确保yourconfigclassname.{h,cpp} | # 添加一行"ClassName=YourConfigClassName",指明由.kcfg文件生成的代码的类名。请记住,生成的类将继承于KConfigSkeleton类。也请确保这个YourConfigClassName类名未在您的应用程序里使用。将此文件保存为{{path|yourconfigclassname.kcfgc}}。这将确保yourconfigclassname.{h,cpp}的生成,您的配置类也在其中。 | ||
# | # 添加其他可选项。也许您的应用程序会用到。有以下几种: | ||
#* NameSpace - 指定配置类所在的名字空间 | #* NameSpace - 指定配置类所在的名字空间 | ||
#* Inherits - 继承你的自定义类 | #* Inherits - 继承你的自定义类 | ||
#* Singleton - | #* Singleton - 指定您的配置类是否为单例模式 | ||
#* MemberVariables - | #* MemberVariables - 指出成员变量的访问级别。默认是private。 | ||
#* ItemAccessors - 与上面那选项有关。如果成员变量是public,那么生成成员变量的get方法就没啥意义了。默认,生成成员变量的get方法。 | #* ItemAccessors - 与上面那选项有关。如果成员变量是public,那么生成成员变量的get方法就没啥意义了。默认,生成成员变量的get方法。 | ||
#* Mutators - 类似于上面那个,但是变成了是否生成成员变量的set方法。 | #* Mutators - 类似于上面那个,但是变成了是否生成成员变量的set方法。 | ||
#* GlobalEnums - specifies whether enums should be class wide of whether they should be always explicitly prefixed with their type | #* GlobalEnums - specifies whether enums should be class wide of whether they should be always explicitly prefixed with their type name(指明枚举类型是否声明为类,并且明确地以类型名为前缀?) | ||
#* UseEnumTypes - 指明在set方法、get方法、信号函数中,枚举值是以int型来传递,还是以enum xxx枚举型传递。 | #* UseEnumTypes - 指明在set方法、get方法、信号函数中,枚举值是以int型来传递,还是以enum xxx枚举型传递。 | ||
#* SetUserTexts - 指明是否处理<label>、<tooltip>、<whatsthis>等标签。这个选项能让KConfigDialog之类的工具利用这几个标签。默认,这仨标签会被忽略。 | #* SetUserTexts - 指明是否处理<label>、<tooltip>、<whatsthis>等标签。这个选项能让KConfigDialog之类的工具利用这几个标签。默认,这仨标签会被忽略。 | ||
Line 112: | Line 111: | ||
== 调整 CMakeLists.txt 文件 == | == 调整 CMakeLists.txt 文件 == | ||
创建完.kcfg文件和.kcfgc文件后,下一步是调整编译参数,让kconfig_compiler在编译时生成必要的类。对于在源码目录里的编译,调整很少,只需要添加下面这两行代码到CMakeLists.txt中(这里假设你的配置文件叫做settings.kcfg和settings.kcfgc): | |||
kde4_add_kcfg_files(<project name>_SRCS settings.kcfgc) | kde4_add_kcfg_files(<project name>_SRCS settings.kcfgc) | ||
install(FILES settings.kcfg DESTINATION ${KCFG_INSTALL_DIR}) | install(FILES settings.kcfg DESTINATION ${KCFG_INSTALL_DIR}) | ||
另外,如果在编译生成的源代码之前要生成.moc文件,使用下面这两行代码: | |||
kde4_add_kcfg_files(<project name>_SRCS GENERATE_MOC settings.kcfgc) | kde4_add_kcfg_files(<project name>_SRCS GENERATE_MOC settings.kcfgc) | ||
install(FILES settings.kcfg DESTINATION ${KCFG_INSTALL_DIR}) | install(FILES settings.kcfg DESTINATION ${KCFG_INSTALL_DIR}) | ||
以上代码确保了配置类自动生成(kde4_add_kcfg_files),并且.kcfg文件正确地安装以便被KConfigEditor等工具使用(install)。 | |||
=== | === 在源码目录外编译 === | ||
对于在源码目录外编译的情况,需要多一个步骤。 | |||
''' | '''问题:'''对于在源码目录外的编译,kconfig_compiler所生成的代码被保存在了编译目录中。此时,如何在源代码中简单地使用''#include "settings.h"''来包含kconfig_compiler所生成的头文件呢? | ||
''' | '''方案:'''也许你的CMakeLists.txt里有一行下面这样的代码: | ||
include_directories(${QT_INCLUDE} ${KDE4_INCLUDES}) | include_directories(${QT_INCLUDE} ${KDE4_INCLUDES}) | ||
给它加上一个变量''CMAKE_CURRENT_BINARY_DIR'',结果如下: | |||
include_directories(${QT_INCLUDE} ${KDE4_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}) | include_directories(${QT_INCLUDE} ${KDE4_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR}) | ||
需要注意的是,在你的工程中应当只调用一次''include_directories''。(如果你在源码根目录里调用了一次''include_directories'',但是又在其他的子目录(由''add_subdirectory''添加的目录)中调用了一次,那么第二次''include_directories''调用将会被忽略。) | |||
== | == 使用对话框 == | ||
做完以上的步骤之后,你已经为使用KConfig XT框架准备完毕了。kconfig_compiler将生成与.kcfg文件同名的代码文件(后缀替换成".h")。在你需要访问配置项的源代码中''#include''该头文件即可。 | |||
只有在.kcfgc文件中添加了<tt>Singleton=true</tt>,你才能使用本特性。 | |||
KConfig XT的最强之处在于,它与Qt设计器生成的对话框能无缝集成。你可是通过使用{{class|KConfigDialog}}来实现。步骤如下: | |||
# | # 创建KConfigDialog,然后将你的配置数据对象作为参数传递给它。构造函数的调用类似下面的代码: | ||
<code cppqt> | <code cppqt> | ||
Line 159: | Line 154: | ||
</code> | </code> | ||
这里假设YourAppSettings是kcfgc中ClassName变量的值。并且该配置类是单例模式。 | |||
# | # 在Qt设计器中创建widget来配置你的程序选项。为了让这些widget与kcfg集成,你需要按照如下的规则来命名widget里的变量: | ||
## | ## 控制某选项的widget的名字必须以"kcfg_"开头 | ||
## | ## 紧接着是name属性的值。这个name属性是该widget对应的kcfg中的选项的name属性。 | ||
# | # 将该Qt设计器生成的widget添加到KConfigDialog中。 | ||
# | # 搞定后,显示该对话框。 | ||
== | == 示例 == | ||
此处使用KConfig XT框架的例子。应用程序的名字叫做Example。 | |||
它的.kcfg文件如下: | |||
<code xml> | <code xml> | ||
Line 192: | Line 188: | ||
</code> | </code> | ||
然后配置生成的配置类的细节。.kcfgc文件如下: | |||
<code ini> | <code ini> | ||
Line 201: | Line 197: | ||
</code> | </code> | ||
程序源代码的头文件不需要变动,只需要在cpp文件中包含如下的代码来访问和修改配置项数据: | |||
<code cppqt> | <code cppqt> | ||
Line 219: | Line 214: | ||
</code> | </code> | ||
self() | self()返回的是对象的实例。所有的writeConfig()都得这样调用,因为它是一个虚函数方法。(其他的读取和设置选项的方法是静态方法。) | ||
要想增加一个配置对话框,你的Qt设计器生成的widget的名字需要与它们对应的选项的名字相同,并且加上"kcfg_"前缀。例如: | |||
[[Image:kconfigxt.png|center|256px]] | [[Image:kconfigxt.png|center|256px]] | ||
然后你就可以照着下面的代码来使用该配置对话框: | |||
<code cppqt> | <code cppqt> | ||
// | // 你的对话框的实例可能已经创建过并缓存着, | ||
// | // 因此可以直接显示该缓存的对话框, | ||
// | // 而无须又创建一个 | ||
if ( KConfigDialog::showDialog( "settings" ) ) | if ( KConfigDialog::showDialog( "settings" ) ) | ||
return; | return; | ||
// | // KConfigDialog并没有找到对话框的缓存,所有创建新的吧: | ||
KConfigDialog* dialog = new KConfigDialog(this, "settings", | KConfigDialog* dialog = new KConfigDialog(this, "settings", | ||
ExampleSettings::self()); | ExampleSettings::self()); | ||
Line 245: | Line 237: | ||
dialog->addPage( confWdg, i18n("Example"), "example" ); | dialog->addPage( confWdg, i18n("Example"), "example" ); | ||
// | // 用户更改对话框里的配置项,然后你更新本地的配置 | ||
connect( dialog, SIGNAL(settingsChanged()), | connect( dialog, SIGNAL(settingsChanged()), | ||
this, SLOT(updateConfiguration()) ); | this, SLOT(updateConfiguration()) ); | ||
Line 253: | Line 244: | ||
</code> | </code> | ||
这就是全部的内容。你可以查看一下[http://websvn.kde.org/trunk/KDE/kdegames kdegames模块]里面的[http://websvn.kde.org/trunk/KDE/kdegames/kreversi KReversi]和[http://websvn.kde.org/trunk/KDE/kdegames/ktron/ KTron]的源代码,看看KConfig XT的真实的例子! | |||
== | == 常见的陷阱和技巧 == | ||
* | * 别忘了给.kcfg文件里的<entry>标签添加type属性。 | ||
* | * 给所有的<entry>增加<label>、<whatsthis>、<tooltip>等标签。 | ||
* | * 在.kcfgc文件中添加MemberVariables=public通常是脑残的做法。碰到变量的访问竞争时,你就可以去领杯具了。 | ||
* If your application doesn't have one central object (created before and destructed after; all others) then always put the Singleton=true entry in your .kcfgs file. | * If your application doesn't have one central object (created before and destructed after; all others) then always put the Singleton=true entry in your .kcfgs file. | ||
* 如果你的应用程序中没有一个中心对象(在其他对象生成之前生成,其他对象销毁后才销毁),那么请务必给.kcfgs文件添加上''Singleton=true''。 | |||
== | == 其他参考 == |
Revision as of 15:04, 12 December 2010
Development/Tutorials/Using_KConfig_XT
Languages: عربي | Asturianu | Català | Česky | Kaszëbsczi | Dansk | Deutsch | English | Esperanto | Español | Eesti | فارسی | Suomi | Français | Galego | Italiano | 日本語 | 한국어 | Norwegian | Polski | Português Brasileiro | Română | Русский | Svenska | Slovenčina | Slovenščina | српски | Türkçe | Tiếng Việt | Українська | 简体中文 | 繁體中文
Template:TutorialBrowser (zh CN)
使用KConfig XT
原作者: Zack Rusin <[email protected]>
本教程介绍了Kconfig XT配置框架的主要概念,并演示了如何在应用程序里快速使用它。本文假设读者已经开发过KDE应用程序,并且熟悉KConfig。同时也要求了解XML及XML Schema的概念。
KConfig XT框架背后的主要想法是,更方便地管理庞大的KDE安装,让应用程序开发者生活得更惬意。
这个新框架有四个基本部分:
- KConfigSkeleton - libkdecore里的一个类。提供了对配置项的便捷操作
- XML文件,包含了配置项的信息(.kcfg文件)
- 一个ini格式的文件,配置生产代码时的细节(.kcfgc文件)
- kconfig_compiler,从.kcfg和.kcfgc文件中生成C++代码。自动生成的类继承于KConfigSkeleton,并且为应用程序提供了API来访问它的配置项。
.kcfg 结构
{{path}.kcfg}}文件的结构由它的XML Schema描述(kcfg.xsd - 可从这里或者kdecore库里下载)。请在继续阅读本教程之前,略读一遍这个小文件。
首先让我们来创建一个简单的.kcfg文件,请参看下面这段示例,来学习各个步骤。
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name="kjotsrc"/>
<include>kglobalsettings.h</include>
<group name="kjots">
<entry name="SplitterSizes" type="IntList">
<label>How the main window is divided.</label>
</entry>
<entry name="Width" type="Int">
<label>Width of the main window.</label>
<default>600</default>
</entry>
<entry name="Height" type="Int">
<label>Height of the main window.</label>
<default>400</default>
</entry>
<entry name="OpenBooks" type="StringList">
<label>All books that are opened.</label>
</entry>
<entry name="CurrentBook" type="String">
<label>The book currently opened.</label>
</entry>
<entry name="Font" type="Font">
<label>The font used to display the contents of books.</label>
<default code="true">KGlobalSettings::generalFont()</default>
</entry>
</group>
</kcfg>
- 使用你最爱的文本编辑器打开 your_application_name.kcfg 文件(记得将your_application_name要替换成实际的应用程序名哦~)。
- 首先给该文件添加<kcfgfile>标签,该标签决定了配置项数据存储于哪个KConfig文件中。这里有三种可能:
- 如果<kcfgfile>标签没有任何属性,那么自动生成的代码将使用程序默认的KConfig文件(通常是$HOME/.kde/config/<appname>rc)。
- 使用“name”属性可以手动指定一个文件名。如果“name”的值不是绝对路径,那么文件将在KDE默认配置文件夹中存放(一般是在$HOME/.kde/config/)。
- 如果你希望在程序运行时决定配置文件的路径,那么请使用<kcfgfile arg="true">。这个会让生成的代码里的构造函数使用KSharedConfig::Ptr作为参数,这就允许你能够创建多个实例,指向不同的文件。
- 添加可选的<include>标签,以便代码编译阶段计算默认值时,能够包含指定的C++头文件,
- XML文件中的其他<entry>由<group>标签来分组,描述了配置文件中的对应分组。
- 每个独立的<entry>至少得有一个name属性或者key属性。key属性用作配置文件中的键名。name属性则用来作为代码中的变量名、标识符等。如果不提供key属性,那么name属性将作为配置文件中的键名;如果提供了key属性,但是不提供name属性,那么会自动将key属性的内容去掉空白符后作为name属性值。
- 务必添加<label>、<tooltip>和<whatsthis>标签来描述您的应用程序里的配置项。<label>标签是简短的表述,而<tooltip>标签和<whatsthis>标签则是详细的描述与说明。这些标签很重要,例如系统管理员使用KConfigEditor工具在网络上配置机器时就需要这些描述信息。请注意,如果不再你的.kcfgc文件中配置SetUserTexts=true,那这些选项会被忽略(请查阅下面章节)。
- 每个<entry>必须有个类型(type属性)。目前可用的类型有:String, Url, StringList, Font, Rect, Size, Color, Point, Int, UInt, Bool, Double, DataTime, Int64, UInt64,Password。除了这些基本类型以外,以下特殊类型也是支持的:
- Path - 其实还是一个字符串,但是会特别作为文件路径处理而已。对于那些在家目录下的路径,存储到配置文件里时会使用$HOME作为前缀。
- Enum - 枚举类型。可能的枚举类型要在<choices>标签中提供。应用程序以整数型来访问这些枚举值,但以字符串形式存储到配置文件中。即使以后添加更多的枚举值也不会破坏兼容性。
- IntList - 整数列表。这将使得提供给应用程序的数据格式是QList<int>。在存储QSplitter的位置时很方便。
- PathList - 路径列表。没啥好说的。
- min和max属性能够用来限制整数型选项的取值范围。
- 每个<entry>还可以有个<default>标签来指定默认值。当任何配置文件中都没有指定该选项的值时就使用这个默认值。默认值将被解释为字面常量。如果某默认值需要被计算,或者它是某个函数调用的返回值,那<default>标签应该包含一个code="true"属性,这样<default>标签里的内容就会当作C++表达式来处理。
- 若还需要代码来计算默认值,那可在<code>标签中提供。该标签里的内容将被原样插入到代码中。典型的用途是,计算一个通用的默认值,给接下来的多处<entry>使用。
- 还可以,给<entry>标签添加hidden属性。可选的值是true和false。
.kcfgc文件
创建完一个.kcfg文件后,还需要创建一个.kcfgc文件来描述C++代码的生成细节。.kcfgc文件是一个简单的ini格式文件,使用"entry=value"格式。可以按照以下的步骤来创建一个简单的.kcfgc文件:
- 使用你喜欢的文本编辑器打开一个新文件。
- 首先添加一行"File=your_application_name.kcfg",指定你的应用程序的配置选项的位置。
- 添加一行"ClassName=YourConfigClassName",指明由.kcfg文件生成的代码的类名。请记住,生成的类将继承于KConfigSkeleton类。也请确保这个YourConfigClassName类名未在您的应用程序里使用。将此文件保存为yourconfigclassname.kcfgc。这将确保yourconfigclassname.{h,cpp}的生成,您的配置类也在其中。
- 添加其他可选项。也许您的应用程序会用到。有以下几种:
- NameSpace - 指定配置类所在的名字空间
- Inherits - 继承你的自定义类
- Singleton - 指定您的配置类是否为单例模式
- MemberVariables - 指出成员变量的访问级别。默认是private。
- ItemAccessors - 与上面那选项有关。如果成员变量是public,那么生成成员变量的get方法就没啥意义了。默认,生成成员变量的get方法。
- Mutators - 类似于上面那个,但是变成了是否生成成员变量的set方法。
- GlobalEnums - specifies whether enums should be class wide of whether they should be always explicitly prefixed with their type name(指明枚举类型是否声明为类,并且明确地以类型名为前缀?)
- UseEnumTypes - 指明在set方法、get方法、信号函数中,枚举值是以int型来传递,还是以enum xxx枚举型传递。
- SetUserTexts - 指明是否处理<label>、<tooltip>、<whatsthis>等标签。这个选项能让KConfigDialog之类的工具利用这几个标签。默认,这仨标签会被忽略。
更详细的kconfig_compiler说明: [1]
调整 CMakeLists.txt 文件
创建完.kcfg文件和.kcfgc文件后,下一步是调整编译参数,让kconfig_compiler在编译时生成必要的类。对于在源码目录里的编译,调整很少,只需要添加下面这两行代码到CMakeLists.txt中(这里假设你的配置文件叫做settings.kcfg和settings.kcfgc):
kde4_add_kcfg_files(<project name>_SRCS settings.kcfgc) install(FILES settings.kcfg DESTINATION ${KCFG_INSTALL_DIR})
另外,如果在编译生成的源代码之前要生成.moc文件,使用下面这两行代码:
kde4_add_kcfg_files(<project name>_SRCS GENERATE_MOC settings.kcfgc) install(FILES settings.kcfg DESTINATION ${KCFG_INSTALL_DIR})
以上代码确保了配置类自动生成(kde4_add_kcfg_files),并且.kcfg文件正确地安装以便被KConfigEditor等工具使用(install)。
在源码目录外编译
对于在源码目录外编译的情况,需要多一个步骤。
问题:对于在源码目录外的编译,kconfig_compiler所生成的代码被保存在了编译目录中。此时,如何在源代码中简单地使用#include "settings.h"来包含kconfig_compiler所生成的头文件呢?
方案:也许你的CMakeLists.txt里有一行下面这样的代码:
include_directories(${QT_INCLUDE} ${KDE4_INCLUDES})
给它加上一个变量CMAKE_CURRENT_BINARY_DIR,结果如下:
include_directories(${QT_INCLUDE} ${KDE4_INCLUDES} ${CMAKE_CURRENT_BINARY_DIR})
需要注意的是,在你的工程中应当只调用一次include_directories。(如果你在源码根目录里调用了一次include_directories,但是又在其他的子目录(由add_subdirectory添加的目录)中调用了一次,那么第二次include_directories调用将会被忽略。)
使用对话框
做完以上的步骤之后,你已经为使用KConfig XT框架准备完毕了。kconfig_compiler将生成与.kcfg文件同名的代码文件(后缀替换成".h")。在你需要访问配置项的源代码中#include该头文件即可。
只有在.kcfgc文件中添加了Singleton=true,你才能使用本特性。
KConfig XT的最强之处在于,它与Qt设计器生成的对话框能无缝集成。你可是通过使用KConfigDialog来实现。步骤如下:
- 创建KConfigDialog,然后将你的配置数据对象作为参数传递给它。构造函数的调用类似下面的代码:
KConfigDialog* dialog = new KConfigDialog(
this, "settings", YourAppSettings::self() );
这里假设YourAppSettings是kcfgc中ClassName变量的值。并且该配置类是单例模式。
- 在Qt设计器中创建widget来配置你的程序选项。为了让这些widget与kcfg集成,你需要按照如下的规则来命名widget里的变量:
- 控制某选项的widget的名字必须以"kcfg_"开头
- 紧接着是name属性的值。这个name属性是该widget对应的kcfg中的选项的name属性。
- 将该Qt设计器生成的widget添加到KConfigDialog中。
- 搞定后,显示该对话框。
示例
此处使用KConfig XT框架的例子。应用程序的名字叫做Example。
它的.kcfg文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<kcfg xmlns="http://www.kde.org/standards/kcfg/1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.kde.org/standards/kcfg/1.0
http://www.kde.org/standards/kcfg/1.0/kcfg.xsd" >
<kcfgfile name="examplerc"/>
<group name="network">
<entry name="ServerName" type="String">
<label>Defines the sample server.</label>
</entry>
<entry name="Port" type="Int">
<label>Defines the server port</label>
<default>21</default>
<min>20</min>
<max>990</max>
</entry>
</group>
</kcfg>
然后配置生成的配置类的细节。.kcfgc文件如下:
File=example.kcfg
ClassName=ExampleSettings
Singleton=true
Mutators=true
程序源代码的头文件不需要变动,只需要在cpp文件中包含如下的代码来访问和修改配置项数据:
...
- include <ExampleSettings.h>
...
void ExampleClass::readConfig() {
m_server = ExampleSettings::serverName();
m_port = ExampleSettings::port();
}
void ExampleClass::saveSettings() {
ExampleSettings::setServerName( m_server );
ExampleSettings::setPort( m_port );
ExampleSettings::self()->writeConfig();
}
self()返回的是对象的实例。所有的writeConfig()都得这样调用,因为它是一个虚函数方法。(其他的读取和设置选项的方法是静态方法。)
要想增加一个配置对话框,你的Qt设计器生成的widget的名字需要与它们对应的选项的名字相同,并且加上"kcfg_"前缀。例如:
然后你就可以照着下面的代码来使用该配置对话框:
// 你的对话框的实例可能已经创建过并缓存着,
// 因此可以直接显示该缓存的对话框,
// 而无须又创建一个
if ( KConfigDialog::showDialog( "settings" ) )
return;
// KConfigDialog并没有找到对话框的缓存,所有创建新的吧:
KConfigDialog* dialog = new KConfigDialog(this, "settings",
ExampleSettings::self());
ExampleDesignerWidget* confWdg =
new ExampleDesignerWidget( 0, "Example" );
dialog->addPage( confWdg, i18n("Example"), "example" );
// 用户更改对话框里的配置项,然后你更新本地的配置
connect( dialog, SIGNAL(settingsChanged()),
this, SLOT(updateConfiguration()) );
dialog->show();
这就是全部的内容。你可以查看一下kdegames模块里面的KReversi和KTron的源代码,看看KConfig XT的真实的例子!
常见的陷阱和技巧
- 别忘了给.kcfg文件里的<entry>标签添加type属性。
- 给所有的<entry>增加<label>、<whatsthis>、<tooltip>等标签。
- 在.kcfgc文件中添加MemberVariables=public通常是脑残的做法。碰到变量的访问竞争时,你就可以去领杯具了。
- If your application doesn't have one central object (created before and destructed after; all others) then always put the Singleton=true entry in your .kcfgs file.
- 如果你的应用程序中没有一个中心对象(在其他对象生成之前生成,其他对象销毁后才销毁),那么请务必给.kcfgs文件添加上Singleton=true。