sexta-feira, 9 de setembro de 2011

Tutorial wxWidgets e sqlite3 parte 9 - Inserindo valores no banco de dados


Hoje vamos ver como inserir valores no banco de dados.

Primeiro, devemos entender como o processo de inserção será feito pelo programa:

Existem dois campos do tipo wxTextCtrl no wxFrame que controla a aplicação, nós pegaremos os valores dessas caixas de texto, veremos primeiro se o nome está em branco e se a idade realmente é um número, se as duas afirmações forem verdadeiras executamos a função que insere os valores no banco de dados, se não, cancelamos a função e avisamos o usuário que os dados estão incompletos ou errados.

Mas vamos lembrar uma coisa, quando clicamos no botão salvar, podemos ter uma ação de inserção ou de edição, para isto, temos a variável de controle chamada ID, que criamos no frame principal, veja que ela inicia com o valor -1, então, sempre que tivermos este valor, a ação será de inserção.

Vamos lembrar como ficaria o código SQL para inserirmos um valor na nossa tabela contatos:

INSERT INTO contatos(ID, NOME, IDADE) VALUES(NULL, 'NOME DO CONTATO', 1);

Vejam que uso apóstrofo entre valores do tipo VARCHAR, e passamos o ID que é chave primária como NULL.

O nome do contato, será o valor que foi digitado na caixa de texto Nome e sua idade será o valor que está na caixa de texto Idade.

Para fazer esta inserção vamos criar uma função que vai pegar estes dois valores e verificar se estão corretos e fazer a inserção, ficará assim:

Em sqlf.h digite:

sqlf.h
//Aqui escrevo uma função que vai receber o nome e a idade como parametros...
void InsertInDB(wxString nome, wxString idade);

Agora vamos implementá-la em sqlf.cpp, digite:

sqlf.cpp
//Vamos Implementá-la
void InsertInDB(wxString nome, wxString idade)
{
    //Primeiro vejo se o nome ou idade estão em branco
    if(nome.IsEmpty() || idade.IsEmpty())
    {
        //Aviso ao usuário que algum dado está em branco:
        wxMessageBox(wxT("Nenhum campo pode estar em branco!"));
        //Cancelo a função...
        return;
    }

    //Agora preciso ver se a idade é um número...
    //Crio um long int
    long int confere_idade;

    //Tento converter a string idade em um número...
    if(!idade.ToLong(&confere_idade))
    {
        //Se não conseguir, significa que ele não é um inteiro...
        //Aviso o usuário...
        wxMessageBox(wxT("O valor da idade (") + idade + wxT(") não é um número"));
        //Cancelo a função...
        return;
    }

    //Se chegamos até aqui, é porque tudo está correto...
    //Vamos abrir o banco de dados:
    wxSQLite3Database *db = OpenDB(GetExecPath() + wxT("/agenda.db3"));

    //Agora vamos montar o sql para inserir os dados...
    wxString SQL = wxT("INSERT INTO contatos(ID, NOME, IDADE) VALUES(NULL, '");
    SQL += nome + wxT("', ");
    SQL += idade + wxT(");");

    //Reparem que adiciono os apóstrofos apenas nos campos VARCHAR...
    //Tenham muito cuidado quando montarem comandos SQL, para não adicionarem
    //valores incorretos, como virgulas após o ultimo campo
    //esquecerem-se de fechar parenteses, etc...

    //uma maneira simples é fazer o seguinte...
    //Escreva o comando todo SQL...

    //wxString SQL = wxT("INSERT INTO contatos(ID, NOME, IDADE) VALUES (NULL, 'NOME', IDADE);");

    //Agora adicione as variáveis no lugar dos valores com os sinais de concatenação:

    //wxString SQL = wxT("INSERT INTO contatos(ID, NOME, IDADE) VALUES (NULL, ' + nome + ', + idade + );");

    //Antes de cada + à esquerda da variável adicione ") e depois de cada + à direita da variável adicione wxT("

    //wxString SQL = wxT("INSERT INTO contatos(ID, NOME, IDADE) VALUES (NULL, '") + nome + wxT("',") + idade + (");");

    //Agora executo a função ExecuteUpdate, que vimos no tutorial anterior, passando como
    //parâmetro a wxString SQL...
    db->ExecuteUpdate(SQL);

    //Fecho db...
    CloseDB(db);
}

