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!");
}
}
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);
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
}
}
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
}
}
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.