【Qt】QSettings介紹【轉】

簡介

QSettings類提供了持久的跨平臺應用程序設置。css

用戶一般指望應用程序記住它的設置(窗口大小、位置等)全部會話。這些信息一般存儲在Windows系統註冊表,OS X和iOS的屬性列表文件中。在Unix系統中,在缺少標準的狀況下,許多應用程序(包括KDE應用程序)使用INI文本文件。算法

QSettings圍繞這些抽象技術,使咱們可以以便攜的方式保存和恢復應用程序設置。它還支持自定義存儲格式。windows

QSettings API基於QVariant,能夠保存不少基礎的類型,好比 QString、QRect、QImage等。數組

若是你須要的是一個非持久性的基於內存結構,能夠考慮使用QMap<QString, QVariant>代替。安全

基本用法

當建立一個QSettings對象時,必須經過指定公司或組織名稱以及產品名稱,例如:公司名稱爲:MySoft,產品名爲:Star Runner,那麼能夠用下列方式來構造QSettings對象:markdown

QSettings settings("MySoft", "Star Runner");app

QSettings對象既能夠建立在棧上,也能夠建立在堆(即便用new)上,構建和銷燬也很是快。函數

若是你的應用程序在不少地方使用QSettings,則可使用QCoreApplication::setOrganizationName()QCoreApplication::setApplicationName()來指定組織名和應用名,而後使用默認的QSettings構造函數:ui

QCoreApplication::setOrganizationName("MySoft");
QCoreApplication::setOrganizationDomain("mysoft.com");
QCoreApplication::setApplicationName("Star Runner");
...
QSettings settings;

QSettings能夠存儲一系列設置。每一個設置包括指定設置名稱(鍵)的一個字符串和一個與該鍵關聯的QVariant存儲數據。使用setValue()能夠實現一個設置。例如:spa

settings.setValue("editor/wrapMargin", 68);

若是存在相同的設置鍵,現有的值將被新值覆蓋。爲了提升效率,這些變化可能不會被當即保存到永久存儲(能夠隨時調用sync()來提交更改)。

可使用value()獲得一個設置的值:

int margin = settings.value("editor/wrapMargin").toInt();

若是沒有指定鍵對應的設置,QSettings將會返回一個空QVariant(可轉換爲整數0)。這時,咱們能夠經過另外一個參數來指定默認值:

int margin = settings.value("editor/wrapMargin", 80).toInt();

  • contains() 判斷一個指定的鍵是否存在
  • remove() 刪除相關的鍵
  • allKeys() 獲取全部鍵
  • clear() 刪除全部鍵

void QSettings::beginGroup(const QString & prefix)

爲當前組附加前綴。

當前組會自動追加到指定QSettings全部鍵。此外,查詢功能,如childGroups()、childKeys()、allKeys() 也是基於組的。默認狀況下,不存在組設置。

組是有用的,以免輸入一樣的設置路徑。例如:

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

int QSettings::beginReadArray(const QString & prefix)

爲當前組添加前綴,並開始從數組中讀取。返回數組的大小。
例:

struct Login {
    QString userName;
    QString password;
};
QList<Login> logins;
...

QSettings settings;
int size = settings.beginReadArray("logins");
for (int i = 0; i < size; ++i) {
    settings.setArrayIndex(i);
    Login login;
    login.userName = settings.value("userName").toString();
    login.password = settings.value("password").toString();
    logins.append(login);
}
settings.endArray();

void QSettings::beginWriteArray(const QString & prefix, int size = -1)

爲當前組添加前綴,並開始寫大小爲size的數組。若是大小爲-1(默認值),系統會自動根據索引的數目肯定。

若是有許多出現必定的鍵集,可使用數組實現更容易。例如,假設想要保存的用戶名和密碼的長度可變的列表。而後,你能夠寫:

struct Login {
    QString userName;
    QString password;
};
QList<Login> logins;
...

QSettings settings;
settings.beginWriteArray("logins");
for (int i = 0; i < logins.size(); ++i) {
    settings.setArrayIndex(i);
    settings.setValue("userName", list.at(i).userName);
    settings.setValue("password", list.at(i).password);
}
settings.endArray();

生成的結果以下:

  • logins/size
  • logins/1/userName
  • logins/1/password
  • logins/2/userName
  • logins/2/password
  • logins/3/userName
  • logins/3/password

enum QSettings::Format

這個枚舉類型指定QSettings所使用的存儲格式。

