Criando aplicações baseadas em banco de dados usando Qt

Esse artigo mostrará como criar você pode integrar recursos do SQLite a sua aplicação usando a arquitetura modelo/visão em uma aplicação-exemplo de gerenciamento de contatos.

Introdução

Um recursos importante do Qt é o suporte a SQL. Usando a arquitetura modelo/visão do Qt e um mínimo de conhecimento em SQL é possível criar poderosas aplicações baseadas em banco de dados. Se você for um iniciante em SQL pode encontrar bons materiais introdutórios sobre SQL pesquisando na web. O SQL é considerada a linguagem mais usada nos sistemas de gerenciamento de banco de dados e parte de qualquer cursos de ciência da computação. Em especial, o SQLite é útil para aplicações móveis já que é um banco de dados SQL transacional, que necessita de configuração zero, não dependente de servidor e auto-contido. O SQLite tem sido usado em vários projetos grandes como Mozilla Firefoz, smartphones Symbian, Solaris, PHP, MAc OS, entre outros, e é provavelmente o banco de dados SQL mais largamente usado. No Qt, o SQLite está disponível para desktop, Meego e Symbian.
Nesse artigo será demonstrado como vocÊ pode integrar os recursos do SQLite a sua aplicação usando a arquitetura modelo/visão em uma aplicação de gerenciamento de contatos. O Nokia Qt SDK foi usado nesse exemplo.
Se estiver usando dispositivos Maemo como o N900, é  necessário instalar o SQLite para Qt antes de testar essa aplicação em seu dispositivo. Abra a aplicação X Terminal e digite os seguintes comandos:

sudo gainroot
apt-get install libqt4-sql-sqlite

sudo gainroot permite que você execute comandos em seu telefone como administrador e precisa ser usado com cuidado.
Para usuários Symbian, a aplicação sqlite3.sis é necessário. Pode ser encontrado junto com o Nokia Qt SDK em \NokiaQtSDK\Symbian\sis\sqlite3.sis ou pronto para instalação  a partir do menu Iniciar (Nokia Qt SDK -> Symbian -> Install SQLite to Symbian).
Se não quiser usar um dispositivo real, umaalternativa é usar o simulador do Qt, disponível no Nokia Qt SDK. Nenhuma instalação adicional é necessária nesse caso.

Classes Qt para acessar o SQLite

Usando Qt, as classes SQL são divididas em três camadas:

  • Camada de Driver: Um conjunto de classes úteis para quem quiser criar o seu próprio driver de banco de dados e adicionar personalizações aos recursos existentes.
  • Camada da API SQL: Acesso básico ao banco de dados, como conexões, erros, manipulação de campos e assim em diante.
  • Camada da interface com o usuário: Um conjunto de classes para ser usadas com a arquitetura modelo/visão do Qt.

Apenas as camadas dois e três serão usadas nesse artigo, e são representadas pelas seguintes classes disponíveis na arquitetura modelo/visão:

  • QSqlDatabase: O conector com o banco de dados (fonte de dados, nessa arquitetura). Como o SQLite é mapeado em um arquivo, a conexão é direta. Para banco de dados mais sofisticados, parâmetros como login, senha e porta podem ser fornecidos.
  • QSqlTableModel: usado como modelo, fornece uma interface de alto nível para acesso ao banco de dados.
  • QTreeView: o objeto da visão usado para exibir os registros do banco de dados

Conectando o banco de dados SQLite a arquitetura modelo/visão do Qt

Como os banco de dados do SQLite são mapeados em arquivos, a conexão ao banco de dados consiste apenas de especificar o arquivo a ser usado. Naturalmente, o caminho para o arquivo pode variar se você estiver programando para MeeGo ou Symbian e você deve cuidar dessa situação com sentenças #ifdef Q_OS_SYMBIAN. Além disso, você precisa criar a estrutura do banco de dados dentro desse arquivo antes de usa-lo para armazenar os registros.
In the following code snippet the database connector is created and the database opened. If the database structure does not exist yet it will be created.

// using SQLITE driver
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("path_to_database_file");
if (db.open()) {
    // Try to locate the contacts database.
    // If it is not available create it.
    if (db.tables().indexOf("contacts") == -1) {
        QSqlQuery query(db);
        query.prepare("CREATE TABLE contacts (name VARCHAR(32), phone VARCHAR(16))");
        if (!query.exec())
            qCritical() << query.lastError();
    }
} else {
    qCritical() << db.lastError();
}