E pra finalizarmos, vamos chamar esta função no evento OnClickSalvar() do frame principal:

Veja que já adicionei a estrutura condicional para sabermos se está em edição ou inserção:

Em framep.cpp digite:

framep.cpp
//Aqui eu inicio a implementação do evento para salvar ou editar um registro...
void wxFramePrincipal::OnClickSalvar(wxCommandEvent& event)
{
    //Vamos, primeiro, verificar qual operação será feita
    //Inserção ou Edição
    if(ID == -1)
    {
        //Se a variável ID for = -1, é porque estamos em inserção...
        //Vamos pegar os valores do campo nome...
        wxString get_nome = nome->GetValue();
        //...agora pegamos a idade...
        wxString get_idade = idade->GetValue();

        //E passamos as duas como parâmetros para a função InsertInDB()...
        InsertInDB(get_nome, get_idade);
    }
    else
    {
    }
}

Vamos testar a função, abrindo o terminal ou o prompt de comando do Windows:

Abra o banco de dados com o comando:
> sqlite3 caminho/para/o/banco_de_dados/agenda.db3


Agora abra o sistema e adicione alguns valores, veja que após inserirmos os valores, os campos continuam preenchidos, iremos alterar isto nos próximos tutoriais.


Agora volte para o terminal e faça uma seleção na tabela contatos:

>SELECT * FROM contatos;


Vejam que os registros já estão lá.


Dúvidas, deixem nos comentários.

Os arquivos alterados completos:

sqlf.h
//ARQUIVO DO BLOG - http://wxnewbie.blogspot.com
//TUTORIAL wxWidgets + sqlite3 usando wxSqlite3

#ifndef SQLF_H_INCLUDED
#define SQLF_H_INCLUDED

#include <wx/wx.h>
#include <wx/wxsqlite3.h>
#include <wx/stdpaths.h>

wxString GetExecPath();
//Nesta primeira função, iremos abrir um banco de dados indicado pelo
//parâmetro caminho e retornar um ponteiro para wxSQLite3Database...
//Se o banco de dados não existir, será criado um...
wxSQLite3Database *OpenDB(wxString caminho);
//Aqui iremos apenas fechar o mesmo...
//Isto é necessário, pois liberaremos o arquivo para novos acessos...
void CloseDB(wxSQLite3Database* db);

//Esta função será usada para criar o nosso banco de dados
//e também para criar a tabela contatos.
//Ela será executada apenas uma vez...
void CreateDBAgenda();

//Aqui escrevo uma função que vai receber o nome e a idade como parametros...
void InsertInDB(wxString nome, wxString idade);

#endif // SQLF_H_INCLUDED


sqlf.cpp
//ARQUIVO DO BLOG - http://wxnewbie.blogspot.com
//TUTORIAL wxWidgets + sqlite3 usando wxSqlite3

#include "sqlf.h"

//Função para pegar o diretório da aplicação, já explicada no blog...
wxString GetExecPath()
{
 wxString retorno;
 retorno = wxStandardPaths::Get().GetExecutablePath();
 retorno = wxPathOnly(retorno);
 return retorno;
}

//Vamos implementar nossa função OpenDB...
wxSQLite3Database *OpenDB(wxString caminho)
{
    //Aqui eu crio um ponteiro para um wxSQLite3Database chamado db...
    //É ele que nós retornaremos na função...
    wxSQLite3Database *db = new wxSQLite3Database();

    //Aqui uso a função Open, passando como parâmetro o caminho para o banco de dados...
    //O interessante aqui é vermos que se existir um banco de dados neste lugar a função
    //irá abrir o mesmo, se não existir o banco de dados será criado...
    db->Open(caminho);

    //Vocês poderão ter um problema ao executar esta função, dizendo que Open possui mais de
    //um parâmetro, se isto acontecer, basta usá-la desta maneira:

    //db->Open(caminho, wxEmptyString);

    //O segundo parametro seria a senha para o banco de dados,
    //se estivessemos usando criptografia no mesmo...

    //retornamos o db...
    return db;
}

