캐시된 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 생성자는 두 개의 인수를 받습니다: 첫 번째는 TableEditor 객체가 작동할 데이터베이스 테이블에 대한 참조입니다. 다른 하나는 부모 위젯에 대한 포인터이며 기본 클래스 생성자에게 전달됩니다.

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() 슬롯의 두 가지 함수로만 구성됩니다. 생성자에서는 데이터 모델과 다양한 창 요소를 생성하고 사용자 정의합니다:

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 에서 사용할 수 있는 몇 가지 표준 버튼(예: 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() 함수를 사용하여 트랜잭션의 롤백을 수행하고 사용자에게 경고를 게시합니다.

또한 참고하세요:

Qt SQL 데이터베이스 클래스의 전체 목록과 모델/보기 프로그래밍 문서를 참조하세요.

예제 프로젝트 @ code.qt.io

© 2025 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.