O próximo passo é associar esse banco de dados a arquitetura modelo/visão. Os métodos setTable() (da classe modelo) e setModel() (da classe visão)  são usados para cumprir essa tarefa. É necessário chamar select() para popular o modelo com dados da tabela e o programador pode escolher sua estratégia de edição  chamando o método setEditEstrategy(). Nesse caso, usando QSqlTableModel::OnFieldChange, qualquer alteração será aplicada imediatamente ao banco de dados.

// create a new model and use the contacts table
QSqlTableModel *model = new QSqlTableModel(this, db);
model->setTable("contacts");
// All changes to the model will be applied immediately to the database
model->setEditStrategy(QSqlTableModel::OnFieldChange);
// Populate the model with data from table
model->select();
// creating the model/view association
ui->view->setModel(model);

Agora sua aplicação está pronta para ser iniciada e todos os dados do banco de dados estarão disponíveis ao usuário através do componente. Adicionalmente, sua aplicação tem suporte a persistência de dados sem qualquer linha de código, todos os registros são mantidos durante as sucessivas execuções do programa.

Adicionando registros

Quando os registros puderem ser visualizados, sua próxima tarefa é criar uma caixa de diálogo para disponibilizar os dados aos usuários. O designer do formulário do Qt Creator torna essa tarefa muito fácil. Uma caixa de diálogo simples com apenas dois campos (nome e telefone) é necessária para essa aplicação exemplo. Crie essa caixa de diálogo e as classes relacionadas e adicione-as ao seu projeto, adicionando métodos para os botões Cancel e Ok. Para mostrar a caixa de diálogo, você precisa usar o método exec(). Depois que essa caixa de diálogo é fechada, você pode verificar se tem algum dado válido e assim adicionar esses dados ao seu banco de dados como um novo registro. O método record() (do modelo) retornará um registro SQL de acordo com a especificação do banco de dados e você pode preencher esse registro usando o método sertValue(). As propriedades do Qt são usadas na classe da caixa de diálogo para nos ajudar a coletar os dados necessários e o método do modelo insertRecord() adicionará esse registro ao banco de dados.

// Create a new empty dialog and show it using exec()
NewContact dlg(this);
dlg.resetName();
dlg.resetPhone();
if(dlg.exec() == QDialog::Accepted && dlg.name().length() > 0) {
    // create a record from the current model
    QSqlRecord rec = model->record();
    rec.setValue("name", dlg.name());
    rec.setValue("phone", dlg.phone());
    // insert a new record (-1)
    model->insertRecord(-1,rec);
}

Apagando registro

O apagamento de registros é simples já que você tem o indice de registro.  Obtenha o indice como um objeto QModelIndex pesquisando o componente da visão e usando-o como um parâmetro para a chamada a removeRow() (do modelo).

// get the current index, if any
QModelIndex sample = ui->view->currentIndex();
if (sample.row() >= 0) {
    QMessageBox::StandardButton reply;
    reply = QMessageBox::question(this, tr("Remove contact"),
                                QString(tr("Remove contact ?")),
                                QMessageBox::Yes | QMessageBox::No);
    if(reply == QMessageBox::Yes)
        model->removeRow(sample.row()); // remove the current index
}

Modificando registros

Depois de criar os métodos addRegister() e deleteRecord(), é fácil codificar o método editRecord(). Obtenha o indice do registro e preencha a caixa de diálogo usando as informações do registro. Depois apresente essa caixa de diálogo ao usuário e salve as alterações.

// get the current index, if any
QModelIndex sample = ui->view->currentIndex();
if (sample.row() >= 0 ) {
    // copy the current record
    QSqlRecord rec = model->record(sample.row());
    NewContact dlg(this);
    dlg.setName(rec.value("name").toString());
    dlg.setPhone(rec.value("phone").toString());
    if (dlg.exec() == QDialog::Accepted) {
        rec.setValue("name",dlg.name());
        rec.setValue("phone",dlg.phone());
        // save modified data
        model->setRecord(sample.row(),rec);
    }
}

Conclusão

Como o Qt é possível criar programas consisos que usam persistência de dados com SQL usando poucas linhas de código. Em especial, a abstração do SQLite fornecida pelo Qt é realmente direta quando usada junto com a arquitetura modelo/visão do Qt.

Código-fonte

Esse programa exemplo foi testado no Maemo, Linux e Windows sem modificações. Você pode baixar todo o código fonte nesse link.

Traduzido de