Qt QSettings::group()徹底解説:設定管理の基本から応用まで

2025-05-27

QSettings クラスは、アプリケーションの設定を永続的に保存および復元するための便利な方法を提供します。設定は、INI ファイル、macOS のプロパティリスト、Windows のレジストリなど、プラットフォームネイティブな形式で保存されます。

QSettings では、設定を階層的に管理するために「グループ (group)」という概念を使用します。これは、INI ファイルのセクションやレジストリのキーに相当します。

QSettings::group() メソッドは、現在のグループのパス(プレフィックス)を返します。

詳細

QSettings オブジェクトを作成した後、通常はルート(最上位)のグループにいます。 beginGroup() メソッドを使って特定のグループに入ると、その後の setValue()value() などの操作は、そのグループのパスを基準に行われます。



QSettings::group() 自体がエラーを発生させることはほとんどありませんが、beginGroup()endGroup() と組み合わせたグループ操作で予期せぬ動作や設定の保存・読み込みに関する問題が発生することがあります。

グループのネスト(入れ子)の誤り

問題
beginGroup()endGroup() のペアが正しく対応していない場合、意図しないグループパスで設定が保存・読み込みされたり、プログラムがクラッシュしたりする可能性があります。

よくある間違い

  • 条件分岐やループの中で beginGroup()/endGroup() を使用し、ロジックのフローによってペアが崩れる。
  • endGroup()beginGroup() よりも多く呼び出す(空のグループから出ようとする)。
  • beginGroup() を呼び出したのに、対応する endGroup() を呼び忘れる。

症状

  • デバッグ出力で settings.group() を確認すると、意図しないパスが表示される。
  • QSettings の操作中にクラッシュ(特に endGroup() を過剰に呼び出した場合)。
  • 設定値が期待するキーパスに保存されていない(例: key ではなく groupname/key に保存されるべきが groupname/anothergroup/key に保存される)。

トラブルシューティング

  • RAII スタイルでの管理
    より堅牢な方法として、カスタムのヘルパークラス(RAII - Resource Acquisition Is Initialization)を作成し、コンストラクタで beginGroup()、デストラクタで endGroup() を呼び出すことで、グループの管理を自動化できます。

    // 簡単な例: グループを自動管理するヘルパークラス
    class SettingsGroupGuard {
    public:
        SettingsGroupGuard(QSettings& settings, const QString& groupName)
            : m_settings(settings)
        {
            m_settings.beginGroup(groupName);
            qDebug() << "Entered group:" << m_settings.group();
        }
    
        ~SettingsGroupGuard() {
            qDebug() << "Exiting group:" << m_settings.group();
            m_settings.endGroup();
        }
    private:
        QSettings& m_settings;
    };
    
    // 使用例
    void myFunction(QSettings& settings) {
        SettingsGroupGuard guard(settings, "myFunctionSettings");
        settings.setValue("data", 123);
        // 関数が終了すると、デストラクタが呼ばれて自動的に endGroup() が実行される
    }
    
  • デバッグ出力の活用
    beginGroup()endGroup() を呼び出すたびに qDebug() << settings.group(); を挿入し、実行時のグループパスがどのように変化するかを追跡します。これにより、いつパスが予期せず変わるかを発見できます。

  • ペアリングの確認
    beginGroup()endGroup() は必ずペアで使用されていることを確認します。関数やブロックの終わりで endGroup() を呼び出すのを忘れていないかチェックします。

グループパスの衝突(意図しない上書き)

問題
複数の場所で同じグループ名を使用している場合、または異なる機能が同じグループ名の下に設定を保存しようとする場合、意図せず設定が上書きされる可能性があります。

症状

  • アプリケーションを再起動すると、一部の設定が以前の状態に戻ってしまう。
  • ある設定値を保存したはずが、別の場所で保存された値によって上書きされてしまう。

