En esta página

Tabla SQL en caché

El ejemplo Tabla en caché muestra cómo puede utilizarse una vista de tabla para acceder a una base de datos, almacenando en caché cualquier cambio en los datos hasta que el usuario los envíe explícitamente mediante un botón pulsador.

El usuario actualiza una celda de la tabla y selecciona el botón de envío para aplicar el cambio en la base de datos.

El ejemplo consiste en una única clase, TableEditor, que es un widget de diálogo personalizado que permite al usuario modificar los datos almacenados en una base de datos. Primero revisaremos la definición de la clase y cómo utilizarla, y después echaremos un vistazo a la implementación.

Definición de la clase TableEditor

La clase TableEditor hereda de QWidget haciendo del widget editor de tablas una ventana de diálogo de nivel superior.

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;
};

El constructor TableEditor toma dos argumentos: El primero es una referencia a la tabla de la base de datos sobre la que operará el objeto TableEditor. El otro es un puntero al widget padre y se pasa al constructor de la clase base.

Observe la declaración de la variable QSqlTableModel: Como veremos en este ejemplo, la clase QSqlTableModel puede utilizarse para proporcionar datos a clases de visualización como QTableView. La clase QSqlTableModel proporciona un modelo de datos editable que permite leer y escribir registros de la base de datos desde una única tabla. Está construida sobre la clase de nivel inferior QSqlQuery que proporciona medios para ejecutar y manipular sentencias SQL.

También vamos a mostrar cómo se puede utilizar una vista de tabla para almacenar en caché cualquier cambio en los datos hasta que el usuario solicite explícitamente enviarlos. Para ello necesitamos declarar un espacio submit() además del modelo y los botones del editor.

Conexión a una base de datos
Antes de poder utilizar la clase TableEditor, debemos crear una conexión a la base de datos que contiene la tabla que queremos editar:
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    if (!createConnection())
        return 1;

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

La función createConnection() es una función de ayuda que se proporciona por comodidad. Está definida en el archivo connection.h que se encuentra en el directorio de ejemplos sql (todos los ejemplos del directorio sql utilizan esta función para conectarse a una base de datos).

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;
}

La función createConnection abre una conexión a una base de datos SQLITE en memoria y crea una tabla de prueba. Si desea utilizar otra base de datos, simplemente modifique el código de esta función.

Implementación de la clase TableEditor

La implementación de la clase consta de sólo dos funciones, el constructor y la ranura submit(). En el constructor creamos y personalizamos el modelo de datos y los distintos elementos de la ventana:

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"));

Primero creamos el modelo de datos y establecemos la tabla de la base de datos SQL sobre la que queremos que opere el modelo. Nótese que la función QSqlTableModel::setTable() no selecciona datos de la tabla; sólo obtiene la información de sus campos. Por esa razón llamamos a la función QSqlTableModel::select() más adelante, rellenando el modelo con datos de la tabla. La selección puede personalizarse especificando filtros y condiciones de ordenación (para más detalles, consulte la documentación de la clase QSqlTableModel ).

También establecemos la estrategia de edición del modelo. La estrategia de edición dicta cuando los cambios realizados por el usuario en la vista, se aplican realmente a la base de datos. Como queremos almacenar en caché los cambios en la vista de tabla (es decir, en el modelo) hasta que el usuario los envíe explícitamente, elegimos la estrategia QSqlTableModel::OnManualSubmit. Las alternativas son QSqlTableModel::OnFieldChange y QSqlTableModel::OnRowChange.

Por último, configuramos las etiquetas que aparecen en la cabecera de la vista utilizando la función setHeaderData() que el modelo hereda de la clase QSqlQueryModel.

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

A continuación, creamos una vista de tabla. La clase QTableView proporciona una implementación modelo/vista por defecto de una vista de tabla, es decir, implementa una vista de tabla que muestra elementos de un modelo. También permite al usuario editar los elementos, almacenando los cambios en el modelo. Para crear una vista de sólo lectura, establezca la bandera adecuada utilizando la propiedad editTriggers que la vista hereda de la clase QAbstractItemView.

Para hacer que la vista presente nuestros datos, pasamos nuestro modelo a la vista utilizando la función 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);

Los botones de TableEditor son objetos QPushButton normales. Los añadimos a una caja de botones para asegurarnos de que los botones se presentan en un diseño apropiado para el estilo del widget actual. Esto se debe a que los cuadros de diálogo y los cuadros de mensaje suelen presentar los botones con un diseño que se ajusta a las directrices de la interfaz de la plataforma en cuestión. Invariablemente, las diferentes plataformas tienen diferentes diseños para sus cuadros de diálogo. QDialogButtonBox permite a un desarrollador añadir botones y utilizará automáticamente el diseño apropiado para el entorno de escritorio del usuario.

La mayoría de los botones para un diálogo siguen ciertos roles. Cuando se añade un botón a una caja de botones utilizando la función addButton(), el rol del botón debe especificarse utilizando el enum QDialogButtonBox::ButtonRole. Como alternativa, QDialogButtonBox proporciona varios botones estándar (por ejemplo, OK, Cancel, Save) que puede utilizar. Existen como banderas, por lo que se pueden O en el constructor.

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

Conectamos el botón Quit a la ranura close() del editor de tablas, y el botón Submit a nuestra ranura privada submit(). Esta última ranura se encargará de las transacciones de datos. Por último, conectamos el botón Revert a la ranura revertAll() de nuestro modelo, revirtiendo todos los cambios pendientes (es decir, restaurando los datos originales).

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

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

Al final añadimos la caja del botón y la vista de la tabla a un diseño, instalamos el diseño en el widget del editor de tablas y establecemos el título de la ventana del editor.

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()));
    }
}

La ranura submit() es llamada cada vez que los usuarios pulsan el botón Submit para guardar sus cambios.

En primer lugar, iniciamos una transacción en la base de datos utilizando la función QSqlDatabase::transaction(). Una transacción de base de datos es una unidad de interacción con un sistema de gestión de base de datos o similar que se trata de forma coherente y fiable independientemente de otras transacciones. Se puede obtener un puntero a la base de datos utilizada utilizando la función QSqlTableModel::database().

A continuación, intentamos enviar todos los cambios pendientes, es decir, los elementos modificados del modelo. Si no se produce ningún error, confirmamos la transacción en la base de datos utilizando la función QSqlDatabase::commit() (tenga en cuenta que en algunas bases de datos, esta función no funcionará si hay un QSqlQuery activo en la base de datos). En caso contrario, realizamos una reversión de la transacción utilizando la función QSqlDatabase::rollback() y enviamos un aviso al usuario.

Ver también:

Una lista completa de las Clases de Bases de Datos SQL de Qt, y la documentación de Programación Modelo/Vista.

Proyecto de ejemplo @ 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.