このページについて

キャッシュされたSQLテーブル

「キャッシュされたテーブル」のサンプルでは、テーブルビューを使用してデータベースにアクセスし、ユーザーがプッシュボタンを使用して明示的に送信するまで、データへの変更をキャッシュする方法を示しています。

ユーザーはテーブルのセルを更新し、送信ボタンを選択して、その変更をデータベースに反映させます。

このサンプルは、TableEditor という単一のクラスで構成されています。これは、ユーザーがデータベースに格納されたデータを変更できるようにするカスタムダイアログウィジェットです。まず、クラスの定義と使用方法を確認し、その後、実装について見ていきます。

TableEditor クラスの定義

TableEditor クラスはQWidget を継承しており、これによりテーブルエディタウィジェットはトップレベルのダイアログウィンドウとなります。

class TableEditor : public QWidget
{
    Q_OBJECT

public:
    explicit TableEditor(const QString &tableName, QWidget *parent = nullptr);

private slots:
    void submit();

private:
    QPushButton *submitButton;
    QPushButton *revertButton;
    QPushButton *quitButton;
    QDialogButtonBox *buttonBox;
    QSqlTableModel *model;
};

TableEditor のコンストラクタは2つの引数を受け取ります。1つ目は、TableEditor オブジェクトが操作対象とするデータベーステーブルへの参照です。もう1つは親ウィジェットへのポインタであり、これは基底クラスのコンストラクタに渡されます。

QSqlTableModel 変数の宣言に注目してください。この例で後述するように、QSqlTableModel クラスは、QTableView などのビュークラスにデータを提供するために使用できます。QSqlTableModel クラスは、単一のテーブルからデータベースレコードを読み書きすることを可能にする、編集可能なデータモデルを提供します。このクラスは、SQL文の実行や操作を行う手段を提供する、より低レベルのQSqlQuery クラスを基盤として構築されています。

また、ユーザーが明示的に送信を要求するまで、データへの変更をキャッシュするためにテーブルビューをどのように使用できるかについても説明します。そのため、モデルやエディタのボタンに加えて、submit() スロットを宣言する必要があります。

データベースへの接続
TableEditor クラスを使用する前に、編集したいテーブルが含まれるデータベースへの接続を作成する必要があります:
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    if (!createConnection())
        return 1;

    TableEditor editor("person");
    editor.show();
    return app.exec();
}

createConnection() 関数は、利便性のために提供されているヘルパー関数です。この関数は、sql サンプルディレクトリにあるconnection.h ファイルで定義されています(sql ディレクトリ内のすべてのサンプルは、この関数を使用してデータベースに接続しています)。

static bool createConnection()
{
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(":memory:");
    if (!db.open()) {
        QMessageBox::critical(nullptr, QObject::tr("Cannot open database"),
            QObject::tr("Unable to establish a database connection.\n"
                        "This example needs SQLite support. Please read "
                        "the Qt SQL driver documentation for information how "
                        "to build it.\n\n"
                        "Click Cancel to exit."), QMessageBox::Cancel);
        return false;
    }

    QSqlQuery query;
    query.exec("create table person (id int primary key, "
               "firstname varchar(20), lastname varchar(20))");
    query.exec("insert into person values(101, 'Danny', 'Young')");
    query.exec("insert into person values(102, 'Christine', 'Holand')");
    query.exec("insert into person values(103, 'Lars', 'Gordon')");
    query.exec("insert into person values(104, 'Roberto', 'Robitaille')");
    query.exec("insert into person values(105, 'Maria', 'Papadopoulos')");

    query.exec("create table items (id int primary key,"
                                             "imagefile int,"
                                             "itemtype varchar(20),"
                                             "description varchar(100))");
    query.exec("insert into items "
               "values(0, 0, 'Qt',"
               "'Qt is a full development framework with tools designed to "
               "streamline the creation of stunning applications and  "
               "amazing user interfaces for desktop, embedded and mobile "
               "platforms.')");
    query.exec("insert into items "
               "values(1, 1, 'Qt Quick',"
               "'Qt Quick is a collection of techniques designed to help "
               "developers create intuitive, modern-looking, and fluid "
               "user interfaces using a CSS & JavaScript like language.')");
    query.exec("insert into items "
               "values(2, 2, 'Qt Creator',"
               "'Qt Creator is a powerful cross-platform integrated "
               "development environment (IDE), including UI design tools "
               "and on-device debugging.')");
    query.exec("insert into items "
               "values(3, 3, 'Qt Project',"
               "'The Qt Project governs the open source development of Qt, "
               "allowing anyone wanting to contribute to join the effort "
               "through a meritocratic structure of approvers and "
               "maintainers.')");

    query.exec("create table images (itemid int, file varchar(20))");
    query.exec("insert into images values(0, 'images/qt-logo.png')");
    query.exec("insert into images values(1, 'images/qt-quick.png')");
    query.exec("insert into images values(2, 'images/qt-creator.png')");
    query.exec("insert into images values(3, 'images/qt-project.png')");

    return true;
}

createConnection 関数は、メモリ内SQLITEデータベースへの接続を開き、テスト用テーブルを作成します。別のデータベースを使用したい場合は、この関数のコードを修正するだけで済みます。

TableEditor クラスの実装

このクラスの実装は、コンストラクタとsubmit() スロットの2つの関数のみで構成されています。コンストラクタ内では、データモデルと各種ウィンドウ要素を作成・カスタマイズします。

