Olá pessoal, notei que existem muitas dúvidas postadas nos fóruns sobre como gravar imagens em uma determinada base de dados e depois exibi-las na aplicação, principalmente sobre qual seria a melhor prática para esse tipo de desenvolvimento. Podemos desenvolver de 2 maneiras: a primeira seria criando um campo do tipo Blob na tabela desejada e dentro da aplicação seria codificado para gravar a imagem nesse campo, pessoalmente não gosto muito dessa técnica pois imaginem um cadastro de peças contendo 1000 imagens uma para cada peça, essa base de dados ficaria enorme e com isso poderíamos perder performance tanto da aplicação quanto do servidor. A segunda maneira seria criar um campo do tipo VARCHAR na tabela desejada e dentro da aplicação gravar no banco somente o caminho para imagem, eu sei que muitos podem questionar a questão de se trabalhar em rede, poderia ser difícil capturar as imagens em estações diferentes, nesse caso o mais sensato seria gravar essas imagens em uma pasta no servidor da rede, desse modo quando fosse necessário tanto gravação ou exibição da imagem a aplicação iria consultar somente uma pasta contendo todas as imagens no servidor.

Nesse artigo vou demonstrar a segunda maneira que é gravando somente o caminho para imagem no banco e posteriormente vamos navegar entre os registros e exibir novamente as imagens na tela, bem chega da conversa vamos codificar...

Para esse artigo criei uma base de dados utilizando o Firebird 2.5 + IBExpert com o nome de DEVMEDIA, e também uma tabela Imagens. Na listagem 1 exibe o script de criação da tabela.

Listagem 1: Script da Tabela Imagens


CREATE TABLE IMAGEM (
    ID INTEGER NOT NULL,
    TITULO_IMAGEM VARCHAR(40) CHARACTER SET WIN1252 COLLATE WIN1252,
    CAMINHO_IMAGEM VARCHAR(500) CHARACTER SET WIN1252 COLLATE WIN1252);
ALTER TABLE IMAGEM ADD CONSTRAINT PK_IMAGEM PRIMARY KEY (ID); 

Agora vamos criar um novo projeto no Delphi, e arrastar para o form alguns componentes, abaixo segue uma breve descrição sobre as configurações necessárias:

1 - TLabel
- Caption = “Descrição da Imagem:”

1 - TEdit
- Name = edtDescricao
- CharCase = ecUpperCase

1 - TImage
- Name = imgImagem
- Strech = true

1 - TDBGrid
- Align = AlBotton
- Name = grdImagem
- ReadOnly = true
- Options > dgEditing = false, dgRowSelect = true

4 - TBitBtn

1 - Name = btnCarregar
- Caption = “Carregar Imagem”
- Cursor = crHandPoint
- Hint = “Carregar Imagem”
- ShowHint = true

2 - Name = btnIncluirImagem
- Caption = “Gravar Imagem”
- Cursor = crHandPoint
- Hint = “Incluir imagem no banco de dados”
- ShowHint = true

3 - Name = btnAlteraImagem
- Caption = “Alterar Imagem”
- Cursor = crHandPoint
- Hint = “Alterar imagem gravada”
- ShowHint = true

4 - Name = btnExcluirImagem
- Caption = “Excluir Imagem”
- Cursor = crHandPoint
- Hint = “Excluir Imagem”
- ShowHint = true

Os componentes foram organizados como mostra a imagem abaixo:

Exibe layout final da tela

Figura 1: Exibe layout final da tela

Os componentes para acesso ao banco de dados e o TOpenDialog para informar o caminho da imagem a ser gravada foram criados em RunTime, desse modo o código ficou um pouco extenso. Como a finalidade deste artigo é apenas demonstrar como podemos gravar o caminho e visualizar imagens através do das informações gravadas no banco de dados então não pretendo estender a explicação de criação de componentes em tempo de execução.

Gravar o caminho da imagem: primeiro temos que capturar seu caminho e para isso vamos usar um TOpenDialog, depois informamos uma descrição para imagem no edtDescricao e pressionamos o botão “Incluir Imagem”.

Alterar um caminho: temos que primeiro selecionar o registro no DBGrid depois pressionar o botão “Carregar Imagem” e selecionar qual será a nova imagem a ser capturado o caminho e depois pressionar o botão “Alterar Imagem”.

Excluir caminho: e bem simples, seleciona o registro no DBGrid e pressiona o botão “Excluir Imagem”.