常量 描述
QSettings::NativeFormat 0 使用平臺最合適的存儲格式設置。在Windows中,使用系統註冊表;OS X和iOS中,使用的是CFPreferences API;在Unix中,使用的是INI格式的文本配置文件。
QSettings::IniFormat 1 存儲在INI文件中的設置。
QSettings::InvalidFormat 16 registerFormat()返回的值

Unix中,NativeFor​​mat和IniFormat意思是同樣的,只是文件擴展名不一樣(NativeFor​​mat爲.conf,IniFormat 爲.ini)。

enum QSettings::Scope

該枚舉指定設置是否用戶特定或同一系統的全部用戶共享。

常量 描述
QSettings::UserScope 0 在一個位置存儲特定於當前用戶的設置(例如,用戶的主目錄)。
QSettings::SystemScope 1 在一個全局位置存儲設置,以便在相同機器上全部用戶訪問同一組的設置。

void QSettings::setPath(Format format, Scope scope, const QString & path)

爲給定格式和範圍設置用來存儲的路徑。對於路徑而言,該格式能夠是自定義格式。

下表總結了默認值:

平臺 格式 範圍 路徑
Windows IniFormat 1.UserScope 2.SystemScope 1.%APPDATA% 2.%COMMON_APPDATA%
Unix NativeFormat, IniFormat 1.UserScope 2.SystemScope 1.$HOME/.config 2./etc/xdg
Qt for Embedded Linux NativeFormat, IniFormat 1.UserScope 2.SystemScope 1.$HOME/Settings 2./etc/xdg
OS X and iOS IniFormat 1.UserScope 2.SystemScope 1.$HOME/.config 2./etc/xdg

在Windows、OS X、iOS中設置NativeFormat沒有任何效果。

警告:此功能不會影響現有QSettings對象。

QVariant和GUI類型

由於QVariant是Qt Core模塊的一部分,它不能提供轉換功能到數據類型-例如:QColor、QImage、 QPixmap,由於這是Qt GUI的一部分。換句話說,QVariant中沒有toColor()、toImage()、toPixmap()等接口。

相反,可使用QVariant::value()或qVariantValue()模板函數。 例如:

QSettings settings("MySoft", "Star Runner");
QColor color = settings.value("DataPump/bgcolor").value<QColor>();

逆轉換(例如,從QColor到QVariant)是自動經過QVariant支持的全部數據類型,包括GUI相關類型:

QSettings settings("MySoft", "Star Runner");
QColor color = palette().background().color();
settings.setValue("DataPump/bgcolor", color);

自定義類型註冊使用qRegisterMetaType()qRegisterMetaTypeStreamOperators()可使用QSettings存儲。

重點說明

設置中的鍵能夠包含任何Unicode字符。Windows註冊表和INI文件使用對鍵不區分大小寫,而在OS X和iOS的CFPreferences API使用區分大小寫。爲了不可移植性問題,須要遵循這些簡單的規則:

  1. 在相同狀況下使用相同的鍵。例如:代碼中的一個位置使用」text fonts」,不要在別的地方使用」Text Fonts」。
  2. 避免鍵名相同除了這種狀況,例如:有一個名爲」MainWindow」的鍵,不要試圖用」mainwindow」保存另外一個鍵。
  3. 不要使用斜線(’/’和’\’)做爲鍵名,反斜槓字符用於分隔子鍵(見下文)。在Windows中,’\’被QSettings轉換爲’/’,這使得它們相同。

可使用’ / ‘字符做爲分隔符造成分層鍵,相似於Unix文件路徑。例如:

settings.setValue("mainwindow/size", win->size());
settings.setValue("mainwindow/fullScreen", win->isFullScreen());
settings.setValue("outputpanel/visible", panel->isVisible());

若是想保存或恢復具備相同前綴的一些設置,可使用beginGroup()來指前綴,結束時調用endGroup()。下面和上面的例子相同,但這時使用組機制:

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();

若是一個組使用beginGroup()設置,大多數功能的行爲變化,組能夠遞歸地設置。

後備機制

假設你用組織名MySoft、應用名Star Runner建立了一個QSettings對象,當查看一個值時,依次搜索四個地方:

  1. 一個供Star Runner應用程序的用戶特定位置
  2. 一個供MySoft全部應用程序的用戶特定位置
  3. 一個供Star Runner應用程序的系統範圍位置
  4. 一個供MySoft全部應用程序的系統範圍位置

