terça-feira, 15 de novembro de 2011

Tutorial Lazarus e Firebird – 2 - Criando um projeto no Lazarus

Por ser um tutorial mais básico, vou deixá-lo apenas em video, no próximo iremos criar a janela Splash

segunda-feira, 31 de outubro de 2011

Tutorial Lazarus e Firebird – 1 - Instalando o Lazarus no Debian Squeeze



Hoje iremos iniciar os tutoriais sobre a IDE Lazarus, que pode ser comparada ao Delphi, principalmente em relação a sua versão 7, a vantagem aqui é que Lazarus é gratuito e pode ser usado em outras plataformas além do Windows.

Para a instalação no Debian Squeeze, existe apenas um pequeno problema na quebra de uma dependência no pacote fpc-source, para a instalação completa e sem problemas vamos seguir os passos seguintes:

Abra o gerenciador de pacotes


Na busca rápida, digite Lazarus


Procure o pacote lazarus-ide e marque para instalação


As dependências serão exibidas, confirme clicando em “Marcar”


Clique em Aplicar na toolbar do Synaptic


Depois aplicar na janela que se abre


Aguarde a instalação


Assim que a mesma estiver completa, abra o Lazarus em Aplicativos → Desenvolvimento → Lazarus



Quando vocês tentarem abrir o Lazarus um erro será exibido, é a dependência comentada acima


Veja que não é possível criar eventos graças a esse problema


Para corrigir, volte ao Synaptic e marque fpc-source para instalação


Aguarde pelo fim da instalação e tente abrir o Lazarus novamente, o problema estará resolvido.

Vejam que esta não é a única maneira de se instalar o Lazarus, você pode instalar o mesmo pelo matapacote existente no repositório ou também fazendo o download do pacote *.deb da última versão do Lazarus na página do projeto no SourceForge.

Até a próxima

 Vídeo com a explicação:

sexta-feira, 28 de outubro de 2011

Invasão Feminina.

Convidada pelo Ilustríssimo Sr. Porcena para vos passar meu humilde conhecimento em informática, já lhes adianto que não sei (nem pretendo saber) absolutamente nada de programação.