トラブルシューティング

  • デバッグ出力と設定ファイルの内容確認
    • qDebug() << settings.group(); を頻繁に利用して、設定保存時にどのグループにいるかを確認します。
    • 保存された設定ファイル(INIファイル、レジストリ、plistなど)を直接開いて内容を確認します。これにより、実際にどのパスにどのような値が保存されているかを把握できます。
  • アプリケーション構造の検討
    アプリケーションの全体的な設定構造を設計し、どの情報がどのグループに属すべきかを明確にします。
  • 一意なグループ名の使用
    可能であれば、グループ名に衝突がないよう、機能やモジュールごとに明確に区別できる名前を使用します。

グループ名の誤字脱字

問題
beginGroup()value()/setValue() を使う際に、グループ名やキー名に誤字脱字があると、設定が正しく読み書きされません。

症状

  • setValue() で設定を保存しても、アプリケーションを再起動するとその設定が反映されていない。
  • value() で設定を読み込もうとしても、デフォルト値が返されるか、古い値が返される。

トラブルシューティング

  • 定数化
    グループ名やキー名は、マジックストリング(直接書き込まれた文字列リテラル)ではなく、定数(const QStringenum)として定義し、それを使用するようにします。これにより、タイプミスを防ぎ、変更が一箇所で済みます。

    // 悪い例: マジックストリング
    settings.beginGroup("UserSettings");
    settings.setValue("Language", "en");
    settings.endGroup();
    
    // 良い例: 定数を使用
    namespace SettingsKeys {
        const QString UserGroup = "UserSettings";
        const QString Language = "Language";
    }
    
    settings.beginGroup(SettingsKeys::UserGroup);
    settings.setValue(SettingsKeys::Language, "en");
    settings.endGroup();
    
  • 文字列の確認
    グループ名やキー名の文字列が正確に一致しているか(大文字・小文字、スペルなど)を注意深く確認します。

QSettings の初期化とスコープの問題

問題
QSettings オブジェクトが適切に初期化されていないか、またはそのスコープが短すぎる場合、設定が期待通りに保存・読み込みされないことがあります。

症状

  • アプリケーション終了時に設定が保存されない。
  • アプリケーション起動時に設定が読み込まれない。

トラブルシューティング

  • オブジェクトの寿命
    QSettings オブジェクトは、設定を操作する必要がある間は有効である必要があります。特に、アプリケーション終了時に設定を書き込みたい場合は、アプリケーションのライフサイクル全体を通じて利用できるスコープ(例: メインウィンドウクラスのメンバ変数、シングルトンなど)に配置されていることを確認します。
  • コンストラクタの確認
    QCoreApplication::setOrganizationName()QCoreApplication::setApplicationName() を、QSettings オブジェクトを作成する前に呼び出しているか確認します。これは、設定ファイルのパス決定に影響します。

設定ファイルへのアクセス権限の問題

問題
稀に、アプリケーションが設定ファイルを保存または読み込むディレクトリへの書き込み/読み取り権限を持っていない場合があります。

症状

  • 設定が読み込めない。
  • 設定が保存できない(特に初回起動時)。

トラブルシューティング

  • 管理者権限での実行
    デバッグのために、アプリケーションを管理者権限で実行してみて、問題が解決するかどうか確認します。
  • 手動での権限確認
    そのディレクトリへの書き込み権限があるか手動で確認します。
  • 設定ファイルの場所の確認
    • QSettings::fileName() を使用して、設定ファイルがどこに保存されようとしているかを確認します。
    • Windows: C:\Users\YourUser\AppData\Roaming\YourCompany\YourApp.ini
    • macOS: ~/Library/Preferences/com.YourCompany.YourApp.plist
    • Linux: ~/.config/YourCompany/YourApp.conf または ~/.local/share/data/YourCompany/YourApp.conf


例1: 基本的なグループの保存と読み込み

この例では、メインウィンドウの位置とサイズ、およびアプリケーションの言語設定を保存・読み込みします。

#include <QCoreApplication>
#include <QSettings>
#include <QDebug>
#include <QSize>
#include <QPoint>