若是一個鍵不能在第一位置被找到時,繼續在第二的位置搜索,依此類推。這確保可以存儲系統範圍或組織範圍內的設置,並在每一個用戶或每一個應用程序覆蓋它們,使用setFallbacksEnabled(false)能夠關閉這一機制。

雖然能夠讀取來自全部四個位置的鍵,僅第一個文件(用戶特定的應用程序)用於寫入訪問。要寫入任何其餘文件,省去了程序名和指定QSettings:: SystemScope(相對於QSettings:: UserScope,默認值)。

用一個例子看看:

QSettings obj1("MySoft", "Star Runner");
QSettings obj2("MySoft");
QSettings obj3(QSettings::SystemScope, "MySoft", "Star Runner");
QSettings obj4(QSettings::SystemScope, "MySoft");

下表總結了QSettings對象訪問的位置。」X」表示該位置相關聯的QSettings對象的主要位置,既能夠讀取也能夠寫入,」O」是指讀操做時被佔用當作後備。

Locations obj1 obj2 obj3 obj4
User, Application X      
User, Organization o X    
System, Application o   X  
System, Organization o o o X

這種機制的優勢在於它能夠在Qt支持的全部平臺運行,它仍然給咱們一個很大的靈活性,無需指定任何文件名或註冊表路徑。

若是想在全部平臺上不使用原生API來使用 INI文件,能夠經過 QSettings::IniFormat格式做爲QSettings構造函數的第一個參數,其次是範圍,組織名,以及應用名:

QSettings settings(QSettings::IniFormat, QSettings::UserScope, "MySoft", "Star Runner");

能夠參考:Settings Editor例子(能夠體驗不一樣的設置-回退、打開、關閉)。

存儲GUI程序狀態

QSettings一般用於存儲GUI程序的狀態。下面的例子演示瞭如何使用QSettings保存和恢復應用程序的主窗口的幾何形狀。

void MainWindow::writeSettings()
{
    QSettings settings("Moose Soft", "Clipper");

    settings.beginGroup("MainWindow");
    settings.setValue("size", size());
    settings.setValue("pos", pos());
    settings.endGroup();
}

void MainWindow::readSettings()
{
    QSettings settings("Moose Soft", "Clipper");

    settings.beginGroup("MainWindow");
    resize(settings.value("size", QSize(400, 400)).toSize());
    move(settings.value("pos", QPoint(200, 200)).toPoint());
    settings.endGroup();
}

能夠參考: Window Geometry。爲何調用QWidget::resize()和QWidget::move()更好,而不是QWidget::setGeometry()來恢復窗口的幾何形狀。

必須在MainWindow構造函數和關閉事件處理程序中調用readSettings()和writeSettings()函數,以下:

MainWindow::MainWindow()
{
    ...
    readSettings();
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if (userReallyWantsToQuit()) {
        writeSettings();
        event->accept();
    } else {
        event->ignore();
    }
}

能夠參考自帶的Application程序示例使用QSettings例子。

同時從多個線程或進程訪問QSettings

QSettings是可重入的,意味着能夠同時在不一樣的線程中使用不一樣的QSettings對象,這保證QSettings對象操做同一磁盤上的文件(或在系統註冊表中的相同條目)。若是經過QSettings對象修改了一個設置,那麼對於操做在同一位置和存在相同的進程的其餘QSettings對象來講,更改會當即可見。

QSettings能夠由不一樣的進程(其能夠是應用程序同時運行的不一樣實例或徹底不一樣的應用程序)安全地使用-在相同的系統位置上進行讀寫,它使用勸告式文件鎖和智能合併算法以確保數據的完整性,須要注意的是sync()由其餘進程所作的更改。

特定平臺

應用程序設置的存儲位置

如上所提到的,在後背機制部分,QSettings爲應用程序存儲的設置多達四個位置,這取決於設置是不是特定於用戶或系統範圍的,設置是否特定於應用或組織範圍的。爲簡單起見,咱們假設該組織被稱爲MySoft而且應用程序被稱爲Star Runner。

在Unix系統中,若是文件格式是NativeFormat,默認使用如下文件:

  1. $HOME/.config/MySoft/Star Runner.conf (Qt for Embedded Linux: $HOME/Settings/MySoft/Star Runner.conf)
  2. $HOME/.config/MySoft.conf (Qt for Embedded Linux: $HOME/Settings/MySoft.conf)
  3. /etc/xdg/MySoft/Star Runner.conf
  4. /etc/xdg/MySoft.conf