Portanto minhas visitas aqui serão exclusivamente para falar sobre acessórios Hi-Tech para computadores e inovações eletrônicas em geral (:

Hoje queria compartilhar um acessório que acho super legal para todos que passam várias horas a fio (como os programadores, por exemplo) em frente ao computador: os Foot Warmers e Hand Warmers. 

Se tratam de almofadinhas ou pantufas confortáveis e com um sistema de aquecimento através de USB, permitindo assim que você mantenha seus pés e mão aquecidos, nos dias mais frios.


 Aquecedores de Mão

Tá, mas estamos entrando na estação mais quente do ano. Porque eu compraria isso agora? Simples!!! Porque todos os artigos de Inverno estão na promoção e você pagará por esses itens fofos e úteis entre $ 15,00 e 20,00 (dólares).

São vários modelos disponíveis, discretos ou chamativos.



 Pantufa






 Botinha





Esses produtos podem ser encontrados no E-Bay e em um site que gosto muito chamado Ioffer.

Problemas com o case sensitive do Firebird.

Hoje estava procurando algumas coisas sobre o comando INNER JOIN no Firebird e achei muitas pessoas com dúvida sobre este problema.
No Firebird, este problema pode ser resolvido facilmente usando o comando UPPER, como proceder?
Simples…
Imagine uma situação assim:
Tabela contatos:

Campo Valor
Nome José
Apelido

 Queremos selecionar este contato, mas podemos ter um usuário preguiçoso que vai digitar o seguinte na consulta:
SELECT * FROM contatos WHERE Nome=‘josé’ AND Apelido=‘zé’;

O que esta consulta retornará no Firebird?

Nada… Pois ele é case-sensitive, ou seja, José é diferente de jOsé que é diferente de josé… Ele diferencia letra maiúscula de letra minúscula.

Vamos resolver este problema?

SELECT * FROM contatos WHERE UPPER(Nome)=UPPER(‘José’) AND UPPER(Apelido)=UPPER(‘zé’);

A consulta retornará os valores que queríamos.

O que este comando faz?

Ele vai converter todos os caracteres do campo selecionado em UPPER() para maiúsculos e na string de comparação idem. No nosso caso ele converteu a string original que era José para JOSÉ e a string de consulta que era josé para JOSÉ, o mesmo para Zé e zé.

Deste jeito, você consegue “burlar” o problema de sensibilidade a caixa do
Firebird, espero ter ajudado.

Até a próxima.

Usando comando INSERT com SELECT no FireBird

Aqui vai um exemplo simples de como usar os dois comandos juntos para inserir dados que estão em outra tabela.

Vamos usar um caso em que tenhamos estas duas tabelas:

Tabela Cliente (TAB_CLI):
ID_CLIENTE
NOME_CLIENTE
TEL_CLIENTE

Tabela Vendas (TAB_VENDA):
ID_VENDA
ID_CLIENTE
PRODUTO
VALOR

Para facilitar na hora de escolher qual cliente efetuou a compra, podemos passar o nome do cliente como parâmetro e inserir seu ID automaticamente.
Fica assim:

insert into TAB_VENDA (ID_VENDA, ID_CLIENTE, PRODUTO, VALOR) VALUES (1, (select ID_CLIENTE from TAB_CLI where NOME_CLIENTE =’JOÃO’), ‘PRODUTO 1′, 10);

No local onde será inserido o valor do cliente coloca-se um select que retornará seu ID pelo nome passado na cláusula where, note que este select funcionará se não houver em registros duplicados, se existirem dois clientes com o nome ‘João’ você poderá adicionar a venda para outro cliente com o mesmo nome. Para corrigir este problema você poderá passar outro parâmetro junto ao nome, que não tenha duplicação, como por exemplo, o RG ou CPF do mesmo.

Obs.: O mesmo comando rodou sem problemas no PSQL.

Abraços até a próxima.

terça-feira, 25 de outubro de 2011

Tutoriais de Lazarus com Firebird

Nos próximos dias, estarei começando alguns tutoriais sobre o desenvolvimento com Lazarus, para quem não conhece a ferramenta aconselho dar uma olhada nessa explicação da Wikipédia.


Para a criação dos tutorias, eu irei usar o Debian como plataforma, também precisaremos do Firebird instalado, a idéia é termos uma noção de como fazer a comunicação entre aplicações feitas em Lazarus com esse banco de dados.

O cronograma será basicamente o seguinte:

Instalação do Lazarus no Debian Squeeze.
Criação de um projeto em Lazarus.
Criação do banco de dados em Firebird usando o FlameRobin.
Criação de uma janela Splash para o exemplo.
Criação do Menu Principal.
Criação dos Formulários de controle.

Se tudo correr bem, podemos tentar alguma coisa relacionada com relatórios e gráficos.

No próximo post começaremos com o projeto.

quarta-feira, 19 de outubro de 2011

Sequência de vídeos sobre imagens com wxWidgets

Desenhando uma imagem com wxWidgets - Parte 1



Desenhando uma imagem com wxWidgets - Parte 2


Desenhando uma imagem com wxWidgets - Parte3


Plano de fundo em um wxPanel

Dúvidas, postem nos comentários, até a próxima.

quarta-feira, 28 de setembro de 2011

Campo auto incremento no Firebird usando isql (Generator + Trigger)


Hoje vamos criar um campo auto incremento usando Generator e Trigger no Firebird, com o isql.

O que faremos é o seguinte, criar um GENERATOR para armazenar um valor para o campo ID da tabela depois um Gatilho para alterar o novo valor de ID quando inserirmos o registro.

Vamos abrir um terminal como root no Linux ou o Prompt de comando no Windows.

Abra a ferramenta isql com o comando

# no Linux
isql-fb


Agora vamos criar o banco de dados:

CREATE DATABASE “/home/alex/firebird_data/tutorial2.fdb” user “SYSDBA” password “senha”;

Criamos também a tabela:

CREATE TABLE TESTE_AI(
ID INTEGER NOT NULL PRIMARY KEY,
NOME VARCHAR(50) NOT NULL,
IDADE INTEGER NOT NULL
);

Agora vamos à criação do GENERATOR que controlará o auto incremento de ID.

CREATE GENERATOR GEN_ID_TESTE_AI;

O comando para a criação de Generators é simples:

CREATE GENERATOR NOME_GENERATOR;

Eu costumo usar GEN + Nome do campo + tabela, mas fica a cargo de cada um a escolha deste nome.

Agora vamos criar um Gatilho que vai incrementar o valor do ID.

Antes, vamos alterar o terminador padrão, que é “;” para outro caractere que não será usado no bloco de código do gatilho, no caso vou colocar um “!”. Qualquer outro caractere pode ser usado, mas você deve ter muito cuidado aqui, pois se usar algum que apareça no meio do caminho, seu comando será fechado e todo seu trabalho será perdido.

Usamos o comando SET TERM + o novo caractere que usaremos (no caso o “!”) e fechamos com o caractere terminador atual, no caso o “;”.

SET TERM !;

CREATE TRIGGER T_G_ID_TESTE_AI
FOR TESTE_AI
ACTIVE
BEFORE INSERT
POSITION 0
AS
BEGIN
     NEW.ID = GEN_ID(GEN_ID_TESTE_AI, 1);
END!


Nesta primeira linha crio o Gatilho, dando um nome para ele, no caso, usei o T (trigger) + G (porque ele está associado a um Generator), + Campo + Tabela).

