アプリケーション状態の永続化
一般的なデスクトップアプリケーションでは、ユーザーが最終的に終了した時の状態(ウィンドウのサイズ、選択されたフォント、ツールバーの表示状態など)を、次回起動時に復元することが求められます。これを実現するには、アプリケーション終了時に状態をファイルやデータベースに保存し、起動時にそれらを読み出す処理が必要です。
設定データの保存形式には、XMLやJSONといったテキスト形式、SQLiteなどの軽量データベース、あるいは独自のバイナリ形式などがあります。Qtフレームワークを利用した開発では、QDataStreamクラスを使用して、設定情報をバイナリデータとして直接ファイルに書き出すアプローチが有効です。この方法は、データの読み書きが効率的であることに加え、バイナリ形式であるためユーザーによる意図しない改変や悪意ある書き換えからデータを保護しやすいという利点があります。
設定管理クラスの設計
設定の保存と読み込みを担当するクラスを設計します。このクラスでは、引数を持たないコンストラクタでファイルから設定を読み込み(デシリアライズ)、設定値を引数に持つコンストラクタでメモリ上のデータを保持し、保存メソッドでファイルへ書き出す(シリアライズ)役割を担います。以下にクラス定義の例を示します。
#ifndef SETTINGS_H
#define SETTINGS_H
#include <QObject>
#include <QFont>
#include <QDataStream>
class AppSettings : public QObject
{
Q_OBJECT
struct UiState {
QFont editorFont;
bool isToolBarVisible;
bool isStatusBarVisible;
bool isLineWrapEnabled;
};
UiState m_state;
bool m_isLoadSuccess;
bool readFromFile();
bool writeToFile();
public:
explicit AppSettings(QObject* parent = nullptr);
explicit AppSettings(QFont font, bool toolBar, bool statusBar, bool wrap, QObject* parent = nullptr);
QFont getEditorFont() const;
bool isToolBarVisible() const;
bool isStatusBarVisible() const;
bool isLineWrapEnabled() const;
bool isSettingsValid() const;
bool save();
};
#endif // SETTINGS_H
実装詳細
実装ファイルでは、QDataStreamを用いてデータのシリアライズを行います。データの互換性を保つため、ストリームのバージョンを明示的に設定することが重要です。
#include "Settings.h"
#include <QFile>
#include <QApplication>
#include <QIODevice>
// 設定ファイルから読み込むコンストラクタ
AppSettings::AppSettings(QObject* parent) : QObject(parent)
{
m_isLoadSuccess = readFromFile();
}
// 現在の状態を保持して保存用に使用するコンストラクタ
AppSettings::AppSettings(QFont font, bool toolBar, bool statusBar, bool wrap, QObject* parent)
: QObject(parent)
{
m_state.editorFont = font;
m_state.isToolBarVisible = toolBar;
m_state.isStatusBarVisible = statusBar;
m_state.isLineWrapEnabled = wrap;
m_isLoadSuccess = true;
}
bool AppSettings::readFromFile()
{
bool result = false;
QString path = QApplication::applicationDirPath() + "/user_state.dat";
QFile configFile(path);
if (configFile.open(QIODevice::ReadOnly)) {
QDataStream in(&configFile);
in.setVersion(QDataStream::Qt_5_15);
in >> m_state.editorFont;
in >> m_state.isToolBarVisible;
in >> m_state.isStatusBarVisible;
in >> m_state.isLineWrapEnabled;
configFile.close();
result = true;
}
return result;
}
bool AppSettings::writeToFile()
{
bool result = false;
QString path = QApplication::applicationDirPath() + "/user_state.dat";
QFile configFile(path);
if (configFile.open(QIODevice::WriteOnly)) {
QDataStream out(&configFile);
out.setVersion(QDataStream::Qt_5_15);
out << m_state.editorFont;
out << m_state.isToolBarVisible;
out << m_state.isStatusBarVisible;
out << m_state.isLineWrapEnabled;
configFile.close();
result = true;
}
return result;
}
// Getterメソッドの実装
QFont AppSettings::getEditorFont() const { return m_state.editorFont; }
bool AppSettings::isToolBarVisible() const { return m_state.isToolBarVisible; }
bool AppSettings::isStatusBarVisible() const { return m_state.isStatusBarVisible; }
bool AppSettings::isLineWrapEnabled() const { return m_state.isLineWrapEnabled; }
bool AppSettings::isSettingsValid() const { return m_isLoadSuccess; }
bool AppSettings::save() { return writeToFile(); }
メインウィンドウへの統合
実際のアプリケーションでは、ウィンドウの初期化時に設定を読み込み、終了時に設定を書き込みます。以下の例では、MainWindowの初期化処理(二段階初期化の一部)とデストラクタで設定クラスを活用しています。
設定の適用(起動時)
bool MainWindow::initializeUI()
{
bool ret = true;
// デフォルトの初期化処理...
ret = ret && initMenuBar();
ret = ret && initToolBar();
ret = ret && initStatusBar();
ret = ret && initEditor();
AppSettings currentSettings;
// 設定ファイルの読み込みが成功した場合のみ状態を復元
if (currentSettings.isSettingsValid()) {
textEditor->setFont(currentSettings.getEditorFont());
// 自動折り返しの設定復元
if (!currentSettings.isLineWrapEnabled()) {
textEditor->setLineWrapMode(QPlainTextEdit::NoWrap);
updateMenuAction("word_wrap", false);
}
// ツールバーの表示状態復元
if (!currentSettings.isToolBarVisible()) {
mainToolBar->setVisible(false);
updateMenuAction("show_toolbar", false);
}
// ステータスバーの表示状態復元
if (!currentSettings.isStatusBarVisible()) {
mainStatusBar->setVisible(false);
updateMenuAction("show_statusbar", false);
}
}
return ret;
}
設定の保存(終了時)
MainWindow::~MainWindow()
{
// 現在のUI状態を取得
QFont currentFont = textEditor->font();
bool wrapEnabled = (textEditor->lineWrapMode() == QPlainTextEdit::WidgetWidth);
bool tbVisible = isMenuActionChecked("show_toolbar");
bool sbVisible = isMenuActionChecked("show_statusbar");
// 設定オブジェクトを作成してファイルへ保存
AppSettings snapshot(currentFont, tbVisible, sbVisible, wrapEnabled);
snapshot.save();
}
この実装により、アプリケーションは終了時の状態を正確に記憶し、次回の起動時にはユーザーが期待する環境を即座に再現できるようになります。バイナリストリームを採用することで、データの読み書きオーバーヘッドが小さく、かつ設定ファイルの直接的な編集を防ぐことができるため、アプリケーションの安定性とセキュリティが向上します。