// 設定を保存する関数
void saveSettings() {
    // 組織名とアプリケーション名を設定
    QCoreApplication::setOrganizationName("MyCompany");
    QCoreApplication::setApplicationName("MyApp");

    QSettings settings; // QSettings オブジェクトを作成

    // メインウィンドウの設定を保存
    settings.beginGroup("MainWindow");
    settings.setValue("pos", QPoint(100, 100)); // 位置
    settings.setValue("size", QSize(800, 600)); // サイズ
    settings.setValue("fullScreen", false); // フルスクリーンモード
    qDebug() << "設定保存中 - 現在のグループ:" << settings.group(); // "MainWindow"
    settings.endGroup(); // "MainWindow" グループを終了

    // アプリケーションの言語設定を保存
    settings.beginGroup("Application");
    settings.setValue("language", "ja_JP"); // 日本語
    qDebug() << "設定保存中 - 現在のグループ:" << settings.group(); // "Application"
    settings.endGroup(); // "Application" グループを終了

    qDebug() << "設定を保存しました。";
}

// 設定を読み込む関数
void loadSettings() {
    // 組織名とアプリケーション名を設定
    QCoreApplication::setOrganizationName("MyCompany");
    QCoreApplication::setApplicationName("MyApp");

    QSettings settings; // QSettings オブジェクトを作成

    // メインウィンドウの設定を読み込む
    settings.beginGroup("MainWindow");
    QPoint pos = settings.value("pos", QPoint(50, 50)).toPoint();
    QSize size = settings.value("size", QSize(640, 480)).toSize();
    bool fullScreen = settings.value("fullScreen", false).toBool();
    qDebug() << "設定読み込み中 - 現在のグループ:" << settings.group(); // "MainWindow"
    qDebug() << "MainWindow: pos =" << pos << ", size =" << size << ", fullScreen =" << fullScreen;
    settings.endGroup(); // "MainWindow" グループを終了

    // アプリケーションの言語設定を読み込む
    settings.beginGroup("Application");
    QString language = settings.value("language", "en_US").toString();
    qDebug() << "設定読み込み中 - 現在のグループ:" << settings.group(); // "Application"
    qDebug() << "Application: language =" << language;
    settings.endGroup(); // "Application" グループを終了

    qDebug() << "設定を読み込みました。";
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 設定を保存
    saveSettings();

    // 設定を読み込み
    loadSettings();

    // QSettings::group() の現在のパスを確認
    QSettings currentSettings;
    qDebug() << "メイン関数終了時 - 現在の QSettings グループ:" << currentSettings.group(); // 空文字列 ("")

    return 0;
}

出力例

設定保存中 - 現在のグループ: "MainWindow"
設定保存中 - 現在のグループ: "Application"
設定を保存しました。
設定読み込み中 - 現在のグループ: "MainWindow"
MainWindow: pos = QPoint(100,100) , size = QSize(800, 600) , fullScreen = false
設定読み込み中 - 現在のグループ: "Application"
Application: language = "ja_JP"
設定を読み込みました。
メイン関数終了時 - 現在の QSettings グループ: ""

解説

  • main 関数終了時の currentSettings.group() は空文字列になります。これは、beginGroup() が呼ばれていないため、ルートグループにいることを示します。
  • settings.endGroup(); は、直前の beginGroup() で入ったグループから抜けます。
  • settings.group() は、現在アクティブなグループのパスを返します。例えば、MainWindow グループに入ると "MainWindow" が返されます。さらにネストすると、"MainWindow/SubSection" のようにパスが連結されます。
  • settings.beginGroup("グループ名"); を呼び出すと、それ以降の setValue()value() の操作は、そのグループの内部で行われます。
  • QSettings settings; でオブジェクトを作成します。デフォルトでは、上記の組織名とアプリケーション名に基づいて、プラットフォームネイティブな形式で設定が保存されます。
  • QCoreApplication::setOrganizationName()QCoreApplication::setApplicationName() は、設定が保存される場所(Windows のレジストリパスや Linux/macOS の設定ファイルパス)を決定するために重要です。

例2: ネストされたグループ(入れ子構造)

