ADO.NET - Salvando e recuperando imagens de um banco de dados - 2

No artigo - ADO.NET - Criando um cadastro de clientes -  criamos uma pequena aplicação para gerenciar os dados dos clientes em uma base de dados Access. Que tal armazenar  no banco de dados a foto do cliente de forma que a poder exibí-la no formulário em um controle PictureBox ?  É isto que vamos fazer.

Podemos armazenar as imagens diretamente no banco de dados ou podemos optar por guardar somente a referência a imagem. Você deve considerar bem qual solução vai adotar pois cada uma tem suas vantagens e desvantagens.

Guardar a referência da imagem no banco de dados é mais simples em termos de código e tem a vantagem de ocupar muito menos espaço do seu banco de dados. Você cria um campo no banco de dados onde guarda o caminho e o nome da imagem . Para exibir a imagem basta recuperar o caminho e nome da imagem exibindo-a em um controle PictureBox. A desvantagem é que você terá que gerenciar a localização das imagens externamente a sua aplicação.

Nota: No VB.NET não existe mais o controle Image . Temos somente o controle PictureBox que agora suporta também arquivos GIF animados. Muitas de suas propriedades mudaram e outras não existem mais. Se você quiser consumir menos recursos pode sobrepor o evento OnPaint do formulário e usar o método DrawImage para exibir uma imagem.

Armazenando as imagens no seu banco de dados você não precisa se preocupar com sua localização mas o código para salvar e recuperar uma imagem é mais complexo e você terá que considerar que o tamanho do seu banco de dados será bem maior. No caso de um banco de dados Access isto pode ser um fator limitante que você deverá considerar pois o tamanho máximo que um banco de dados Access pode chegar é algo em torno de 2 GB.

No artigo - Salvando imagens em um banco de dados - eu mostro uma outra forma de gravar imagens em um banco de dados

Vou adotar a segunda solução e armazenar e recuperar as imagens diretamente no banco de dados. Para isto vou usar o aplicativo cadastro de clientes já criado e o banco de dados Biblio.mdb com a tabela Clientes. Então vamos arregaçar as mangas....

 

A primeira coisa a faze é alterar a estrutura do banco de dados e incluir um campo para armazenar as fotos dos clientes. Vou incluir um novo campo com o nome de Foto e do tipo Objeto OLE pois iremos armazenar dados no formato binário.(Você pode armazenar imagens , arquivos de áudio , etc.)

Veja ao lado como deve ficar a estrutura da tabela Clientes.

 

Vamos agora alterar o layout do formulário incluindo um controle PictureBox para poder exibir as fotos dos clientes. Vou incluir um control Button (o antigo commandButton do VB6) para poder gerenciar a inclusão da imagem e um controle GroupBox (o antigo controle Frame do VB6). Abaixo o novo layout do formulário para cadastro de clientes:

- Ao lado o novo layout do formulário já com os controles : PictureBox , Button e GroupBox.

- Vou dar um nome mais sugestivo para  o controle PictureBox : picFoto e para o botão : btnIncluiImage

- Teremos que alterar as configurações dos objetos odaClientes e dsClientes para refletir a nova estrutura da tabela Clientes.

Vamos ter que ajustar as configurações dos objetos DataAdapter(odaClientes) e DataSet(dsClientes) pois a estrutura do banco de dados foi alterada e teremos que refletir esta alteração nestes objetos.

Vamos agora gerar novamente o DataSet.

Pronto ! as configurações já estão ajustadas para nova estrutura da tabela clientes.

Nota: Quando um dataset tipado é gerado em tempo de desenho (todos os DataSets gerados a partir de um DataAdapter são tipados por padrão) uma classe DataSet e um esquema XML associado é criado no seu projeto.

Um esquema XML define e valida os dados importados de um fluxo XML ou documentos em um dataset tipado. O esquem XML associado com o dataset pode ser carregado em um Descritor XML fornecendo uma representação visual da estrutura do DataSet que pode se editado e visualizado. Veja na janela Solution Explorer o esquema XML - dsClientesx.xsd.(ver figura 1.0). Este arquivo é criado automaticamente para o novo dataset dsClientes.

Se você clicar duas vezes sobre o arquivo dsClientesx.xsd  o descritor XML irá  exibir a estrutura do esquema XML (figura 2.0)

Para visualizar o formato XML clique na guia XML e você terá estrutura do arquivo de esquema XML. (figura 3.0 ).

figura 1.0 Figura 2.0 Figura 3.0

Um arquivo de esquema XML tem as seguintes funções:

  • Descreve a forma do documento XML
  • Valida os dados importados de um fluxo XML ou documento para um DataSet
  • Estabelece uma estrutura relacional das tabelas e colunas de um dataset, chaves , relacionamentos entre as tabelas. Esta informação é usada para gerar a classe DataSet.

Obs: Não altere nada na estrutura do arquivo XML.

Vamos passar agora para a etapa onde iremos criar o código para exibir as fotos no formulário e salvar as imagens no banco de dados. Lembre-se que ainda não temos nenhuma imagem salva no banco de dados.

O botão incluir - btnIncluiImage -colocado abaixo do controle - PictureBox -picFoto -  irá permitir que uma imagem seja salva no banco de dados. Este botão somente poderá estar habilitado quando o usuário estiver editando ou incluindo um novo registro, por isso , devemos definir a sua propriedade Enabled como False e torná-la True somente quando o usuário clicar nos botões Editar e Incluir. (Quando o usuário clicar nos botões Salvar e Cancelar devemos retornar Enabled como False)

Quando o usuário clicar no botão - Incluir - deveremos abrir uma caixa que permita a procura e seleção de um arquivo imagem a ser incluído no banco de dados. O controle -  OpenFileDialog - faz exatamente isto , e , para simplificar vou usar um filtro para que somente imagens do tipo JPG sejam permitidas na seleção.  Abaixo o código atribuido ao evento Click do botão - Incluir :

