Aprenda C++ com QT Creator

  • Página Inicial
  • Contato!
  • Tudo sobre C++ com QT Creator Parte 1!
  • Tudo sobre C++ com QT Creator Parte 2!
  • Tudo sobre C++ com QT Creator Parte 3!
  • Tudo sobre C++ com QT Creator Parte 4!
  • Tudo sobre C++ com QT Creator Parte 5!
  • Tudo sobre C++ com QT Creator Parte 6!
  • Tudo sobre C++ com QT Creator Parte 7!
  • C++ com QT Creator e Banco de Dados Parte 1

    Usando Banco de Dados no SQL no QT

    Crie um novo projeto para uma agenda em QT, mas nos details mude o nome da classe MainWindow para JanelaLogin.

    Crie um arquivo SQLite (dbagenda.db3) no SQLite Studio com esses dados:

    
    create table if not exists admin (
        id integer not null primary key autoincrement,
        nome varchar(30),
        username varchar(20),
        senha varchar(40),
        acesso char(1)
    );
    
    insert into admin (nome, username, senha, acesso) values ('Administrador', 'admin', '123', 'A');
    
    

    No projeto do QT, vá no arquivo pro e vá até aproximadamente na linha 7 e deixe essa linha assim:

    
    QT       += core gui sql
    
    

    No arquivo janelalogin.h, coloque isso:

    
    #include <QtSql>
    #include <QDebug>
    #include <QFileInfo>
    
    

    No arquivo janelalogin.cpp deixe o construtor assim:

    
    ui->setupUi(this);
    
    QSqlDatabase bancoDeDados = QSqlDatabase::addDatabase("QSQLITE");
    
    QString caminho = qApp->applicationDirPath();
    
    bancoDeDados.setDatabaseName(caminho + "/bancos/dbagenda.db3"); // Link do arquivo, melhor colocar este na pasta do projeto
    
    if(!bancoDeDados.open()) {
        ui->lblCon->setText("Não foi Possível Conectar ao Banco!");
    }
    else {
        ui->lblCon->setText("Banco de Dados Aberto com Sucesso!");
    }
    
    

    PS: Podemos também usar imagens para indicar se a conexão está ativa, para isso crie um arquivo de recursos, salve as imagens e altere as linhas assim:

    
    if(!bancoDados.open()) {
        QPixmap led(":/imgs/imagens/led-red.png");
        
        ui->lblImg->setPixmap(led);
    }
    else {
        QPixmap led(":/imgs/imagens/led-green.png");
        
        ui->lblImg->setPixmap(led);
    }
    
    

    Podemos também criar as tabelas via programação, basta colocar isso no construtor, dentro do else:

    
    // Isso é para caso queira criar a tabela via programação:
    QSqlQuery query;
    
    QString tabela = "-- Coloque o conteúdo da criação de tabela aqui";
    
    query.exec(tabela);
    
    

    PS: Ao testar o programa, esqueça da variável caminho e coloque o caminho completo onde está o arquivo para não dar erros de conexão do banco, por exemplo:

    
    bancoDeDados.setDatabaseName("C:/Meus Projetos/QT/AgendaComDB/bancos/dbagenda.db3");
    
    

    Crie na janela login os labels e os line edit para login e senha (mude o echoMode para password), e um botão, alinhe eles nos layouts e mude seus names.

    PS: No exemplo acima seria para trabalhar com SQLite, se for usar outro banco de dados como o PostgreSQL ou o MySQL, coloque a sigla correspondente a ele, que estão listadas aqui: https://doc.qt.io/qt-5/sql-driver.html

    Esse seria um exemplo de conexão com MySQL:

    
    JanelaLogin::JanelaLogin(QWidget *parent) : QMainWindow(parent), ui(new Ui::JanelaLogin) {
        ui->setupUi(this);
        
        QSqlDatabase bancoDeDados = QSqlDatabase::addDatabase("QMYSQL");
    
        bancoDeDados.setHostName("localhost");
        bancoDeDados.setUserName("root");
        bancoDeDados.setPassword("");
        bancoDeDados.setDatabaseName("dbagenda");
    
        if(!bancoDeDados.open()) {
            ui->lblCon->setText("Não foi Possível Conectar ao Banco!");
        }
        else {
            ui->lblCon->setText("Banco de Dados Aberto com Sucesso!");   
        }
    }
    
    

    Tela de Login e Base da Janela Principal

    Crie no projeto, uma nova janela, indo em Qt, Qt Designer Form Class e Dialog without Buttons (ou Main Window). Coloque o nome FormPrincipal

    No janelalogin.h, coloque o include para formprincipal.h.

    Coloque um login e senha dentro do SQLite usando o insert, e adicione o slot clicked do botão login com esse código:

    
    void JanelaLogin::on_btnEntr_clicked() {
        QString username = ui->txtLogin->text().trimmed();
        QString senha = ui->txtSenha->text().trimmed();
    
        if(!bancoDeDados.isOpen()) { // Recorte a declaração da variável bancoDeDados e coloque como global, na classe JanelaLogin, deixando a inicialização no construtor.
            qDebug() << "Banco de Dados Não está Aberto!";
    
            return;
        }
    
        QSqlQuery query;
    
        QString consulta = "select * from admin where username = ? and senha = ?";
    
        query.prepare(consulta);
    
        query.bindValue(0, username);
        query.bindValue(1, senha);
    
        if(query.exec()) {
            int cont = 0;
    
            while(query.next()) {
                cont++;
            }
    
            if(cont == 1) {
                this->close();
    
                FormPrincipal princ;
    
                princ.setModal(true);
                princ.exec();
    
                /*
                No caso de Main Window
    
                FormPrincipal *princ = new FormPrincipal(this);
    
                princ->show();
                */
            }
            else {
                ui->lblCon->setText("Login não Efetuado!");
    
                ui->txtLogin->clear();
                ui->txtSenha->clear();
    
                ui->txtLogin->setFocus();
            }
        }
    }
    
    

    PS: Diferente de outras linguagens, o índice das interrogações começam em 0, e não em 1. Essas interrogações são consultas preparadas para evitar SQL Injection.

    O recomendado é colocar a senha criptografada, nesse caso colocamos no SQLite o hash da senha (por exemplo, em SHA-1), e no código acima alteramos assim:

    
    QString username = ui->txtLogin->text().trimmed();
    QString senha = ui->txtSenha->text().trimmed();
    
    QString encripta = QString(QCryptographicHash::hash(senha.toStdString().c_str(), QCryptographicHash::Md5).toHex()); // Inclua QCryptographicHash
    
    

    As opções são várias, as mais usadas são Md5, Sha1 e Sha256.

    Aí nos bindValue basta trocar o senha por encripta, assim:

    
    query.bindValue(0, username);
    query.bindValue(1, encripta);
    
    

    Inserindo Registros na Tabela do Banco de Dados SQL

    Crie uma tabela com esses dados:

    
    create table if not exists contato (
        id integer not null primary key autoincrement,
        nome varchar(30),
        telefone varchar(15),
        email varchar(50)
    );
    
    

    Adicione um QT Designer Form Class do tipo Dialog without Buttons (ou Main Window) com o nome NovoContato.

    No formulário principal, coloque os botões, com os textos adicionar contato e pesquisar contato, altere os names dele também.

    No código do formprincipal.h, dê o include do novocontato.h. Adicione o slot clicked no botão adicionar do formulário principal e coloque esse código:

    
    NovoContato novoCont;
        
    novoCont.exec();
    
    

    No caso de Main Window:

    
    NovoContato *novoCont = new NovoContato(this);
        
    novoCont->show();
    
    

    No formulário de Novo contato, coloque três labels, três line edits, um botão para gravar e um para cancelar. Mude os labels, os names dos campos e botões, e coloque os layouts para alinhar eles.

    Coloque o slot clicked do botão gravar e coloque esse código:

    
    void NovoContato::on_btnGrav_clicked() {
        QString nome = ui->txtNome->text().trimmed();
        QString tel = ui->txtTel->text().trimmed();
        QString mail = ui->txtMail->text().trimmed();
    
        QSqlQuery query; // Inclua QtSql
        
        QString consulta = "insert into contato (nome, telefone, email) values (?, ?, ?)";
    
        query.prepare(consulta);
    
        query.bindValue(0, nome);
        query.bindValue(1, tel);
        query.bindValue(2, mail);
        
        if(query.exec()) {
            QMessageBox::information(this, "Info", "Registro Gravado com Sucesso!"); // Inclua QMessageBox
    
            ui->txtNome->clear();
            ui->txtTel->clear();
            ui->txtMail->clear();
    
            ui->txtNome->setFocus();
        }
        else {
            qDebug() << "Erro ao Inserir Registro"; // Inclua QDebug
        }
    }
    
    

    Inserindo Registro do Banco de Dados no QTableWidget

    Adicione no projeto, um Qt Designer Form Class, Dialog without Buttons (ou Main Window), com o nome PesquisaContato.

    Coloque nesse novo formulário, um label, um line edit, um button (pra filtrar) e um table widget abaixo deles, e abaixo deles dois botões (pra excluir e editar). Alinhe eles no Layout e mude os names e os textos.

    No formulário principal, coloque o slot clicked do botão Pesquisar Contato e coloque esse código:

    
    void FormPrincipal::on_btnPesq_clicked() {
        PesquisaContatos novoPesq; // Inclua o header de pesquisacontatos
        
        novoPesq.exec();
    }
    
    

    No caso de Main Window:

    
    void FormPrincipal::on_btnPesq_clicked() {
        PesquisaContatos *novoPesq = new PesquisaContatos(this); // Inclua o header de pesquisacontatos
        
        novoPesq->show();
    }
    
    

    Adicione alguns contatos na tabela contatos. No formulário cpp de Pesquisa Contato, faça os includes de QtSql e QMessageBox. E no construtor dele coloque isso:

    
    PesquisaContatos::PesquisaContatos(QWidget *parent) : QDialog(parent), ui(new Ui::PesquisaContatos) {
        ui->setupUi(this);
    
        QSqlQuery query; // Inclua QtSql
        QString sql = "select * from contato";
    
        query.prepare(sql);
    
        if(query.exec()) {
            int linha = 0; // Contador de linhas, a partir do zero
    
            ui->tbList->setColumnCount(4); // Quantidade de Colunas exibidas
    
            while(query.next()) {
                ui->tbList->insertRow(linha); // Contador vai dentro do método
                ui->tbList->setItem(linha, 0, new QTableWidgetItem(query.value(0).toString())); // Números das colunas, a partir do zero
                ui->tbList->setItem(linha, 1, new QTableWidgetItem(query.value(1).toString()));
                ui->tbList->setItem(linha, 2, new QTableWidgetItem(query.value(2).toString()));
                ui->tbList->setItem(linha, 3, new QTableWidgetItem(query.value(3).toString()));
    
                ui->tbList->setRowHeight(linha, 20); // Altura da linha
    
                linha++;
            }
        }
        else {
            QMessageBox::critical(this, "Erro", "Erro ao Pesquisar Tabela de Contatos"); // Inclua QMessageBox
        }
    }
    
    

    QTableWidget Formatação e Comando Delete

    No construtor de pesquisacontatos.cpp, abaixo do While, coloque esse código:

    
    ui->tbList->setColumnWidth(0, 30); // Os parâmetros são coluna e tamanho
    ui->tbList->setColumnWidth(1, 150);
    ui->tbList->setColumnWidth(3, 250);
    
    QStringList cabecalhos = {"ID", "Nome", "Telefone", "E-mail"}; // Tipo um array
    
    ui->tbList->setHorizontalHeaderLabels(cabecalhos); // Define os cabecalhos da tabela
    ui->tbList->setEditTriggers(QAbstractItemView::NoEditTriggers); // Bloqueia a edição
    ui->tbList->setSelectionBehavior(QAbstractItemView::SelectRows); // Seleciona a linha inteira ao clicar
    ui->tbList->verticalHeader()->setVisible(false); // Oculta os números da esquerda
    ui->tbList->setStyleSheet("QTableView {selection-background-color: blue}"); // Muda a cor do item selecionado, em CSS.
    
    

    No formulário de pesquisacontato, adicione o slot clicked do botão excluir e coloque esse código:

    
    void PesquisaContatos::on_btnExcl_clicked() {
        int linha = ui->tbList->currentRow(); // Pega a linha atual (selecionada), retorna -1 com nenhuma selecionada
        int id = ui->tbList->item(linha, 0)->text().toInt(); // Número da coluna, no caso, a zero. Atenção as conversões
        
        QSqlQuery query; // Inclua QtSql
        QString sql = "delete from contato where id = ?";
    
        query.prepare(sql);
        
        query.bindValue(0, id);
        
        if(query.exec()) {
            ui->tbList->removeRow(linha);
    
            QMessageBox::information(this, "Info", "Contato Excluído!"); // Inclua QMessageBox
        }
        else {
            QMessageBox::critical(this, "Erro", "Erro ao Excluir o Registro!");
        }
    }
    
    

    PS: Para limpar uma table widget, pode usar o método setRowCount(0) no objeto QTableWidget, e podemos permitir a ordenação por colunas colocando no construtor o método setSortingEnabled(true) no construtor do mesmo.