複数の階層にわたる設定を保存・読み込みする例です。

#include <QCoreApplication>
#include <QSettings>
#include <QDebug>

void saveNestedSettings() {
    QCoreApplication::setOrganizationName("MyCompany");
    QCoreApplication::setApplicationName("MyApp");
    QSettings settings;

    qDebug() << "保存開始時のグループ:" << settings.group(); // ""

    settings.beginGroup("UserPreferences");
    qDebug() << "グループに入った直後:" << settings.group(); // "UserPreferences"
    settings.setValue("username", "john_doe");

    settings.beginGroup("Theme");
    qDebug() << "さらにグループに入った直後:" << settings.group(); // "UserPreferences/Theme"
    settings.setValue("colorScheme", "Dark");
    settings.setValue("fontSize", 12);
    settings.endGroup(); // "UserPreferences/Theme" から出る
    qDebug() << "グループを一つ出た後:" << settings.group(); // "UserPreferences"

    settings.beginGroup("Network");
    qDebug() << "別のグループに入った直後:" << settings.group(); // "UserPreferences/Network"
    settings.setValue("proxyEnabled", true);
    settings.setValue("proxyAddress", "192.168.1.1:8080");
    settings.endGroup(); // "UserPreferences/Network" から出る
    qDebug() << "グループを一つ出た後:" << settings.group(); // "UserPreferences"

    settings.endGroup(); // "UserPreferences" から出る
    qDebug() << "すべてのグループから出た後:" << settings.group(); // ""

    qDebug() << "ネストされた設定を保存しました。";
}

void loadNestedSettings() {
    QCoreApplication::setOrganizationName("MyCompany");
    QCoreApplication::setApplicationName("MyApp");
    QSettings settings;

    qDebug() << "読み込み開始時のグループ:" << settings.group(); // ""

    settings.beginGroup("UserPreferences");
    qDebug() << "グループに入った直後:" << settings.group(); // "UserPreferences"
    QString username = settings.value("username", "guest").toString();
    qDebug() << "Username:" << username;

    settings.beginGroup("Theme");
    qDebug() << "さらにグループに入った直後:" << settings.group(); // "UserPreferences/Theme"
    QString colorScheme = settings.value("colorScheme", "Light").toString();
    int fontSize = settings.value("fontSize", 10).toInt();
    qDebug() << "Theme: colorScheme =" << colorScheme << ", fontSize =" << fontSize;
    settings.endGroup();
    qDebug() << "グループを一つ出た後:" << settings.group(); // "UserPreferences"

    settings.beginGroup("Network");
    qDebug() << "別のグループに入った直後:" << settings.group(); // "UserPreferences/Network"
    bool proxyEnabled = settings.value("proxyEnabled", false).toBool();
    QString proxyAddress = settings.value("proxyAddress", "").toString();
    qDebug() << "Network: proxyEnabled =" << proxyEnabled << ", proxyAddress =" << proxyAddress;
    settings.endGroup();
    qDebug() << "グループを一つ出た後:" << settings.group(); // "UserPreferences"

    settings.endGroup();
    qDebug() << "すべてのグループから出た後:" << settings.group(); // ""

    qDebug() << "ネストされた設定を読み込みました。";
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    saveNestedSettings();
    qDebug() << "\n--- 読み込み ---";
    loadNestedSettings();

    return 0;
}

出力例

保存開始時のグループ: ""
グループに入った直後: "UserPreferences"
さらにグループに入った直後: "UserPreferences/Theme"
グループを一つ出た後: "UserPreferences"
別のグループに入った直後: "UserPreferences/Network"
グループを一つ出た後: "UserPreferences"
すべてのグループから出た後: ""
ネストされた設定を保存しました。

