キャッシュ SQL テーブル

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

この例は、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 クラスは編集可能なデータモデルを提供し、1つのテーブルからデータベースのレコードを読み書きできるようにします。このクラスは、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::OnFieldChangeQSqlTableModel::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 では、いくつかの標準ボタン(例:OKCancelSave )を提供しています。これらはフラグとして存在するので、コンストラクタで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() 関数を使用してトランザクションをロールバックし、ユーザーに警告を表示します。

こちらも参照してください:

Qt の SQLデータベースクラスの完全なリストと、モデル/ビュープログラミングのドキュメントも参照してください。

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

©2024 The Qt Company Ltd. ここに含まれるドキュメントの著作権はそれぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。