CREATE TRIGGER T_G_ID_TESTE_AI

Na segunda linha uso o FOR para mostrar a qual tabela ele está relacionado, no caso TESTE_AI.

FOR TESTE_AI

Digo que quero que este Gatilho esteja ativado.

ACTIVE

Ele será executado antes de Inserir, quando executamos o comando Insert, antes dos dados serem salvos no banco, ele executa este comando.

BEFORE INSERT

Agora digo que ele será o primeiro a ser executado, isto é preciso quando temos mais de um gatilho sendo executado no mesmo ponto de alteração, então se eu tivesse outro gatilho nesta tabela para ser executado em BEFORE INSERT, eu uso este comando para controlar o fluxo de execução. POSITION 0 para o primeiro, POSITION 1 para o segundo, etc...

POSITION 0

Inicio o bloco de comandos

AS
BEGIN

Altero o valor do novo ID para o valor armazenado no Generator incrementando 1 ao mesmo usando GEN_ID.

Veja que aqui nesta linha, eu preciso fechá-la com o “;”, se não tivéssemos alterado o terminador de linha, o comando SQL seria fechado neste momento de forma incompleta e perderíamos todo o trabalho.

NEW.ID = GEN_ID(GEN_ID_TESTE_AI, 1);

Agora fecho o comando, veja que para fechar o comando SQL, agora eu uso o novo terminador que escolhemos no início do comando.

END!

Para não mantermos este terminador para os próximos comandos voltamos o mesmo para o “;”.

SET TERM ;!

Vamos testar o comando inserindo alguns valores:

INSERT INTO TESTE_AI VALUES(NULL, 'TESTE', 20);
INSERT INTO TESTE_AI VALUES(NULL, 'TESTE1', 20);
INSERT INTO TESTE_AI VALUES(NULL, 'TESTE2', 20);
INSERT INTO TESTE_AI VALUES(NULL, 'TESTE3', 20);
INSERT INTO TESTE_AI VALUES(NULL, 'TESTE4', 20);

Agora selecione os valores.

SELECT * FROM TESTE_AI;

Se alguma coisa der errada, tente refazer cada passo, entendendo o porque de cada comando.

Até a próxima.

terça-feira, 27 de setembro de 2011

Erro no Debian, wrong fs type, bad option, bad superblock on /dev/sdb1...

Após instalar o Debian 6.0 squeeze, eu fui montar uma das partições de um segundo HD que tenho no computador e este erro apareceu:

wrong fs type, bad option, bad superblock on /dev/sdb1,
missing codepage or helper program, or other error
In some cases useful info is found in syslog - try
dmesg | tail  or so.


Dei uma olhada no /etc/fstab e pra minha surpresa encontrei esta linha:

/dev/sdb1       /media/cdrom0   udf,iso9660 user,noauto     0       0

Vejam que no fstab, sdb1 está configurado como um cdrom...

Quando fiz minha primeira instalação do Debian, eu havia usado um CD como mídia, e isto não havia ocorrido, desta vez, eu usei o netinstall e não usei o CD como mídia, e sim um pendrive...

Para conseguir corrigir isto, apenas comentei esta linha no fstab:

Abra o terminal como root:

nano /etc/fstab

Comente a linha indicada:

#/dev/sdb1       /media/cdrom0   udf,iso9660 user,noauto     0       0

F2 para salvar

CTRL + X para sair

Pode fazer a mesma coisa com o gedit ou outro editor de texto que vocês possuam aí.

Tente montar o HD novamente, se não conseguir, tente Reiniciar e montar novamente.

Espero ter ajudado.

quinta-feira, 15 de setembro de 2011

A lista com todos os links do tutorial de wxWidgets + sqlite3

Configurações

Tutorial wxWidgets e sqlite3 parte 1 – Configurando sqlite3 no Windows

Tutorial wxWidgets e sqlite3 parte 4 – Compilando wxSqlite3 no Linux

Tutorial wxWidgets e sqlite3 parte 5 - Iniciando com o exemplo


Criando um banco de dados

Tutorial wxWidgets e sqlite3 parte 2 – Criando um banco de dados pelo prompt de comando.

Tutorial wxWidgets e sqlite3 parte 3 – Criando um banco de dados pelo Black Cat - SQLite3 database manager


Sistema em si

Tutorial wxWidgets e sqlite3 parte 6 - Criando o Projeto e a Interface do programa

Tutorial wxWidgets e sqlite3 parte 7 - Comunicando-se com um banco de dados

Tutorial wxWidgets e sqlite3 parte 8 - Criando um banco de dados e a tabela contatos

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

Tutorial wxWidgets e sqlite3 parte 10 - Selecionando valores e colocando em um wxGrid

Tutorial wxWidgets e sqlite3 parte 11 - Passando os dados do wxGrid para a edição

Tutorial wxWidgets e sqlite3 parte 12 - Limpando os Campos após alterações e aproveitando para acertar algumas coisas...

Tutorial wxWidgets e sqlite3 parte 13 - Editando valores no banco de dados

Tutorial wxWidgets e sqlite3 parte 14 - Excluindo registros


O download do código fonte comentado você pode fazer aqui.

Tutorial wxWidgets e sqlite3 parte 14 - Excluindo registros

Para finalizar o sistema, vamos escrever a função para deletar os registros.

Ela vai funcionar da seguinte maneira:

Vamos criar uma função que vai receber o ID do registro que está sendo editado, vamos passar este ID para um comando SQL, vamos chamar ExecuteUpdate(SQL).

Escreva a função:

sqlf.h
//Função para deletar um registro...
//Passo como parâmetro o ID do registro que será deletado...
void DeleteInDB(wxString ID);