--- 読み込み ---
読み込み開始時のグループ: ""
グループに入った直後: "UserPreferences"
Username: "john_doe"
さらにグループに入った直後: "UserPreferences/Theme"
Theme: colorScheme = "Dark" , fontSize = 12
グループを一つ出た後: "UserPreferences"
別のグループに入った直後: "UserPreferences/Network"
Network: proxyEnabled = true , proxyAddress = "192.168.1.1:8080"
グループを一つ出た後: "UserPreferences"
すべてのグループから出た後: ""
ネストされた設定を読み込みました。
  • settings.endGroup() は、直近の beginGroup() に対応し、一つ上の階層に戻ります。
  • settings.group() は、その時点での完全なグループパス(例: "UserPreferences/Theme")を返します。
  • settings.beginGroup() を複数回呼び出すことで、階層的なグループ構造を作成できます。


QSettings のグループ機能を使わない、またはより直接的な設定管理の代替手段はいくつかあります。

キーパスを直接指定する

beginGroup() / endGroup() を使わずに、キーパスをスラッシュ (/) で区切って直接 setValue()value() に渡す方法です。

Pros

  • グループの開始/終了を管理する手間が省ける。
  • シンプルな設定構造であれば、コードが短くなる。

Cons

  • グループ内のすべてのキーを列挙する childKeys() や、サブグループを列挙する childGroups() の恩恵を受けられない。
  • 複数の設定が同じグループに属する場合でも、毎回フルパスを記述する必要があるため、繰り返しが多くなる。
  • キーパスが長くなりがちで、入力ミスが発生しやすい。

コード例

#include <QCoreApplication>
#include <QSettings>
#include <QDebug>

void saveSettingsDirectly() {
    QCoreApplication::setOrganizationName("MyCompany");
    QCoreApplication::setApplicationName("MyApp");
    QSettings settings;

    // メインウィンドウの設定
    settings.setValue("MainWindow/pos", QPoint(100, 100));
    settings.setValue("MainWindow/size", QSize(800, 600));
    settings.setValue("MainWindow/fullScreen", false);

    // アプリケーションの言語設定
    settings.setValue("Application/language", "ja_JP");

    qDebug() << "直接パスで設定を保存しました。";
}

void loadSettingsDirectly() {
    QCoreApplication::setOrganizationName("MyCompany");
    QCoreApplication::setApplicationName("MyApp");
    QSettings settings;

    // メインウィンドウの設定を読み込む
    QPoint pos = settings.value("MainWindow/pos", QPoint(50, 50)).toPoint();
    QSize size = settings.value("MainWindow/size", QSize(640, 480)).toSize();
    bool fullScreen = settings.value("MainWindow/fullScreen", false).toBool();
    qDebug() << "MainWindow: pos =" << pos << ", size =" << size << ", fullScreen =" << fullScreen;

    // アプリケーションの言語設定を読み込む
    QString language = settings.value("Application/language", "en_US").toString();
    qDebug() << "Application: language =" << language;

    qDebug() << "直接パスで設定を読み込みました。";
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    saveSettingsDirectly();
    loadSettingsDirectly();
    return 0;
}

カスタム設定ファイル形式を使用する

QSettings のデフォルトのフォーマット(INI、レジストリ、plist)に依存せず、独自のファイルフォーマット(XML、JSONなど)で設定を保存する方法です。

Pros

  • 特定のニーズに合わせた複雑なデータ構造を簡単に保存できる。
  • 人間が読みやすい形式にできる(JSON/XMLの場合)。
  • 設定の構造を完全に制御できる。

Cons

  • プラットフォーム間の互換性を自分で管理する必要がある。
  • 設定の読み書きロジックを自分で実装する必要がある(パースとシリアライズ)。

一般的な実装方法

  • INIファイルを手動でパース
    QFileQTextStream を使ってINIファイルを読み書きし、正規表現などでセクションやキーをパースします。(これは QSettings のINIフォーマットを直接利用する方がはるかに簡単なので、通常は推奨されません。)
  • XML
    QXmlStreamReader, QXmlStreamWriter または QDomDocument を使用して、設定をXML形式でファイルに保存・読み込みます。
  • JSON
    QJsonDocument, QJsonObject, QJsonArray を使用して、設定をJSON形式でファイルに保存・読み込みます。

コード例(JSONの場合)