TableEditor::TableEditor(const QString &tableName, QWidget *parent)
    : QWidget(parent)
{
    model = new QSqlTableModel(this);
    model->setTable(tableName);
    model->setEditStrategy(QSqlTableModel::OnManualSubmit);
    model->select();

    model->setHeaderData(0, Qt::Horizontal, tr("ID"));
    model->setHeaderData(1, Qt::Horizontal, tr("First name"));
    model->setHeaderData(2, Qt::Horizontal, tr("Last name"));

まず、データモデルを作成し、そのモデルが操作する対象となるSQLデータベーステーブルを設定します。 なお、QSqlTableModel::setTable() 関数はテーブルからデータを選択するものではなく、フィールド情報を取得するだけです。そのため、後でQSqlTableModel::select() 関数を呼び出し、テーブルのデータをモデルに格納します。フィルタやソート条件を指定することで、選択内容をカスタマイズできます(詳細については、QSqlTableModel クラスのドキュメントを参照してください)。

また、モデルの編集戦略も設定します。編集戦略は、ユーザーがビューで行った変更が、いつ実際にデータベースに反映されるかを決定します。ユーザーが明示的に送信するまで、テーブルビュー(つまりモデル内)に変更をキャッシュしておきたいので、QSqlTableModel::OnManualSubmit 戦略を選択します。その他の選択肢としては、QSqlTableModel::OnFieldChange およびQSqlTableModel::OnRowChange があります。

最後に、モデルがQSqlQueryModel クラスから継承しているsetHeaderData()関数を使用して、ビューのヘッダーに表示されるラベルを設定します。

    QTableView *view = new QTableView;
    view->setModel(model);
    view->resizeColumnsToContents();

次に、テーブルビューを作成します。QTableView クラスは、テーブルビューのデフォルトのモデル/ビュー実装を提供します。つまり、モデルからの項目を表示するテーブルビューを実装しています。また、ユーザーが項目を編集し、その変更をモデルに保存することも可能です。読み取り専用のビューを作成するには、ビューがQAbstractItemView クラスから継承しているeditTriggers プロパティを使用して、適切なフラグを設定します。

ビューにデータを表示させるには、setModel() 関数を使用して、モデルをビューに渡します。

    submitButton = new QPushButton(tr("Submit"));
    submitButton->setDefault(true);
    revertButton = new QPushButton(tr("&Revert"));
    quitButton = new QPushButton(tr("Quit"));

    buttonBox = new QDialogButtonBox(Qt::Vertical);
    buttonBox->addButton(submitButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(revertButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);

TableEditor のボタンは、通常のQPushButton オブジェクトです。これらのボタンをボタンボックスに追加することで、現在のウィジェットスタイルに適したレイアウトでボタンが表示されるようにします。その理由は、ダイアログやメッセージボックスでは通常、そのプラットフォームのインターフェースガイドラインに準拠したレイアウトでボタンが表示されるためです。 当然のことながら、プラットフォームごとにダイアログのレイアウトは異なります。`QDialogButtonBox ` を使用すると、開発者はボタンを追加するだけで、ユーザーのデスクトップ環境に適したレイアウトが自動的に適用されます。

ダイアログのボタンのほとんどは、特定の役割に従います。addButton() 関数を使用してボタンボックスにボタンを追加する際は、QDialogButtonBox::ButtonRole 列挙型を使用してボタンの役割を指定する必要があります。あるいは、QDialogButtonBox には、OK 、Cancel 、Save など、使用可能な標準ボタンがいくつか用意されています。これらはフラグとして存在するため、コンストラクタ内でOR演算を組み合わせることができます。

    connect(submitButton, &QPushButton::clicked, this, &TableEditor::submit);
    connect(revertButton, &QPushButton::clicked,  model, &QSqlTableModel::revertAll);
    connect(quitButton, &QPushButton::clicked, this, &TableEditor::close);

Quit ボタンをテーブルエディタのclose()スロットに接続し、Submit ボタンをプライベートスロットsubmit() に接続します。後者のスロットがデータトランザクションを処理します。最後に、Revert ボタンをモデルのrevertAll()スロットに接続し、保留中の変更をすべて元に戻します(つまり、元のデータを復元します)。

    QHBoxLayout *mainLayout = new QHBoxLayout;
    mainLayout->addWidget(view);
    mainLayout->addWidget(buttonBox);
    setLayout(mainLayout);

    setWindowTitle(tr("Cached Table"));
}

最後に、ボタンボックスとテーブルビューをレイアウトに追加し、そのレイアウトをテーブルエディタウィジェットに配置して、エディタのウィンドウタイトルを設定します。

void TableEditor::submit()
{
    model->database().transaction();
    if (model->submitAll()) {
        model->database().commit();
    } else {
        model->database().rollback();
        QMessageBox::warning(this, tr("Cached Table"),
                             tr("The database reported an error: %1")
                             .arg(model->lastError().text()));
    }
}

submit() スロットは、ユーザーが変更を保存するために「Submit 」ボタンをクリックするたびに呼び出されます。

まず、QSqlDatabase::transaction() 関数を使用して、データベース上でトランザクションを開始します。データベーストランザクションとは、データベース管理システムや類似のシステムとのやり取りの単位であり、他のトランザクションとは独立して、一貫性があり信頼性の高い方法で処理されます。使用中のデータベースへのポインタは、QSqlTableModel::database() 関数を使用して取得できます。

次に、保留中の変更、つまりモデルで変更された項目をすべて送信しようとします。エラーが発生しなければ、QSqlDatabase::commit() 関数を使用してトランザクションをデータベースにコミットします(一部のデータベースでは、データベース上でアクティブなQSqlQuery がある場合、この関数は機能しないことに注意してください)。 エラーが発生した場合は、QSqlDatabase::rollback() 関数を使用してトランザクションをロールバックし、ユーザーに警告を表示します。

関連項目:

QtSQLデータベースクラスの完全な一覧、およびモデル/ビュープログラミングのドキュメント。

サンプルプロジェクト @ code.qt.io

© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.