//Aqui vamos fechar a "conexão" com o banco de dados...
void CloseDB(wxSQLite3Database* db)
{
    //Vemos se db é verdadeiro...
    assert(db != NULL);
    //Fechamos db com o comando Close();
    db->Close();

    //Deletamos db da memória...
    delete db;
}

void CreateDBAgenda()
{
    //Primeiro, vamos pegar o diretório da aplicação mais o nome do banco de dados...
    wxString conf_path = GetExecPath() + wxT("/agenda.db3");

    //Agora vamos verificar se o arquivo já existe...
    //Se existir, paro a execução da função...
    if(wxFileExists(conf_path))
    {
        return;
    }

    //Se ele não existir crio um wxSQLite3Database com este caminho...
    wxSQLite3Database *db = OpenDB(conf_path);

    //Ok, agora criamos um sql com o comando de criação da nossa tabela
    //CREATE TABLE contatos(
    //ID INTEGER PRIMARY KEY,
    //NOME VARCHAR(50),
    //IDADE INTEGER
    //);

    //Vamos adicionar isto em uma wxString

    wxString SQL = wxT("CREATE TABLE contatos(\n");
    SQL += wxT("ID INTEGER PRIMARY KEY,\n");
    SQL += wxT("NOME VARCHAR(50),\n");
    SQL += wxT("IDADE INTEGER\n");
    SQL += wxT(");");

    //Agora vamos usar ExecuteUpdate para executar este SQL...
    //Usamos ExecuteUpdate para criarmos tabelas, views, triggers...
    //Inserir registros no banco de dados...
    //Editar registros no banco de dados...
    //Excluir registros no banco de dados...
    //Não use ExecuteUpdate para seleções...
    db->ExecuteUpdate(SQL);

    //Fechamos a conexão com o banco de dados...
    CloseDB(db);
}

//Vamos Implementá-la
void InsertInDB(wxString nome, wxString idade)
{
    //Primeiro vejo se o nome ou idade estão em branco
    if(nome.IsEmpty() || idade.IsEmpty())
    {
        //Aviso ao usuário que algum dado está em branco:
        wxMessageBox(wxT("Nenhum campo pode estar em branco!"));
        //Cancelo a função...
        return;
    }

    //Agora preciso ver se a idade é um número...
    //Crio um long int
    long int confere_idade;

    //Tento converter a string idade em um número...
    if(!idade.ToLong(&confere_idade))
    {
        //Se não conseguir, significa que ele não é um inteiro...
        //Aviso o usuário...
        wxMessageBox(wxT("O valor da idade (") + idade + wxT(") não é um número"));
        //Cancelo a função...
        return;
    }

    //Se chegamos até aqui, é porque tudo está correto...
    //Vamos abrir o banco de dados:
    wxSQLite3Database *db = OpenDB(GetExecPath() + wxT("/agenda.db3"));

    //Agora vamos montar o sql para inserir os dados...
    wxString SQL = wxT("INSERT INTO contatos(ID, NOME, IDADE) VALUES(NULL, '");
    SQL += nome + wxT("', ");
    SQL += idade + wxT(");");

    //Reparem que adiciono os apóstrofos apenas nos campos VARCHAR...
    //Tenham muito cuidado quando montarem comandos SQL, para não adicionarem
    //valores incorretos, como virgulas após o ultimo campo
    //esquecerem-se de fechar parenteses, etc...

    //uma maneira simples é fazer o seguinte...
    //Escreva o comando todo SQL...

    //wxString SQL = wxT("INSERT INTO contatos(ID, NOME, IDADE) VALUES (NULL, 'NOME', IDADE);");

    //Agora adicione as variáveis no lugar dos valores com os sinais de concatenação:

    //wxString SQL = wxT("INSERT INTO contatos(ID, NOME, IDADE) VALUES (NULL, ' + nome + ', + idade + );");

    //Antes de cada + à esquerda da variável adicione ") e depois de cada + à direita da variável adicione wxT("

    //wxString SQL = wxT("INSERT INTO contatos(ID, NOME, IDADE) VALUES (NULL, '") + nome + wxT("',") + idade + (");");

    //Agora executo a função ExecuteUpdate, que vimos no tutorial anterior, passando como
    //parâmetro a wxString SQL...
    db->ExecuteUpdate(SQL);

    //Fecho db...
    CloseDB(db);
}