#include <QCoreApplication>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QVariantMap>
#include <QDebug>

void saveSettingsToJson(const QString& filePath) {
    QJsonObject rootObject;

    // MainWindow グループ
    QJsonObject mainWindowObject;
    mainWindowObject["pos_x"] = 100;
    mainWindowObject["pos_y"] = 100;
    mainWindowObject["width"] = 800;
    mainWindowObject["height"] = 600;
    mainWindowObject["fullScreen"] = false;
    rootObject["MainWindow"] = mainWindowObject;

    // Application グループ
    QJsonObject applicationObject;
    applicationObject["language"] = "ja_JP";
    rootObject["Application"] = applicationObject;

    QJsonDocument doc(rootObject);
    QFile file(filePath);
    if (file.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
        file.write(doc.toJson(QJsonDocument::Indented)); // 整形して保存
        file.close();
        qDebug() << "JSON形式で設定を保存しました:" << filePath;
    } else {
        qWarning() << "JSONファイルを開けませんでした:" << filePath;
    }
}

void loadSettingsFromJson(const QString& filePath) {
    QFile file(filePath);
    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qWarning() << "JSONファイルを開けませんでした:" << filePath;
        return;
    }

    QByteArray jsonData = file.readAll();
    file.close();

    QJsonDocument doc = QJsonDocument::fromJson(jsonData);
    if (doc.isNull()) {
        qWarning() << "JSONデータをパースできませんでした:" << filePath;
        return;
    }

    QJsonObject rootObject = doc.object();

    // MainWindow グループを読み込む
    if (rootObject.contains("MainWindow") && rootObject["MainWindow"].isObject()) {
        QJsonObject mainWindowObject = rootObject["MainWindow"].toObject();
        int posX = mainWindowObject["pos_x"].toInt(50);
        int posY = mainWindowObject["pos_y"].toInt(50);
        int width = mainWindowObject["width"].toInt(640);
        int height = mainWindowObject["height"].toInt(480);
        bool fullScreen = mainWindowObject["fullScreen"].toBool(false);
        qDebug() << "MainWindow (JSON): pos = (" << posX << "," << posY << "), size = (" << width << "," << height << "), fullScreen =" << fullScreen;
    }

    // Application グループを読み込む
    if (rootObject.contains("Application") && rootObject["Application"].isObject()) {
        QJsonObject applicationObject = rootObject["Application"].toObject();
        QString language = applicationObject["language"].toString("en_US");
        qDebug() << "Application (JSON): language =" << language;
    }

    qDebug() << "JSON形式で設定を読み込みました。";
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QString settingsFilePath = QCoreApplication::applicationDirPath() + "/my_app_settings.json";
    saveSettingsToJson(settingsFilePath);
    loadSettingsFromJson(settingsFilePath);
    return 0;
}

カスタム設定管理クラスを設計する

アプリケーションの設定をカプセル化し、読み書きのロジックを隠蔽する専用のクラスを作成する方法です。このクラスの内部で QSettings を使うこともできますし、上記のカスタムファイル形式を使うこともできます。

Pros

  • シングルトンパターンと組み合わせることで、アプリケーションのどこからでも設定にアクセスできる。
  • 設定値へのアクセスをより型安全に、読みやすくできる。
  • 設定ロジックが一箇所に集中するため、保守性が向上する。

Cons

  • 初期設計と実装に手間がかかる。

例(QSettings を内部で使う場合)

#include <QCoreApplication>
#include <QSettings>
#include <QDebug>
#include <QPoint>
#include <QSize>

// 設定を管理するシングルトンクラス
class AppSettings : public QObject
{
    Q_OBJECT
public:
    static AppSettings* instance() {
        if (!m_instance) {
            m_instance = new AppSettings(qApp);
        }
        return m_instance;
    }