sqlf.cpp
void DeleteInDB(wxString ID)
{
    //Abro o banco de dados
    wxSQLite3Database *db = OpenDB(GetExecPath() + wxT("/agenda.db3"));

    //SQL para deletar o registro...
    wxString SQL = wxT("DELETE FROM contatos WHERE ID=") + ID + wxT(";");

    //ExecuteUpdate para deletar o registro...
    db->ExecuteUpdate(SQL);

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

Agora vamos chamar esta função no frame principal, na função OnClickDelete.

Nó vamos confirmar com o usuário se ele quer mesmo que delete o registro, depois deletamos o registro.

framep.cpp
//Aqui o evento quando eu clicar no botão deletar...
void wxFramePrincipal::OnClickDeletar(wxCommandEvent& event)
{
    //Vamos verificar também se o registro está em modo de edição...
    //Pois se não estiver, não teremos quem deletar lá no banco de dados...
    if(ID == -1)
        return;

    //Vamos perguntar primeiro se o usuário tem certeza que quer deletar o registro...
    int confirma = wxMessageBox(wxT("Tem certeza que quer deletar o registro?"), wxT("Confirmação"), wxYES_NO);

    //Se o usuário clicar em não, cancelo a função...
    if(confirma == wxNO)
        return;

    //Executo a função para deletar o registro...
    DeleteInDB(wxString::Format(wxT("%d"), ID));

    //Após deletarmos um registro atualizamos o wxGrid lista contatos...
    SelectInDB(lista_contatos);

    //E limpamos os campos de edição...
    LimparCampos();
}

Pronto, o sistema está completo, agora vocês podem refazer o mesmo, adicionando novas funcionalidades, adicionando outros campos, tabelas, etc...

Espero que tenham aproveitado a sequencia de tutoriais sobre wxWidgets e sqlite3 usando a biblioteca wxSqlite3.

Até a próxima.

quarta-feira, 14 de setembro de 2011

Tutorial wxWidgets e sqlite3 parte 13 - Editando valores no banco de dados

A edição de dados vai ser feita com base na função de inserção de dados, para isto criaremos a mesma nos arquivos sqlf.* do projeto.

Como ela irá funcionar:

Nó passaremos como parâmetros, o ID do registro que está sendo editado, para fazermos o controle na cláusula WHERE do SQL, passaremos também o nome que foi editado e a idade.

Antes de executarmos qualquer alteração verificamos se os dados são válidos, se não estão em branco ou se idade é realmente um número.

O comando usado aqui será o ExecuteQuery(), o mesmo usado na inserção dos dados.

Vamos escrever.

No arquivo sqlf.h digite:

sqlf.h
//Aqui a função para editar os dados...
void UpdateDB(wxString ID, wxString nome, wxString idade);

No arquivo sqlf.cpp:

sqlf.cpp
void UpdateDB(wxString ID, 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 editar os dados...
    wxString SQL = wxT("UPDATE contatos \n");
    SQL += wxT("SET NOME = '") + nome + wxT("',\n");
    SQL += wxT("IDADE = ") + idade + wxT("\n");
    SQL += wxT(" WHERE ID = ") + ID + wxT(";");

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

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


Agora vamos chamar a mesma em framep.cpp:

framep.cpp
if(ID == -1)
    {
        //Se a variável ID for = -1, é porque estamos em inserção...
        //E passamos as duas como parâmetros para a função InsertInDB()...
        InsertInDB(get_nome, get_idade);
    }
    else
    {
        //Pegamos o valor do ID...
        wxString get_id = wxString::Format(wxT("%d"), ID);
        //Passamos como parâmetros, para a função...
        UpdateDB(get_id, get_nome, get_idade);
    }


Pequenas alterações que fiz na GUI do sistema.

framep.cpp
//Adicionei um tamanho padrão para a janela...
this->SetSize(wxSize(450, 350));

//Adiciono o box dos botões ao box principal...
//Aqui arrumei o tamanho do sizer dos botões em relação
//a janela e dei um espaço de 10px na base
boxp->Add(box_btns, 0, wxEXPAND|wxBOTTOM, 10);

Estamos quase terminando nosso sistema, falta apenas implementar a função de deletar...

Até a próxima.

Tutorial wxWidgets e sqlite3 parte 12 - Limpando os Campos após alterações e aproveitando para acertar algumas coisas...

Nesta parte do tutorial, iremos implementar a função LimparCampos(), do arquivo framep.cpp.

O que ela irá fazer?

1 – Vai alterar o valor de ID para -1, ou seja, cancelar a edição...
2 – Vai limpar o campo nome.
3 – Vai limpar o campo idade.
4 – Alterar o título da janela para modo de inserção.

O código vai ficar assim:

Digite o seguinte em framep.cpp

framep.cpp
//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()
{
    //A função mais simples de todas...
    //Será usada na criação do frame.
    //Na função OnClickSalvar
    //Na função OnClickLimpar
    //e na função OnClickDeletar

    //Primeiro vamos alterar o valor do ID para -1
    //Para voltarmos ao modo de Inserção...
    ID = -1;

    //Agora limpamos o nome...
    nome->Clear();

    //limpamos o campo idade...
    idade->Clear();

    //Alteramos o valor da janela para modo de Inserção...
    this->SetTitle(wxT("Teste Tutorial Sqlite3 - Modo de Inserção"));
}

Agora vamos chamá-la no final da criação do frame 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();

    //Aqui chamo a função limpar campos...
    LimparCampos();

    //Vamos carregar os dados no grid...
    SelectInDB(lista_contatos);
}

Também no final da função OnClickSalvar

    }

    //Após editarmos um valor, recarregamos os valores no grid...
    SelectInDB(lista_contatos);

    //E também limpamos os valores de edição/inserção...
    LimparCampos();
}