Private Sub btnIncluiImage_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnIncluiImage.Click

'Permite somente arquivos Jpeg files

OpenFileDialog1.Filter = "(Jpeg Files) *.jpg | *.jpg"

OpenFileDialog1.Title = "Selecione um arquivo JPG para inserir no campo Foto"

OpenFileDialog1.ShowDialog()

If OpenFileDialog1.FileName <> "" Then

  'Copia o arquivo jpeg selecionado para a PictureBox com o metodo FromFile do objeto Image

  picFoto.Image = Image.FromFile(OpenFileDialog1.FileName)

End If

End Sub

Abaixo temos a janela - OpenFileDialog - filtrando apenas arquivos JPG sendo exibida. Observe que definimos a propriedade - Title - do componente para exibir o título da janela.

Após selecionar uma imagem a mesma deverá ser exibida no controle Picture Box e , se o usuário clicar no botão - Salvar - a imagem deverá ser salva no DataSet. O código associado ao evento Click do botão - Salvar - é dado a seguir:

Nota: Nas versões anterioes do VB o componente OLE Container permitia que você incluisse objetos OLE em seus formulários. No VB.NET os Windows Forms não suportam este recurso. Se precisar fazer isto use um controle WebBrowser.
Private Sub btnsalvar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnsalvar.Click

 

'O método EndCurrentEdit do objeto BindingContext completa o processo de edição

Me.BindingContext(dsClientes, "Clientes").EndCurrentEdit()

 

'Usei o método HasChanges do Dataset para estar certo de que o registro foi modificado antes

' de gastar recursos efetuando um Update na fonte de dados. HasChanges retorna True se

' alguma modificação foi feita.

If dsClientes.HasChanges() = True Or OpenFileDialog1.FileName <> "" Then

  'Esteja certo que o usuario alterou o valor do PictureBox antes de atualizar o campo Foto

   If OpenFileDialog1.FileName <> "" Then

       'Cria um objeto FileStream object e abre o arquivo imagem

       Dim fsPicFile As New System.IO.FileStream(OpenFileDialog1.FileName, System.IO.FileMode.Open, System.IO.FileAccess.Read)

       'Cria um Byte array vazio do tamanho do arquivo imagem

       Dim bytePicFile(fsPicFile.Length() - 1) As Byte

       'Usa o objeto FileStream (fsFicFile) para ler a imagem no Byte array

      fsPicFile.Read(bytePicFile, 0, bytePicFile.Length)

      'Fecha FileStream

      fsPicFile.Close()

      'Copia o conteudo do byte array (bytePicFile) para o campo Foto

      dsClientes.Clientes(Me.BindingContext(dsClientes,"Clientes").Position)("Foto") = bytePicFile

      'Limpa a propriedade FileName depois de copiar a imagem jpeg para o campo Foto

      OpenFileDialog1.FileName = ""

    End If

   'Para escrever as alterações de um registro para o banco de dados você deve chamar o método Update do DataAdapter

   odaClientes.Update(dsClientes)

   'Após editar um registro você precisa preencher o Data Adapter novamente. Antes de fazer isto sempre limpe o Data Adapter

   dsClientes.Clear()

   'O método Fill do Data Adapter preenche todos os datasets vinculados a ele

   odaClientes.Fill(dsClientes, "Clientes")

End If

txtNome.ReadOnly = True

txtEndereco.ReadOnly = True

txtUF.ReadOnly = True

txtNascimento.ReadOnly = True

txtTelefone.ReadOnly = True

btnIncluiImage.Enabled = False

SetButtons(sender, e)

End Sub

Agora só falta o código para recuperar uma imagem salva no campo Foto e exibí-la no controle - PicFoto -. Vamos criar uma rotina chamada MostraFoto() cujo código é o seguinte :

Private Sub MostraFoto()

'tenha certeza de que a tabela contem registros

If dsClientes.Tables("Clientes").Rows.Count > 0 Then

 

   'verifique se o campo Picture do registro atual não é NULL

   If Not dsClientes.Clientes(Me.BindingContext(dsClientes, "Clientes").Position)("Foto") Is DBNull.Value Then

     'Dimensiona uma varivael Byte array (bytePicData) e armazena o valor no campo Foto

     Dim bytePicData() As Byte = _

     dsClientes.Tables("Clientes").Rows(Me.BindingContext(dsClientes, "Clientes").Position)("Foto")

 

     'Um MemoryStream é um obejto System.IO (como um FileStream). Movendo os valores de

     ' do byte array bytePicData para MemoryStream, podemos usar o metodo FromStream do objeto Image Intrínseco

     ' para converter e copiar a figura diretamente para a propriedade Image do controle picFoto

     Dim PicMemStream As New System.IO.MemoryStream(bytePicData)

     picFoto.Image = Image.FromStream(PicMemStream)

   Else 'Se o campo Foto for Null, define a propriedade Image de picFoto para Nothing

    ' para remover qualquer imagem exibida antes

    picFoto.Image = Nothing

   End If

End If

End Sub

Como devemos exibir as fotos para cada cliente a rotina - MostraFoto() - deverá ser invocada sempre que irmos de um registro para outro. Vamos então colocar a chamada para a rotina na procedure - SetButtons().

Pronto ! agora é só executar o projeto , salvar algumas imagens e ver o resultado final . (abaixo um exemplo):

O próximo passo será incluir uma rotina para procurar informações em nosso projeto. Aguarde...

(O código completo deste artigo esta no Super DVD .Net.)

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

 

 

             Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter
 

Referências:


José Carlos Macoratti