    void loadSettings() {
        QSettings settings;
        settings.beginGroup("MainWindow");
        m_mainWindowPos = settings.value("pos", QPoint(50, 50)).toPoint();
        m_mainWindowSize = settings.value("size", QSize(640, 480)).toSize();
        m_fullScreen = settings.value("fullScreen", false).toBool();
        settings.endGroup();

        settings.beginGroup("Application");
        m_language = settings.value("language", "en_US").toString();
        settings.endGroup();

        qDebug() << "設定をロードしました。";
        qDebug() << "Current group (after load):" << settings.group(); // ルート ""
    }

    void saveSettings() {
        QSettings settings;
        settings.beginGroup("MainWindow");
        settings.setValue("pos", m_mainWindowPos);
        settings.setValue("size", m_mainWindowSize);
        settings.setValue("fullScreen", m_fullScreen);
        settings.endGroup();

        settings.beginGroup("Application");
        settings.setValue("language", m_language);
        settings.endGroup();

        qDebug() << "設定を保存しました。";
    }

    // 各設定値へのアクセサ(例として一部のみ)
    QPoint mainWindowPos() const { return m_mainWindowPos; }
    void setMainWindowPos(const QPoint& pos) { m_mainWindowPos = pos; }

    QSize mainWindowSize() const { return m_mainWindowSize; }
    void setMainWindowSize(const QSize& size) { m_mainWindowSize = size; }

    bool isFullScreen() const { return m_fullScreen; }
    void setFullScreen(bool fs) { m_fullScreen = fs; }

    QString language() const { return m_language; }
    void setLanguage(const QString& lang) { m_language = lang; }

private:
    explicit AppSettings(QObject* parent = nullptr) : QObject(parent) {}
    ~AppSettings() {} // シングルトンのデストラクタはプライベートにするか、deleteLaterを適切に呼ぶ

    static AppSettings* m_instance;

    QPoint m_mainWindowPos;
    QSize m_mainWindowSize;
    bool m_fullScreen;
    QString m_language;
};

AppSettings* AppSettings::m_instance = nullptr; // 静的メンバ変数の初期化

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QCoreApplication::setOrganizationName("MyCompany");
    QCoreApplication::setApplicationName("MyApp");

    AppSettings* appSettings = AppSettings::instance();

    // 設定を変更する前
    qDebug() << "初期設定(デフォルト値):";
    appSettings->loadSettings(); // ファイルから読み込む
    qDebug() << "Window Pos:" << appSettings->mainWindowPos();
    qDebug() << "Language:" << appSettings->language();

    // 設定を変更
    appSettings->setMainWindowPos(QPoint(200, 200));
    appSettings->setLanguage("en_US");
    appSettings->setFullScreen(true);

    // 変更した設定を保存
    appSettings->saveSettings();

    // アプリケーションを再起動したかのように、もう一度設定をロードしてみる
    qDebug() << "\n再ロード後:";
    appSettings->loadSettings();
    qDebug() << "Window Pos:" << appSettings->mainWindowPos();
    qDebug() << "Language:" << appSettings->language();
    qDebug() << "Full Screen:" << appSettings->isFullScreen();

    return 0;
}
#include "main.moc" // moc ファイルのインクルード (Qt のビルドシステムが自動生成)

解説

  • QSettings::group() はこのクラスの内部の実装詳細となり、外部からは直接呼び出されることはありません。
  • 内部で QSettings を使用し、beginGroup()endGroup() を使って設定の読み書きを行いますが、外部からはその詳細は隠蔽されています。
  • この例では、AppSettings クラスがシングルトンとして設計されており、アプリケーション全体で設定を管理します。

QSettings::group()beginGroup() / endGroup() と共に QSettings のコアな機能であり、階層的な設定管理をQtが提供する最も標準的な方法です。

  • アプリケーション全体で設定を統一的に管理し、アクセスをカプセル化したい場合
    カスタム設定管理クラスを設計し、その内部で QSettings または他の方法を使用するのが良いでしょう。
  • 設定が複雑で、厳密なスキーマや人間が読みやすい形式を求める場合
    JSONやXMLなどのカスタム形式での保存を検討する価値があります。
  • 簡単な設定や既存のINI/レジストリ形式を利用したい場合
    QSettings のグループ機能が最も推奨されます。