Aproveitamos para implementar a função OnClickLimpar

//Aqui o evento que vai limpar os campos...
void wxFramePrincipal::OnClickLimpar(wxCommandEvent& event)
{
    //Chamamos a função LimparCampos()...
    LimparCampos();
}

E adiantamos algumas coisas na função OnClickDeletar

//Aqui o evento quando eu clicar no botão deletar...
void wxFramePrincipal::OnClickDeletar(wxCommandEvent& event)
{
    //Vamos verificar também se o registro está em modo de edição...
    //Pois se não estiver, não teremos quem deletar lá no banco de dados...
    if(ID == -1)
        return;

    //Após deletarmos um registro atualizamos o wxGrid lista contatos...
    SelectInDB(lista_contatos);

    //E limpamos os campos de edição...
    LimparCampos();
}


Vejam que tínhamos uma função chamada ConfereCampos em framep.h e framep.cpp, por descuido, acabei implementando isto na função de inserir registros de sqlf.cpp, para não enrolarmos a continuidade do tutorial, deletem esta função ConfereCampos dos dois arquivos, o *.h e o *.cpp.

Mais uma parte do tutorial concluída, no próximo iremos finalizar o código do tutorial.

Até a próxima.

Tutorial wxWidgets e sqlite3 parte 11 - Passando os dados do wxGrid para a edição

Hoje vamos escrever a função do duplo click no wxGrid.

O objetivo desta função é:

Ao clicar duas vezes em alguma célula do wxGrid lista_contatos, pegaremos a linha que foi clicada, depois passaremos os valores do ID, NOME e IDADE para seus respectivos valores de edição que são:

A variável ID que vai controlar se estamos em modo de edição ou não, se for em modo de edição qual registro que está sendo editado.

A caixa de texto nome.

A caixa de texto idade.

Vamos ao código:

Em framep.cpp, altere a seguinte parte:

framep.cpp
//Aqui o evento que será executado
//quando eu der 2 cliques em uma célula...
void wxFramePrincipal::OnDoubleClickCell(wxGridEvent& event)
{
    //Primeiro vamos pegar o índice da linha que está sendo clicada:
    int row = event.GetRow();

    //Agora vamos passar os valores desta linha para nossos dados...

    //Primeiro a variável ID
    long int get_id;
    lista_contatos->GetCellValue(row, 0).ToLong(&get_id);

    ID = get_id;
    //Veja que neste momento, a varável ID assume um valor maior que -1
    //Então entramos no modo de edição...

    //Agora pego o valor atual para nome...
    nome->SetValue(lista_contatos->GetCellValue(row, 1));

    //E por último a idade...
    idade->SetValue(lista_contatos->GetCellValue(row, 2));

    //Agora podemos fazer as alterações dos valores, passando como parâmetro
    //o valor do ID...

    //Uma alteração que podemos fazer também é
    //colocar um aviso no título da janela
    //para dizer ao usuário qual a função que ele está executando:

    this->SetTitle(wxT("Teste Tutorial Sqlite3 - Modo de Edição"));
}

Pronto, agora o usuário poderá selecionar qual registro ele quer editar.

No próximo tutorial, implementar a função que limpa os campos após as edições.

Até a próxima.

segunda-feira, 12 de setembro de 2011

Tutorial wxWidgets e sqlite3 parte 10 - Selecionando valores e colocando em um wxGrid


Hoje vamos ver como exibir os valores de uma consulta SQL, em um wxGrid.

A explicação como de costume está nos comentários do fonte, basicamente, o que faremos, é selecionar todos os valores que estão na tabela contatos com um comando SQL que é:

SELECT ID, NOME, IDADE FROM contatos;
ou
SELECT * FROM CONTATOS;

Passar esta consulta como parâmetro para a função ExecuteQuery() da classe wxSQLite3Database().

Esta função irá retornar um wxSQLite3ResultSet(), que armazenará todos os valores contidos na consulta.

Vamos caminhar por todas as linhas do resultset e passaremos os valores para o wxGrid...

Para isto eu criei uma função chamada SelectInDB, que recebe como parâmetro um wxGrid(), nos arquivos sqlf.

Então abra o projeto e adicione os seguintes códigos:

em sqlf.h declare a função SelectInDB

sqlf.h
//Aqui a função que vai fazer um select no banco de dados e preencher o grid...
//Eu passo um ponteiro como parametro, para o grid que será preenchido...
void SelectInDB(wxGrid* grid);



em sqlf.cpp implemente a mesma função

sqlf.cpp
void SelectInDB(wxGrid* grid)
{
    //Nesta linha eu limpo o Grid, veja que, se o grid já estiver vazio
    //eu não faço nada, isto evita alguns erros...
    if(grid->GetNumberRows() > 0)
    {
        //Aqui uso a função DeleteRows() de wxGrid, ela vai deletar
        //as linhas do grid desde a posição passada no parametro 1 (no caso 0)
        //mais a quantidade de linhas passada no parametro 2...
        //no caso o número de linhas presentes no grid atual...
        //para sabermos este número usamos a função GetNumberRows() ou GetRows()...
        grid->DeleteRows(0, grid->GetNumberRows());
    }

    //Agora vamos escrever o código de seleção dos dados...
    wxString SQL = wxT("SELECT ID, NOME, IDADE FROM contatos;");
    //Veja que o banco de dados vai me retornar todas as colunas da tabela,
    //No caso, 3 colunas, e como não colocamos nenhuma condição no comando SQL,
    //ele vai retornar todas as linhas da tabela...

    //Criamos a conexão com o banco de dados...
    wxSQLite3Database *db = OpenDB(GetExecPath() + wxT("/agenda.db3"));

    //Agora vamos usar uma classe que não tinhamos usado ainda
    //que é wxSQLite3ResultSet...
    //Esta classe vai armazenar todos os valores que pedirmos em um comando SELECT
    //e é com ela que pegaremos estes dados e passaremos para o grid...

    wxSQLite3ResultSet result = db->ExecuteQuery(SQL);

    //Veja que aqui usamos outra função de wxSQLite3Database que é ExecuteQuery
    //Esta função, diferente de ExecuteUpdate, recebe um comando SQL como parametro,
    //e retorna um wxSQLite3ResultSet como os valores da consulta...

    //Agora vamos pegar todos estes valores e colocaremos no wxGrid...
    //Enquanto existirem linhas a serem lidas...
    while(result.NextRow())
    {
        //Adiciono uma linha ao grid...
        grid->AppendRows(1);

        //Aqui é a parte que temos que fixar bem...

        //Vou pegar o valor da primeira coluna da linha atual do resultset e passar para
        //a primeira coluna da linha atual do grid...
        grid->SetCellValue(grid->GetNumberRows() - 1, 0, result.GetAsString(wxT("ID")));

        //Vejam que mesmo eu tendo o ID declarado como INTEGER eu posso chamá-lo como String,
        //Isto ocorre porque quem controla o banco de dados é nossa aplicação...
        //Eu posso pegar este valor usando o indice do mesmo no resultset assim:
        //result.GetAsString(0);
        //Pois ele é a primeira coluna da seleção e em sqlite3 o indice sempre vai começar em 0

        //Fazemos a mesma coisa para pegar o nome...
        grid->SetCellValue(grid->GetNumberRows() - 1, 1, result.GetAsString(wxT("NOME")));

        //E a idade...
        grid->SetCellValue(grid->GetNumberRows() - 1, 2, result.GetAsString(wxT("IDADE")));
    }

    //Neste ponto fechamos o resultset...
    result.Finalize();

    //Fechamos o banco de dados...
    CloseDB(db);
}

em framep.cpp vamos chamar esta função no final da implementação do frame principal e no final da função OnClickSalvar