Abaixo seguem várias listagens com os devidos códigos para o processamento das informações:

Listagem 2: Procedimento para conectar-se ao banco de dados


procedure TForm2.Conectar;
begin
    //Procedimento para conectar-se ao banco de dados
    Conexao := TSQLConnection.Create(nil);

    try
        //Passa os parâmetros para o objeto Conexao
        Conexao.Connected := false;
        Conexao.LoginPrompt := false;
        Conexao.Params.Clear;
        Conexao.ParamsLoaded := True;
        Conexao.DriverName := 'Firebird';
        Conexao.GetDriverFunc := 'getSQLDriverINTERBASE';
        Conexao.LibraryName := 'dbxfb.dll';
        Conexao.VendorLib := 'fbclient.dll';
        Conexao.Params.Add('drivername=Firebird');
        Conexao.Params.Add('hostname=LOCALHOST');
        Conexao.Params.Add('user_name=SYSDBA');
        Conexao.Params.Add('password=masterkey');
        Conexao.Params.Add('port=3050');
        Conexao.Params.Add('Database=C:\Projeto Imagens\DEVMEDIA.fdb');
        Conexao.Connected := true;
     Except
        on E:Exception do
        ShowMessage('Erro ao acessar banco de dados!'#13#10 + E.Message);
     end;
end;

Listagem 3: Código do evento OnCreate do Form


procedure TForm2.FormCreate(Sender: TObject);
begin
    //Inicia uma conexão com o banco de dados
    Conectar();
    //Carrega as informações no DDGrid
    CarregaGrid();
end;
.

Listagem 4: Código do evento OnClick do botão btnCarregarImagem


procedure TForm2.btnCarregaImagemClick(Sender: TObject);
var
  OpenDialog: TOpenDialog;
begin
     //Carrega a janela para procurar o Imagem
     try
        OpenDialog := TOpenDialog.Create(nil);
        if OpenDialog.Execute then
        begin
            edtDescricao.Clear;
            Caminho := OpenDialog.FileName;
            imgImagem.Picture.LoadFromFile(Caminho);
        end;
     finally
         FreeAndNil(OpenDialog);
     end;
end;

Listagem 5: Exibe os 3 procedimentos INCLUSÃO, ALTERAÇÃO E EXCLUSÃO


/Procedimento para incluir imagem no banco
procedure TForm2.IncluirImagem(Descricao: string; var Caminho: string);
begin
     try
        FSql := 'INSERT INTO IMAGEM (TITULO_IMAGEM, CAMINHO_IMAGEM)VALUES(:DESC, :CAMINHO)';

        qryAux := TSQLQuery.Create(nil);
        qryAux.SQLConnection := FConexao;
        qryAux.Close;
        qryAux.SQL.Clear;
        qryAux.SQL.Add(FSql);
        qryAux.Params[0].AsString := Descricao;
        qryAux.Params[1].AsString := Caminho;
        FReturn := qryAux.ExecSQL();

        if FReturn > 0 then
           ShowMessage('Registro gravado com sucesso!');

        CarregaGrid();
     finally
        FreeAndNil(qryAux);
     end;
end;

//Procedimento para alterar imagem no banco
procedure TForm2.AlterarImagem(Id: integer; Descricao: string; var Caminho: string);
begin
     try
        FSql := 'UPDATE IMAGEM SET TITULO_IMAGEM=:DESC, CAMINHO_IMAGEM=:CAMINHO WHERE ID=:ID';

        qryAux := TSQLQuery.Create(nil);
        qryAux.SQLConnection := FConexao;
        qryAux.Close;
        qryAux.SQL.Clear;
        qryAux.SQL.Add(FSql);
        qryAux.Params[0].AsString := Descricao;
        qryAux.Params[1].AsString := Caminho;
        qryAux.Params[2].AsInteger := Id;
        FReturn := qryAux.ExecSQL();

        if FReturn > 0 then
           ShowMessage('Registro alterado com sucesso!');

        CarregaGrid();
     finally
        FreeAndNil(qryAux);
     end;
end;

//Procedimento para exclusão do registro
procedure TForm2.ExcluirImagem(Id: integer);
begin
     try
        FSql := 'DELETE FROM IMAGEM WHERE ID = :ID';

        qryAux := TSQLQuery.Create(nil);
        qryAux.SQLConnection := FConexao;
        qryAux.Close;
        qryAux.SQL.Clear;
        qryAux.SQL.Add(FSql);
        qryAux.Params[0].AsInteger := Id;
        qryAux.ExecSQL();

        CarregaGrid();
        imgImagem.Picture := nil;
     finally
        FreeAndNil(qryAux);
     end;
end;

Listagem 6: Exibe o procedimento para carregar as informações no DBGrid


//Procedimento para exibir os dados no DBGrid
procedure TForm2.CarregaGrid;
begin
    try
       FSql := 'SELECT ID, TITULO_IMAGEM AS TITULO, CAMINHO_IMAGEM AS CAMINHO FROM IMAGEM';

       //Verfica se já existe um objeto TSQLQuery intânciado
       if not Assigned(qryDados) then
       begin
           qryDados := TSQLQuery.Create(nil);
           qryDados.SQLConnection := FConexao;
       end;

       //Verfica se já existe um objeto TDataSetProvider intânciado
       if not Assigned(dspDados) then
          dspDados := TDataSetProvider.Create(nil);

       //Verfica se já existe um objeto TClientDataSet intânciado
       if not Assigned(cdsDados) then
       begin
          cdsDados := TClientDataSet.Create(nil);
          cdsDados.ProviderName  := dspDados.Name;
          cdsDados.PacketRecords := -1;
          cdsDados.AfterScroll   := Self.CarregarImagem;
       end;

       //Verfica se já existe um objeto TDataSource intânciado
       if not Assigned(dtsDados) then
          dtsDados := TDataSource.Create(nil);

       //Prepara a qryDados
       qryDados.Close;
       qryDados.SQL.Clear;
       qryDados.SQL.Add(FSql);
       qryDados.Open;

       //Atribui o objeto qryDados a propriedade DataSet do Provider
       dspDados.DataSet := qryDados;

       //Prepara o ClientDataSet
       cdsDados.Close;
       cdsDados.SetProvider(dspDados.DataSet);
       cdsDados.Open;

       //Atribui o objeto cdsDados a propriedade DataSet do DataSource
       dtsDados.DataSet := cdsDados;

       //Seta a propriedade DataSource do DBGrid
       grdImagem.DataSource := dtsDados;

    Except
        on E:Exception do
        ShowMessage('Erro ao carregar dados no DBGrid!'#13#10 + E.Message);
    end;
end;

Listagem 7: Exibe o procedimento carregar a imagem no TImage


//Procedimento para carregar a imagem no imgImagem
procedure TForm2.CarregarImagem(DataSet: TDataSet);
begin
    //Verifica se o caminho da imagem é válido
    if FileExists(DataSet.Fields[2].AsString) then
    begin
       imgImagem.Picture.LoadFromFile(DataSet.Fields[2].AsString);
       edtDescricao.Text := DataSet.Fields[1].AsString;
    end
    else
    begin
       imgImagem.Picture := nil;
       edtDescricao.Clear;
    end;
end;

Observação: Nesse código não estou aplicando algumas boas práticas de programação, conceitos de POO como encapsulamento para alguns atributos e etc. também não foram verificados. Quanto a trabalhar com componentes em RunTime no próprio portal DevMedia existem excelente artigos e vídeos - aulas sobre esse tema.

Todos os procedimentos estão comentados, mas destaco o código da listagem 7 onde é verificado se o caminho da imagem que está gravado no banco é valido e posteriormente carrega essa imagem no componente imgImage, notem que atribuo esse procedimento ao evento AfterScroll na criação do objeto cdsDados para que sempre que o cursor mudar de registro seja carregado a imagem do atual registro. Esse evento resume perfeitamente o objetivo desse artigo, ou seja, simplesmente gravamos o caminho para a imagem e mesmo assim podemos obter uma boa performance da aplicação para visualizar tais imagens.

Após executarmos a aplicação podemos observar que clicando sobre o registro desejado no DBGrid será alterada a imagem na tela, essas imagens foram selecionadas apenas para testar o funcionamento.

Exibe imagem após seleção do registro no DBGrid

Figura 2: Exibe imagem após seleção do registro no DBGrid

Bom pessoal, demonstrei nesse artigo como pode ser simples gravar somente o caminho das imagens no banco e posteriormente exibi-las, essa prática pode ser muito interessante para diversos tipos de aplicações, eu mesmo já usei.

Com isso finalizo mais um artigo, espero que tenham apreciado e até a próxima.

Qualquer dúvida meu e-mail: wllfl@ig.com.br

Abraços...