framep.cpp
//ARQUIVO DO BLOG - http://wxnewbie.blogspot.com
//TUTORIAL wxWidgets + sqlite3 usando wxSqlite3

#include "framep.h"
#include "sqlf.h"

wxFramePrincipal::wxFramePrincipal():wxFrame(NULL, wxID_ANY, wxT("Teste Tutorial Sqlite3"))
{
    //Altero a cor do background do Frame
    this->SetBackgroundColour(*wxWHITE);

    //Meu BoxSizer Principal...
    wxBoxSizer *boxp = new wxBoxSizer(wxVERTICAL);

    //Inicio a construção do grid...
    lista_contatos = new wxGrid(this, ID_GRID);

    //Começo com 0 linhas e 3 colunas, lembre-se que o número de colunas deve ser igual ao numero de campos
    //Da view que iremos carregar ou do comando select que iremos carregar...
    lista_contatos->CreateGrid(0, 3);

    //Aqui altero o valor dos rótulos de cada coluna...
    //Nunca se esqueça, o vetor começa em 0, tanto para colunas como para linhas...
    lista_contatos->SetColLabelValue(0, wxT("ID"));
    lista_contatos->SetColLabelValue(1, wxT("Nome"));
    lista_contatos->SetColLabelValue(2, wxT("Idade"));

    //Altero a largura padrão do rótulo da linha para 25px...
    //Altero a altura padrão do rótulo da coluna para 25px...
    lista_contatos->SetRowLabelSize(25);
    lista_contatos->SetColLabelSize(25);

    //Desabilito a edição dos valores no grid, a alteração de valores será feita
    //pelos wxTextCtrl's
    lista_contatos->EnableEditing(false);

    //Adiciono o grid no BoxSizer principal...
    boxp->Add(lista_contatos, 1, wxEXPAND, 0);

    //Aqui eu adiciono um separador...
    boxp->Add(0, 0, 0, wxALL, 10);

    //Aqui crio um BoxSizer para arranjar os campos de preenchimento de valores...
    wxBoxSizer *box_texts = new wxBoxSizer(wxVERTICAL);

    //o rótulo para o campo nome...
    label_nome = new wxStaticText(this, wxID_ANY, wxT("Nome"));
    //adiciono o rótulo no box dos valores de preenchimento...
    box_texts->Add(label_nome, 0, wxALL, 2);

    //Faço o mesmo que fiz anteriormente para todos os outros campos...
    nome = new wxTextCtrl(this, wxID_ANY, wxEmptyString ,wxDefaultPosition, wxSize(200, -1));
    box_texts->Add(nome, 0, wxALL, 5);

    label_idade = new wxStaticText(this, wxID_ANY, wxT("Idade"));
    box_texts->Add(label_idade, 0, wxALL, 2);

    idade = new wxTextCtrl(this, wxID_ANY, wxEmptyString ,wxDefaultPosition, wxSize(120, -1));
    box_texts->Add(idade, 0, wxALL, 5);

    //Aqui adiciono o box dos campos de preenchimento no box principal...
    boxp->Add(box_texts, 0, wxLEFT, 40);

    //Agora um box para arranjar os botões...
    wxBoxSizer *box_btns = new wxBoxSizer(wxHORIZONTAL);

    //Um separador...
    box_btns->Add(0, 0, 0, wxLEFT, 40);

    //Botão salvar...
    salvar = new wxButton(this, ID_SALVAR, wxT("Salvar"));
    //Adiciono ao box dos botões...
    box_btns->Add(salvar, 0, wxALL, 5);

    limpar = new wxButton(this, ID_LIMPAR, wxT("Limpar Campos"));
    box_btns->Add(limpar, 0, wxALL, 5);

    deletar = new wxButton(this, ID_DELETAR, wxT("Deletar"));
    box_btns->Add(deletar, 0, wxALL, 5);

    //Adiciono o box dos botões ao box principal...
    boxp->Add(box_btns, 1, wxEXPAND, 0);

    //"Digo" ao meu frame que o boxp é o box principal...
    this->SetSizer(boxp);

    //Aqui apenas faço com que tudo seja arranjado de maneira correta...
    this->Layout();

    //Seto o ID como -1 para saber que inicio em modo de inserção...
    ID = -1;
}