framep.cpp
//Vamos carregar os dados no grid...
SelectInDB(lista_contatos);

O tutorial de hoje é bem simples, tendo como maior importância vocês entenderem como os dados são manipulados pelo resultset, se fixarem bem este esquema, vocês verão que existem maneiras mais simples para implementar funções que agilizam o processo de seleção dos dados e preenchimento dos mesmos em um grid, relatórios e outros controles wxWdigets.

Os arquivos modificados ficaram assim:

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>
#include <wx/grid.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);

//Aqui a função que vai fazer um select no banco de dados e preencher o grid...
//Eu passo um ponteiro como parametro, para o grid que será preenchido...
void SelectInDB(wxGrid* grid);

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

void SelectInDB(wxGrid* grid)
{
    //Nesta linha eu limpo o Grid, veja que, se o grid já estiver vazio
    //eu não faço nada, isto evita alguns erros...
    if(grid->GetNumberRows() > 0)
    {
        //Aqui uso a função DeleteRows() de wxGrid, ela vai deletar
        //as linhas do grid desde a posição passada no parametro 1 (no caso 0)
        //mais a quantidade de linhas passada no parametro 2...
        //no caso o número de linhas presentes no grid atual...
        //para sabermos este número usamos a função GetNumberRows() ou GetRows()...
        grid->DeleteRows(0, grid->GetNumberRows());
    }

    //Agora vamos escrever o código de seleção dos dados...
    wxString SQL = wxT("SELECT ID, NOME, IDADE FROM contatos;");
    //Veja que o banco de dados vai me retornar todas as colunas da tabela,
    //No caso, 3 colunas, e como não colocamos nenhuma condição no comando SQL,
    //ele vai retornar todas as linhas da tabela...

    //Criamos a conexão com o banco de dados...
    wxSQLite3Database *db = OpenDB(GetExecPath() + wxT("/agenda.db3"));

    //Agora vamos usar uma classe que não tinhamos usado ainda
    //que é wxSQLite3ResultSet...
    //Esta classe vai armazenar todos os valores que pedirmos em um comando SELECT
    //e é com ela que pegaremos estes dados e passaremos para o grid...

    wxSQLite3ResultSet result = db->ExecuteQuery(SQL);

    //Veja que aqui usamos outra função de wxSQLite3Database que é ExecuteQuery
    //Esta função, diferente de ExecuteUpdate, recebe um comando SQL como parametro,
    //e retorna um wxSQLite3ResultSet como os valores da consulta...

    //Agora vamos pegar todos estes valores e colocaremos no wxGrid...
    //Enquanto existirem linhas a serem lidas...
    while(result.NextRow())
    {
        //Adiciono uma linha ao grid...
        grid->AppendRows(1);

        //Aqui é a parte que temos que fixar bem...

        //Vou pegar o valor da primeira coluna da linha atual do resultset e passar para
        //a primeira coluna da linha atual do grid...
        grid->SetCellValue(grid->GetNumberRows() - 1, 0, result.GetAsString(wxT("ID")));

        //Vejam que mesmo eu tendo o ID declarado como INTEGER eu posso chamá-lo como String,
        //Isto ocorre porque quem controla o banco de dados é nossa aplicação...
        //Eu posso pegar este valor usando o indice do mesmo no resultset assim:
        //result.GetAsString(0);
        //Pois ele é a primeira coluna da seleção e em sqlite3 o indice sempre vai começar em 0

        //Fazemos a mesma coisa para pegar o nome...
        grid->SetCellValue(grid->GetNumberRows() - 1, 1, result.GetAsString(wxT("NOME")));

        //E a idade...
        grid->SetCellValue(grid->GetNumberRows() - 1, 2, result.GetAsString(wxT("IDADE")));
    }

    //Neste ponto fechamos o resultset...
    result.Finalize();

    //Fechamos o banco de dados...
    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;

    //Vamos carregar os dados no grid...
    SelectInDB(lista_contatos);
}

//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
    {
    }

    //Após editarmos um valor, recarregamos os valores no grid...
    SelectInDB(lista_contatos);
}

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



Até a próxima.

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.