在Mac OS X版本10.2和10.3中,這些文件所使用的默認值:

  1. $HOME/Library/Preferences/com.MySoft.Star Runner.plist
  2. $HOME/Library/Preferences/com.MySoft.plist
  3. /Library/Preferences/com.MySoft.Star Runner.plist
  4. /Library/Preferences/com.MySoft.plist

在Windows上,NativeFormat設置存儲在註冊表路徑以下:

  1. HKEY_CURRENT_USER\Software\MySoft\Star Runner
  2. HKEY_CURRENT_USER\Software\MySoft\OrganizationDefaults
  3. HKEY_LOCAL_MACHINE\Software\MySoft\Star Runner
  4. HKEY_LOCAL_MACHINE\Software\MySoft\OrganizationDefaults

若是文件格式是IniFormat,,如下文件用於在Unix、Mac OS X,、和iOS:

  1. $HOME/.config/MySoft/Star Runner.ini (Qt for Embedded Linux: $HOME/Settings/MySoft/Star Runner.ini)
  2. $HOME/.config/MySoft.ini (Qt for Embedded Linux: $HOME/Settings/MySoft.ini)
  3. /etc/xdg/MySoft/Star Runner.ini
  4. /etc/xdg/MySoft.ini

在Windows中,使用如下文件:

  1. %APPDATA%\MySoft\Star Runner.ini
  2. %APPDATA%\MySoft.ini
  3. %COMMON_APPDATA%\MySoft\Star Runner.ini
  4. %COMMON_APPDATA%\MySoft.ini

%APPDATA%路徑一般爲:C:\Documents and Settings\All Users\Application Data
%COMMONAPPDATA%路徑一般爲:C:\Documents and Settings\All Users\Application Data

在黑莓手機只有一個文件。若是文件格式是IniFormat,這時」Settings/MySoft/Star Runner.ini」在應用程序的主目錄。

對於在.ini和conf文件的路徑,可使用的setPath()來改變。在Unix、Mac OS X、iOS中,用戶能夠經過設置XDG_CONFIG_HOME環境變量替代他們。

訪問INI和.plist文件

有時候,想在一個特定的文件或註冊表路徑中訪問存儲設置。在全部平臺上,若是想直接讀取INI文件,可使QSettings構造函數的第一個參數爲文件名,第二個參數爲QSettings::IniFormat。例如:

QSettings settings("/home/petra/misc/myapp.ini", QSettings::IniFormat);

而後,就能夠對文件進行讀寫設置。
在OS X和iOS中,能夠經過指定第二個參數爲QSettings::NativeFormat訪問屬性列表的.plist文件。例如:

QSettings settings("/Users/petra/misc/myapp.plist", QSettings::NativeFormat);

訪問Windows註冊表

在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);

注意,反斜線字符,如前所述,使用QSettings分割爲子項。這樣一來,不能讀寫包含斜線或反斜線Windows註冊表項,若是須要的話,應該使用Windows API。

訪問Windows上常見的註冊表設置

在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"

平臺限制

儘管QSettings試圖支持​​不一樣平臺,但還存在着一些差別,咱們應該知道,當移植應用程序:

Windows系統註冊表有如下限制:一個子項不能超過255個字符,一個條目的值不得超過16,383個字符,一個鍵的全部值不得超過65,535個字符。要解決這些侷限性的一種方法是使用IniFormat代替NativeFor​​mat存儲設置。

在OS X和iOS中,allKeys()將返回適用於全部應用程序的全局設置一些額外的鍵。這些鍵可使用value()讀取,但不能改變,只能跟蹤。調用setFallbacksEnabled(false) 將隱藏這些全局設置。

在OS X和iOS,使用QSettings的CFPreferences API預計互聯網域名而不是組織名。爲了提供一個統一的API,QSettings源於該組織名提供一個假域​​名(除非組織名已是一個域名,如:OpenOffice.org)。該算法追加」.com」到公司名,並用連字符替換空格和其餘非法字符。若是你想指定不一樣的域名,在main()函數中調用QCoreApplication::setOrganizationDomain()、QCoreApplication::setOrganizationName()、QCoreApplication::setApplicationName(),而後使用默認的QSettings構造函數。
另外一種解決方案是使用預處理指令,例如:

#ifdef Q_OS_MAC
    QSettings settings("grenoullelogique.fr", "Squash");
#else
    QSettings settings("Grenoulle Logique", "Squash");
#endif



原文做者:一去丶二三裏
做者博客:去做者博客空間
相關文章
相關標籤/搜索