//Aqui minha tabela de eventos declarada...
BEGIN_EVENT_TABLE(wxFramePrincipal, wxFrame)
//Veja que digo para cada evento, que o controle que estiver com
//determinado id, é o que será responsável por executá-lo
//No exemplo de salvar:
//Eu digo que é um evento do tipo EVT_BUTTON, ou seja, um evento executado por um botão...
//O botão responsável pelo evento é o que tiver o identificador: ID_SALVAR
//e o evento que ele vai executar é o OnClickSalvar...

//É muito importante o entendimento desta parte para não acontecer nada de errado...
EVT_BUTTON(ID_SALVAR, wxFramePrincipal::OnClickSalvar)
EVT_BUTTON(ID_LIMPAR, wxFramePrincipal::OnClickLimpar)
EVT_BUTTON(ID_DELETAR, wxFramePrincipal::OnClickDeletar)

//Quando você for criar um evento para grid's repare que alguns levam um CMD no nome e outros não...
//Se você estiver criando uma classe derivada de wxGrid, vc não usa o comando que contém o CMD
//Veja que este comando sem CMD como é o caso de EVT_GRID_CELL_LEFT_DCLICK (comando que é executado
//quando dou 2 cliques em uma célula) não recebe ID nenhum como parâmetro...
//agora se eu for executar o mesmo comando usando um wxGrid como controle no meu frame ou dialogo
//eu uso o comando com CMD como é o caso do evento abaixo...
EVT_GRID_CMD_CELL_LEFT_DCLICK(ID_GRID, wxFramePrincipal::OnDoubleClickCell)
END_EVENT_TABLE()

//Aqui eu inicio a implementação do evento para salvar ou editar um registro...
void wxFramePrincipal::OnClickSalvar(wxCommandEvent& event)
{
    //Vamos, primeiro, verificar qual operação será feita
    //Inserção ou Edição
    if(ID == -1)
    {
        //Se a variável ID for = -1, é porque estamos em inserção...
        //Vamos pegar os valores do campo nome...
        wxString get_nome = nome->GetValue();
        //...agora pegamos a idade...
        wxString get_idade = idade->GetValue();

        //E passamos as duas como parâmetros para a função InsertInDB()...
        InsertInDB(get_nome, get_idade);
    }
    else
    {
    }
}

//Aqui o evento que vai limpar os campos...
void wxFramePrincipal::OnClickLimpar(wxCommandEvent& event)
{
    //...Os comandos que usaremos aqui, será escrito depois...
}

//Aqui o evento quando eu clicar no botão deletar...
void wxFramePrincipal::OnClickDeletar(wxCommandEvent& event)
{
    //...Os comandos que usaremos aqui, será escrito depois...
}

//Aqui o evento que será exxecutado
//quando eu der 2 cliques em uma célula...
void wxFramePrincipal::OnDoubleClickCell(wxGridEvent& event)
{
    //...Os comandos que usaremos aqui, será escrito depois...
}

//Esta função eu vou usar para limpar os campos
//como eu precisarei fazer isto sempre que eu completar uma alteração
//vou escrever este código em uma função em separado...
void wxFramePrincipal::LimparCampos()
{
    //...Os comandos que usaremos aqui, será escrito depois...
}

//Aqui vou conferir os campos para ver se o usuário digitou algo errado...
bool wxFramePrincipal::ConfereCampos()
{
    //...Os comandos que usaremos aqui, será escrito depois...
    return true;
}


No próximo tutorial, vamos exibir os valores inseridos no wxGrid.

Até a próxima.

0 comentários:

Postar um comentário