用户通常希望应用程序能够记住其跨会话的设置(窗口大小和位置、选项等)。 此信息通常存储在 Windows 上的系统注册表中,以及 macOS 和 iOS 上的属性列表文件中。在 Unix 系统上,由于没有标准,许多应用程序使用 INI 文本文件。
QSettings 是对这些技术的抽象,使用户能够以可移植的方式保存和恢复应用程序设置。它还支持自定义存储格式。
QSettings 的 API 是基于 QVariant 的,可以让用户便捷地保存大多数基于值的类型,例如 QString、QRect 和 QImage。
如果只需要一个非持久的基于内存的结构,请考虑使用 QMap
创建 QSettings 对象时,可传递公司或组织的名称以及应用程序的名称。 例如,如果您的产品名为 Star Runner,而您的公司名为 MySoft,可按如下方式构造 QSettings 对象:
QSettings settings("MySoft", "Star Runner");
构造和销毁 QSettings 对象都非常快。
如果在应用程序的许多地方使用 QSettings,可使用 QCoreApplication::setOrganizationName() 和 QCoreApplication::setApplicationName() 指定组织名称和应用程序名称,然后使用默认的 QSettings 构造函数:
QCoreApplication::setOrganizationName("MySoft");
QCoreApplication::setOrganizationDomain("mysoft.com");
QCoreApplication::setApplicationName("Star Runner");
...
QSettings settings;
QSettings 用来存储设置。每个设置由一个指定设置名称(键)的 QString 和一个存储与键关联的数据的 QVariant 组成。 要编写设置,请使用 setValue()。
如果已存在具有相同键的设置,则现有值将被新值覆盖。 为提高效率,更改可能不会立即保存到永久存储中。(可以调用 sync() 来提交更改)
由于 QVariant 是 Qt Core 模块的一部分,因此它无法提供对 QColor、QImage 和 QPixmap 等数据类型的转换功能,这些都是 Qt GUI 的一部分。 换句话说,QVariant 中没有 toColor()、toImage() 或 toPixmap() 函数。
相反,可以使用 QVariant::value() 模板函数。 例如:
QSettings settings("MySoft", "Star Runner");
QColor color = settings.value("DataPump/bgcolor").value();
对于 QVariant 支持的所有数据类型,包括 GUI 相关类型,逆转换(例如,从 QColor 到 QVariant)是自动的:
QSettings settings("MySoft", "Star Runner");
QColor color = palette().background().color();
settings.setValue("DataPump/bgcolor", color);
可以使用 QSettings 存储使用 qRegisterMetaType() 注册的自定义类型,这些类型具有用于流入和流出 QDataStream 的运算符。
设置键可以包含任何 Unicode 字符。Windows 注册表和 INI 文件使用不区分大小写的键,而 macOS 和 iOS 上的 CFPreferences API 使用区分大小写的键。为避免可移植性问题,请遵循以下规则:
可以使用“/”字符作为分隔符来形成分层键,类似于 Unix 文件路径。 例如:
QSettings settings("program.ini", QSettings::IniFormat);
settings.setValue("mainwindow/size", w.size());
settings.setValue("mainwindow/fullScreen", w.isFullScreen());
settings.setValue("outputpanel/visible", w.isVisible());
如果要保存或恢复许多具有相同前缀的设置,可以使用 beginGroup() 指定前缀并在最后调用 endGroup():
QSettings settings("program.ini", QSettings::IniFormat);
settings.beginGroup("mainwindow");
settings.setValue("size", w.size());
settings.setValue("fullScreen", w.isFullScreen());
settings.endGroup();
settings.beginGroup("outputpanel");
settings.setValue("visible", w.isVisible());
settings.endGroup();
效果同上。
组可以递归设置。
QSettings 通常用于存储 GUI 应用程序的状态。以下示例说明了如何使用 QSettings 来保存和恢复应用程序主窗口的几何图形。
void MainWindow::writeSettings()
{
QSettings settings("Moose Soft", "Clipper");
settings.beginGroup("MainWindow");
settings.setValue("geometry", saveGeometry());
settings.endGroup();
}
void MainWindow::readSettings()
{
QSettings settings("Moose Soft", "Clipper");
settings.beginGroup("MainWindow");
const auto geometry = settings.value("geometry", QByteArray()).toByteArray();
if (geometry.isEmpty())
setGeometry(200, 200, 400, 400);
else
restoreGeometry(geometry)
settings.endGroup();
}
必须从主窗口的构造函数和关闭事件处理程序调用 readSettings() 和 writeSettings() 函数:
MainWindow::MainWindow()
{
...
readSettings();
}
void MainWindow::closeEvent(QCloseEvent *event)
{
if (userReallyWantsToQuit())
{
writeSettings();
event->accept();
}
else
{
event->ignore();
}
}
QSettings 是可重入的。这意味着可以同时在不同线程中使用不同的 QSettings 对象。即使 QSettings 对象引用磁盘上的相同文件(或系统注册表中的相同条目)。如果通过一个 QSettings 对象修改了设置,则更改将立即在任何其他在同一位置运行并存在于同一进程中的 QSettings 对象中可见。
如果满足某些条件,可以安全地从不同进程(可以是同时运行的应用程序的不同实例或完全不同的应用程序)使用 QSettings 来读取和写入相同的系统位置。对于 QSettings::IniFormat,它可确保数据完整性,条件是可写配置文件必须是一个常规文件,并且必须驻留在当前用户可以在其中创建新的临时文件的目录中。
调用 sync() 导入其他进程所做的更改。
假设已经创建了一个 QSettings 对象,其组织名称为 MySoft,应用程序名称为 Star Runner。查找值时,最多会按以下顺序搜索四个位置:
如果在第一个位置找不到值,则在第二个位置继续搜索,依此类推。这使得能够存储系统范围或组织范围的设置,并在每个用户或每个应用程序的基础上覆盖它们。要关闭此机制,请调用 setFallbacksEnabled(false)。
如果文件格式为 QSettings::NativeFormat:
在Unix系统上,默认使用以下文件:
如果未设置 XDG_CONFIG_DIRS,则使用 /etc/xdg 的默认值。
在 macOS 和 iOS 上默认使用以下文件:
在 Windows 上,存储在以下注册表路径中:
注意:在 Windows 上,对于在 WOW64 模式下运行的 32 位程序,存储在以下注册表路径中:HKEY_LOCAL_MACHINE\Software\WOW6432node。
如果文件格式为 QSettings::NativeFormat,则为应用程序主目录中的“Settings/MySoft/Star Runner.conf”。
如果文件格式为 QSettings::IniFormat:
在 Unix、macOS 和 iOS 上使用以下文件:
在 Windows 上,使用以下文件:
以 FOLDERID_ 为前缀的标识符是特殊的项目 ID 列表,需要传递给 Win32 API 函数 SHGetKnownFolderPath() 以获取相应的路径。
FOLDERID_RoamingAppData 通常指向 C:\Users\User Name\AppData\Roaming,也由环境变量 %APPDATA% 显示。
FOLDERID_ProgramData 通常指向 C:\ProgramData。
如果文件格式为 QSettings::IniFormat,则为应用程序主目录中的“Settings/MySoft/Star Runner.ini”。
有时希望访问存储在特定文件或注册表路径中的设置。 在所有平台上,如果要直接读取 INI 文件,可以使用 QSettings 构造函数,该构造函数将文件名作为第一个参数并将 QSettings::IniFormat 作为第二个参数传递。 例如:
QSettings settings("/home/petra/misc/myapp.ini",QSettings::IniFormat);
然后可以使用 QSettings 对象在文件中读取和写入设置。
在 macOS 和 iOS 上,可以将 QSettings::NativeFormat 作为第二个参数传递来访问属性列表 .plist 文件。 例如:
QSettings settings("/Users/petra/misc/myapp.plist",QSettings::NativeFormat);
在 Windows 上,QSettings 允许访问在系统注册表中使用 QSettings 编写的设置(或支持格式的设置,例如字符串数据)。 这是通过在注册表和 QSettings::NativeFormat 中构造一个带有路径的 QSettings 对象来完成的。例如:
QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Office", QSettings::NativeFormat);
出现在指定路径下的所有注册表项都可以通过 QSettings 对象读取或写入(使用正斜杠而不是反斜杠)。 例如:
settings.setValue("11.0/Outlook/Security/DontTrustInstalledFiles", 0);
在 Windows 上,键可以同时具有值和子键。 其默认值通过使用“Default”或“.”访问。 代替子键:
settings.setValue("HKEY_CURRENT_USER\\MySoft\\Star Runner\\Galaxy", "Milkyway");
settings.setValue("HKEY_CURRENT_USER\\MySoft\\Star Runner\\Galaxy\\Sun", "OurStar");
settings.value("HKEY_CURRENT_USER\\MySoft\\Star Runner\\Galaxy\\Default"); // returns "Milkyway"
在 Windows 以外的其他平台上,“Default”和“.” 将被视为常规子键。
1、enum QSettings::Format:此枚举类型指定 QSettings 使用的存储格式。
在 Unix 上,NativeFormat 和 IniFormat 的意思相同,只是文件扩展名不同(NativeFormat 为 .conf,IniFormat 为 .ini)。
INI 文件格式是 Qt 在所有平台上都支持的 Windows 文件格式。 在没有 INI 标准的情况下,将尝试遵循 Microsoft 的做法,但有以下例外:
pos = @Point(100 100)
为了尽量减少兼容性问题,任何没有出现在值的第一个位置或后面没有 Qt 类型(Point、Rect、Size 等)的 @ 都被视为普通字符。
尽管反斜杠是 INI 文件中的特殊字符,但大多数 Windows 应用程序不会对文件路径中的反斜杠 (\) 进行转义:
windir = C:\Windows
QSettings 始终将反斜杠视为特殊字符,并且不提供用于读取或写入此类条目的 API。
QSettings 将假定 INI 文件是 utf-8 编码的。 这意味着键和值将被解码为 utf-8 编码条目并作为 utf-8 写回。
2、enum QSettings::Scope:此枚举指定设置是特定于用户的还是由同一系统的所有用户共享。
3、enum QSettings::Status:状态
1、QSettings(QObject *parent = nullptr)
构造一个 QSettings 对象,用于通过调用 QCoreApplication::setOrganizationName()、QCoreApplication::setOrganizationDomain() 和 QCoreApplication::setApplicationName() 访问先前设置的应用程序和组织的设置。
作用域是 QSettings::UserScope,格式是 defaultFormat()(默认是 QSettings::NativeFormat)。
如果之前没有调用过 QCoreApplication::setOrganizationName() 和 QCoreApplication::setApplicationName(),则 QSettings 对象将无法读取或写入任何设置,并且 status() 将返回 AccessError。
QSettings(const QString &fileName, QSettings::Format 格式, QObject *parent = nullptr)
构造一个 QSettings 对象,用于访问存储在名为 fileName 的文件中的设置。如果该文件尚不存在,则会创建它。
如果 format 为 QSettings::NativeFormat,则 fileName 的含义取决于平台。在 Unix 上,fileName 是 INI 文件的名称。在 macOS 和 iOS 上,fileName 是 .plist 文件的名称。在 Windows 上,fileName 是系统注册表中的路径。
如果 format 是 QSettings::IniFormat,fileName 是 INI 文件的名称。
提供此功能是为了方便。它适用于访问由 Qt 生成的 INI 或 .plist 文件,但在其他程序产生的此类文件中发现的某些语法可能会失败。尤其要注意以下限制:
- QSettings 无法读取 INI“路径”条目,即带有未转义斜杠字符的条目。
- 在 INI 文件中,QSettings 在某些上下文中使用 @ 字符作为元字符来编码 Qt 特定的数据类型(例如 @Rect),因此当它出现在纯 INI 文件中时可能会误解它。
QSettings(QSettings::Format format, QSettings::Scope scope, const QString &organization, const QString &application = QString(), QObject *parent = nullptr)
构造一个 QSettings 对象,用于从名为 organization 的组织中访问名为 application 的应用程序的设置。
如果范围是 QSettings::UserScope,则 QSettings 对象首先搜索特定于用户的设置,然后再搜索系统范围的设置作为后备。如果范围是 QSettings::SystemScope,则 QSettings 对象将忽略特定于用户的设置并提供对系统范围设置的访问。
如果格式为 QSettings::NativeFormat,则使用本机 API 来存储设置。 如果格式为 QSettings::IniFormat,则使用 INI 格式。
如果未给出应用程序名称,则 QSettings 对象将仅访问组织范围的位置。
QSettings(QSettings::Scope scope, const QString &organization, const QString &application = QString(), QObject *parent = nullptr)
构造一个 QSettings 对象,用于从名为 organization 的组织中访问名为 application 的应用程序的设置。
如果范围是 QSettings::UserScope,则 QSettings 对象首先搜索特定于用户的设置,然后再搜索系统范围的设置作为后备。 如果范围是 QSettings::SystemScope,则 QSettings 对象将忽略特定于用户的设置并提供对系统范围设置的访问。
存储格式设置为 QSettings::NativeFormat。
如果未给出应用程序名称,则 QSettings 对象将仅访问组织范围的位置。
QSettings(const QString &organization, const QString &application = QString(), QObject *parent = nullptr)
构造一个 QSettings 对象,用于从名为 organization 的组织中访问名为 application 的应用程序的设置,并具有父级父级。
范围设置为 QSettings::UserScope,格式设置为 QSettings::NativeFormat。
QSettings(QSettings::Scope scope, QObject *parent = nullptr)
2、~QSettings()
任何未保存的更改最终都会写入永久存储。
3、QStringList allKeys()
返回可以使用 QSettings 对象读取的所有键(包括子键)的列表。
QSettings settings;
settings.setValue("fridge/color", QColor(Qt::white));
settings.setValue("fridge/size", QSize(32, 96));
settings.setValue("sofa", true);
settings.setValue("tv", false);
QStringList keys = settings.allKeys();
// keys: ["fridge/color", "fridge/size", "sofa", "tv"]
如果使用 beginGroup() 设置组,则仅返回组中的键,不带组前缀:
settings.beginGroup("fridge");
keys = settings.allKeys();
// keys: ["color", "size"]
4、QString applicationName()
返回用于存储设置的应用程序名称。
QString organizationName()
返回用于存储设置的组织名称。
5、void beginGroup(const QString &prefix)
将前缀附加到当前组。当前组自动添加到指定给 QSettings 的所有键。组可以嵌套。
组有助于避免重复地输入相同的设置路径。 例如:
settings.beginGroup("mainwindow");
settings.setValue("size", win->size());
settings.setValue("fullScreen", win->isFullScreen());
settings.endGroup();
settings.beginGroup("outputpanel");
settings.setValue("visible", panel->isVisible());
settings.endGroup();
这将设置三个设置的值:
mainwindow/size
mainwindow/fullScreen
outputpanel/visible
void endGroup()
调用 endGroup() 将当前组重置为相应的 beginGroup() 调用之前的状态。
QString group()
返回当前组。
6、void beginWriteArray(const QString &prefix, int size = -1)
向当前组添加前缀并开始写入大小为 size 的数组。 如果 size 为 -1,则根据写入的条目的索引自动确定。如果多次出现某组键,则使用数组使更加便捷。
int main(int argc, char *argv[])
{
QSettings settings("program.ini", QSettings::IniFormat);
struct Login
{
Login(QString userName,QString password)
{
this->userName = userName;
this->password = password;
}
QString userName;
QString password;
};
QList list;
list << Login("张三","123") << Login("李四","234") << Login("王五","567");
settings.beginWriteArray("logins");
for (int i = 0; i < list.size(); ++i)
{
settings.setArrayIndex(i);
settings.setValue("userName", list.at(i).userName);
settings.setValue("password", list.at(i).password);
}
settings.endArray();
}
int beginReadArray(const QString &prefix)
向当前组添加前缀并开始从数组中读取。返回数组的大小。
int main(int argc, char *argv[])
{
QSettings settings("program.ini", QSettings::IniFormat);
struct Login
{
Login(QString userName,QString password)
{
this->userName = userName;
this->password = password;
}
QString userName;
QString password;
};
QList list;
int size = settings.beginReadArray("logins");
for (int i = 0; i < size; ++i)
{
settings.setArrayIndex(i);
Login login(settings.value("userName").toString(),settings.value("password").toString());
list.append(login);
}
settings.endArray();
for(const auto &item : list)
qDebug()<
void endArray()
关闭使用 beginReadArray() 或 beginWriteArray() 启动的数组。
void setArrayIndex(int i)
将当前数组索引设置为 i。 对 setValue()、value()、remove() 和 contains() 等函数的调用将对该索引处的数组条目进行操作。
必须先调用 beginReadArray() 或 beginWriteArray() 才能调用此函数。
7、QStringList childGroups()
返回包含可以使用 QSettings 对象读取的键的所有键顶级组的列表。
QSettings settings;
settings.setValue("fridge/color", QColor(Qt::white));
settings.setValue("fridge/size", QSize(32, 96));
settings.setValue("sofa", true);
settings.setValue("tv", false);
QStringList groups = settings.childGroups();
// groups: ["fridge"]
如果使用 beginGroup() 设置组,则返回该组中的第一级键,不带组前缀。
settings.beginGroup("fridge");
groups = settings.childGroups();
// groups: []
可以使用 childKeys() 和 childGroups() 递归浏览整个设置层次结构。
8、QStringList childKeys()
返回可以使用 QSettings 对象读取的所有顶级键的列表。
QSettings settings;
settings.setValue("fridge/color", QColor(Qt::white));
settings.setValue("fridge/size", QSize(32, 96));
settings.setValue("sofa", true);
settings.setValue("tv", false);
QStringList keys = settings.childKeys();
// keys: ["sofa", "tv"]
如果使用 beginGroup() 设置组,则返回该组中的顶级键,不带组前缀:
settings.beginGroup("fridge");
keys = settings.childKeys();
// keys: ["color", "size"]
9、void clear()
删除与此 QSettings 对象关联的主要位置中的所有条目。
10、bool contains(const QString &key)
是否存在名为 key 的设置。如果使用 beginGroup() 设置组,则key被视为相对于该组。
11、【static】QSettings::Format defaultFormat()
返回用于存储 QSettings(QObject *) 构造函数设置的默认文件格式。 如果未设置默认格式,则使用 QSettings::NativeFormat。
12、QString fileName()
返回存储使用此 QSettings 对象写入的设置的路径。
在 Windows 上,如果格式为 QSettings::NativeFormat,则返回值是系统注册表路径。
13、bool isWritable()
是否可以使用此 QSettings 对象写入设置。
此函数可能返回 false 的原因之一是 QSettings 对只读文件进行操作。
警告:此功能并不完全可靠,因为文件权限可以随时更改。
14、【static】QSettings::Format registerFormat(const QString &extension, QSettings::ReadFunc readFunc, QSettings::WriteFunc writeFunc, Qt::CaseSensitivity caseSensitivity = Qt::CaseSensitive)
注册自定义存储格式。成功时,返回一个特殊的 Format 值,然后可以将其传递给 QSettings 构造函数。失败时,返回 InvalidFormat。
extension 是与格式关联的文件扩展名(不带“.”)。
readFunc 和 writeFunc 参数是指向读取和写入一组键/值对的函数的指针。 读取和写入函数的 QIODevice 参数始终以二进制模式打开(即,没有 QIODevice::Text 标志)。
caseSensitivity 参数指定键是否区分大小写。这在使用 QSettings 查找值时会有所不同。默认值区分大小写。
默认情况下,如果使用根据组织名称和应用程序名称工作的构造函数之一,则使用的文件系统位置与 IniFormat 相同。
bool readXmlFile(QIODevice &device, QSettings::SettingsMap &map);
bool writeXmlFile(QIODevice &device, const QSettings::SettingsMap &map);
int main(int argc, char *argv[])
{
const QSettings::Format XmlFormat = QSettings::registerFormat("xml", readXmlFile, writeXmlFile);
QSettings settings(XmlFormat, QSettings::UserScope, "MySoft", "Star Runner");
...
}
15、void remove(const QString &key)
删除设置键和键的任何子设置。
QSettings settings;
settings.setValue("ape");
settings.setValue("monkey", 1);
settings.setValue("monkey/sea", 2);
settings.setValue("monkey/doe", 4);
settings.remove("monkey");
QStringList keys = settings.allKeys();
// keys: ["ape"]
如果 key 为空字符串,则删除当前 group() 中的所有键。 例如:
QSettings settings;
settings.setValue("ape");
settings.setValue("monkey", 1);
settings.setValue("monkey/sea", 2);
settings.setValue("monkey/doe", 4);
settings.beginGroup("monkey");
settings.remove("");
settings.endGroup();
QStringList keys = settings.allKeys();
// keys: ["ape"]
16、void setAtomicSyncRequired(bool enable)
配置是否需要 QSettings 来执行设置的原子保存和重新加载(同步)。
如果为 true(默认值),sync() 将只执行原子同步操作。
如果为 false,sync() 将调用失败并且 status() 将返回一个错误条件。
将此属性设置为 false 将允许 QSettings 直接写入配置文件并忽略任何试图锁定它以防止其他进程同时尝试写入的错误。应谨慎使用此选项,但在某些情况下是必需的,例如存在于其他不可写目录或 NTFS 备用数据流中的 QSettings::IniFormat 配置文件。
bool isAtomicSyncRequired()
如果仅允许 QSettings 执行设置的原子保存和重新加载(同步),则返回 true。
如果允许将设置内容直接保存到配置文件,则返回 false。
17、【static】void setDefaultFormat(QSettings::Format format)
将默认文件格式设置为给定格式,用于存储 QSettings(QObject *) 构造函数的设置。
如果未设置默认格式,则使用 QSettings::NativeFormat。
18、【static】void setPath(QSettings::Format format, QSettings::Scope scope, const QString &path)
设置路径。format 可以是自定义格式。此函数不会影响现有的 QSettings 对象。
下表总结了默认值:
用户可以通过设置 XDG_CONFIG_HOME 环境变量来覆盖 Unix、macOS 和 iOS 上的默认 UserScope 路径($HOME/.config 或 $HOME/Settings)。
在 Windows、macOS 和 iOS 上设置 NativeFormat 路径无效。
19、void setValue(const QString &key, const QVariant &value)
设置键的值。 如果键已存在,则覆盖先前的值。
QSettings settings;
settings.setValue("interval", 30);
settings.value("interval").toInt(); // returns 30
settings.setValue("interval", 6.55);
settings.value("interval").toDouble(); // returns 6.55
20、QSettings::Status status()
返回一个状态代码,指示 QSettings 遇到的第一个错误,如果没有发生错误,则返回 QSettings::NoError。
QSettings 会延迟执行某些操作。出于这个原因,可能需要调用 sync() 以确保在调用 status() 之前将存储在 QSettings 中的数据写入磁盘。
21、void sync()
将任何未保存的更改写入永久存储,并重新加载其他应用程序在此期间更改的任何设置。
此函数会定期从 QSettings 的析构函数和事件循环中自动调用,因此通常无需自己调用它。
22、QVariant value(const QString &key, const QVariant &defaultValue = QVariant())
返回设置键的值。 如果设置不存在,则返回 defaultValue。
如果未指定默认值,则返回默认 QVariant。