... Assinatura do site por 3 anos + Kit MontaRibbons + 3 Livros em PDF + Diversas Revistas (pdf) de brinde, por apenas R$145,00
(
podendo parcelar em até 10 vezes no cartão de crédito)...

Clique aqui e obtenha mais detalhes do nosso kit completo e de como comprar.


Utilizando Classe no Access - A Classe Produto

Por: Plinio Mabesi
 

Continuando a inclusão de funcionalidade em nosso sistema vamos agora ao próximo passo.

A próxima classe a ser codificada será a classe Produto. Após apresentar a estrutura da classe faremos a implementação da interface gráfica que manipulará os dados dos objetos.

Mais uma vez, caso necessário, relembre os conceitos anteriores sobre atributos, métodos, acesso às propriedades do objeto, instâncias e demais ensinamentos sobre a programação orientada a objetos, vistos nos primeiros artigos.

A Classe Produto

O objetivo desta classe, conforme dito anteriormente, é oferecer funcionalidades de inclusão, consulta, atualização e exclusão dos objetos do tipo produto.

Este é o código da classe, com todos os seus atributos e métodos, que se utilizam de funções próprias, bem como dos métodos do objeto da classe ConexaoBD.

Código da classe:

Option Compare Database
Option Explicit

'Atributos da Classe

'Atributo de backup e atributo identificador da Classe
'PK - Código que identifica o produto.
Private bkpCodProduto As Variant
Private lngCodProduto As Variant

'Descrição do produto.
Private strDescricao As Variant

'Quantidade mínima desejada no estoque.
Private dblEstoqueMinimo As Variant

'Quantidade atual do estoque.
Private dblQtdEstoque As Variant

'Unidade de comercialização do produto.
Private strUnidade As Variant

'Valor unitário do produto.
Private curValorUnitario As Variant


'Métodos Get, Set e Let da Classe

Property Get codProduto() As Variant

    codProduto = lngCodProduto

End Property

Property Let codProduto(argCodProduto As Variant)

    lngCodProduto = argCodProduto
    
    If IsEmpty(bkpCodProduto) Then
      bkpCodProduto = lngCodProduto
    End If

End Property

Property Get descricao() As Variant

    descricao = strDescricao

End Property

Property Let descricao(argDescricao As Variant)

    strDescricao = argDescricao

End Property

Property Get estoqueMinimo() As Variant

    estoqueMinimo = dblEstoqueMinimo

End Property

Property Let estoqueMinimo(argEstoqueMinimo As Variant)

    dblEstoqueMinimo = argEstoqueMinimo

End Property

Property Get qtdEstoque() As Variant

    qtdEstoque = dblQtdEstoque

End Property

Property Let qtdEstoque(argQtdEstoque As Variant)

    dblQtdEstoque = argQtdEstoque

End Property

Property Get unidade() As Variant

    unidade = strUnidade

End Property

Property Let unidade(argUnidade As Variant)

    strUnidade = Ucase(argUnidade)

End Property

Property Get valorUnitario() As Variant

    valorUnitario = curValorUnitario

End Property

Property Let valorUnitario(argValorUnitario As Variant)

    curValorUnitario = argValorUnitario

End Property

'Método Existe [Com conhecimento de SQL]
'Verifica a existência do objeto Produto na tabela 
'correspondente no Banco de Dados.
Function existe(argCodProduto As Variant) As Boolean
On Error GoTo Err_existe

    Dim objCon As New aclConexaoBD
    Dim rstExiste As Recordset
    Dim strSql As String

    existe = False

    strSql = "Select * " & _
            "From Produto " & _
            "Where codProduto = " & objCon.valorSql(argCodProduto)

    Set rstExiste = objCon.consulta(strSql)

    If rstExiste.RecordCount > 0 Then
        existe = True
    End If

    'Fecha o Recordset existe
    rstExiste.close

Exit_existe:
    Set rstExiste = Nothing
    Exit Function

Err_existe:
    existe = False
    GoTo Exit_existe

End Function

'Método Incluir [Com conhecimento de SQL]
'Inclui um novo objeto na tabela correspondente dentro do Banco de dados
Function incluir() As Boolean
On Error GoTo Err_incluir

    Dim objCon As New aclConexaoBD
    Dim strSql As String

    strSql = "Insert Into " & _
            "Produto(codProduto,descricao,estoqueMinimo,qtdEstoque, _
            unidade,valorUnitario) " & _
            "Values(" & objCon.valorSql(codProduto) & "," & _ 
            objCon.valorSql(descricao) & "," & _
            objCon.valorSql(estoqueMinimo) & "," & _ 
            objCon.valorSql(qtdEstoque) & "," & _
            objCon.valorSql(unidade) & "," & _
            objCon.valorSql(valorUnitario) & ")"

    incluir = (objCon.executa(strSql) > 0)

    If incluir Then
        'Atualiza os campos de backup
        bkpCodProduto = codProduto
    End If

Exit_incluir:
    Exit Function

Err_incluir:
    incluir = False
    GoTo Exit_incluir

End Function

'Método Excluir [Com conhecimento de SQL]
'Exclui o objeto atual na tabela correspondente dentro do Banco de dados
Function excluir() As Boolean
On Error GoTo Err_excluir

    Dim objCon As New aclConexaoBD
    Dim strSql As String

    strSql = "Delete From Produto " & _
            "Where codProduto = " & objCon.valorSql(codProduto)

    excluir = (objCon.executa(strSql) > 0)

Exit_excluir:
    Exit Function

Err_excluir:
    excluir = False
    GoTo Exit_excluir

End Function

'Método Obter [Com conhecimento de SQL]
'Recupera o objeto Produto através dos argumentos informados
Function obter(argCodProduto As Variant) As Boolean
On Error GoTo Err_obter

    Dim objCon As New aclConexaoBD
    Dim rstObter As Recordset
    Dim strSql As String

    strSql = "Select * " & _
            "From Produto " & _
            "Where codProduto = " & objCon.valorSql(argCodProduto)

    Set rstObter = objCon.consulta(strSql)

    If rstObter.RecordCount = 0 Then
        obter = False
        Exit Function
    End If

    'Atualiza os campos de backup e os identificadores
    codProduto = argCodProduto
    bkpCodProduto = argCodProduto

    'Atualiza os campos restantes
    descricao = rstObter.Fields("descricao")
    estoqueMinimo = rstObter.Fields("estoqueMinimo")
    qtdEstoque = rstObter.Fields("qtdEstoque")
    unidade = rstObter.Fields("unidade")
    valorUnitario = rstObter.Fields("valorUnitario")

    obter = True

    'Fecha o Recordset obter
    rstObter.close

Exit_obter:
    Set rstObter = Nothing
    Exit Function

Err_obter:
    obter = False
    GoTo Exit_obter

End Function

'Método Salvar [Com conhecimento de SQL]
'Salva o objeto atual na tabela correspondente dentro do Banco de dados
Function salvar() As Boolean
On Error GoTo Err_salvar

    Dim objCon As New aclConexaoBD
    Dim strSql As String

    If existe(bkpCodProduto) Then
        strSql = "Update Produto " & _
            "Set codProduto = " & objCon.valorSql(codProduto) & _
                ", descricao = " & objCon.valorSql(descricao) & _
                ", estoqueMinimo = " & objCon.valorSql(estoqueMinimo) & _
                ", qtdEstoque = " & objCon.valorSql(qtdEstoque) & _
                ", unidade = " & objCon.valorSql(unidade) & _
                ", valorUnitario = " & objCon.valorSql(valorUnitario) & _
            " Where codProduto = " & objCon.valorSql(bkpCodProduto)

        salvar = (objCon.executa(strSql) > 0)
    Else
        salvar = incluir
    End If

    If salvar Then
        'Atualiza as variáveis de backup com o novo valor da chave
        bkpCodProduto = codProduto
    End If

Exit_salvar:
    Exit Function

Err_salvar:
    salvar = False
    GoTo Exit_salvar

End Function

'Método baixarEstoque()
'Atualiza o estoque diminuindo a quantidade informada como parâmetro
'e devolve um valor booleano que indica o sucesso da operação;
Function baixarEstoque(argQtd As Double) As Boolean
    
    If dblQtdEstoque - Abs(argQtd) < 0 Then
        baixarEstoque = False
    Else
        dblQtdEstoque = dblQtdEstoque - Abs(argQtd)
        baixarEstoque = salvar
    End If

End Function

'Método subirEstoque()
'Atualiza o estoque acrescentando a quantidade informada como
'parâmetro e devolve um valor booleano que indica o sucesso
'da operação;
Function subirEstoque(argQtd As Double) As Boolean
    
    dblQtdEstoque = dblQtdEstoque + Abs(argQtd)
    subirEstoque = salvar

End Function

'Método estoqueBaixo
'Verifica o estoque atual e compara com o valor de estoque mínimo
'cadastrado para produto e devolve um valor booleano que indica
'se o valor atual está abaixo do previsto.
Function estoqueBaixo() As Boolean
    
    If dblQtdEstoque < dblEstoqueMinimo Then
        estoqueBaixo = True
    End If

End Function

'Fim da classe...

Pontos Importantes

Desta vez, complementando os itens tratados no artigo anterior, vamos destacar o pontos a seguir.

1. Controle do estoque: Ao baixarmos o estoque de um produto, devemos verificar se é possível diminuir a quantidade informada, pois seria impossível retirar mais do que a quantidade existente em estoque. Além disso, não podemos baixar quantidades negativas de produto, pois isto significa que estaríamos aumentando a quantidade ao invés de diminuir. O método somente retornará True se for possível realizar a operação.

Function baixarEstoque(argQtd As Double) As Boolean
    
    If dblQtdEstoque - Abs(argQtd) <= 0 Then
        baixarEstoque = False
    Else
        dblQtdEstoque = dblQtdEstoque - Abs(argQtd)
        baixarEstoque = salvar
    End If

End Function

2. Conversão de dados no momento da atribuição do valor: Para a atribuição de algumas propriedades será realizada uma conversão dos dados. No caso da unidade o valor será convertido em letras maiúsculas para que fique padronizado. Para os atributos que armazenas a quantidade de produto em estoque e estoque mínimo não serão aceitos valores negativos, sendo assim todas as quantidades serão convertidas para seus respectivos valores absolutos.

Property Let estoqueMinimo(argEstoqueMinimo As Variant)

    dblEstoqueMinimo = Abs(argEstoqueMinimo)

End Property


Property Let qtdEstoque(argQtdEstoque As Variant)

    dblQtdEstoque = Abs(argQtdEstoque)

End Property


Property Let unidade(argUnidade As Variant)

    strUnidade = UCase(argUnidade)

End Property

A Interface Gráfica

Assim como no artigo anterior, para que possamos visualizar e manipular os dados dos produtos devemos criar um formulário com campos para preenchimento e botões de comando que coordenem as ações sobre os dados.

A seguir serão definidas as características para o formulário no qual iremos trabalhar com os dados dos objetos relativos aos produtos. Neste caso as especificações de design também são apenas sugestões, porém as informações de origem de dados, bloqueio de campos e formatos de dados são obrigatórias, sob pena de não obter a funcionalidade desejada. Estas especificações estarão marcadas com um asterisco vermelho ao lado.

No formulário teremos uma lista contendo os produtos cadastrados, um campo de texto para realizar buscas, alguns campos de texto para digitação das informações e os botões de comando para criar, salvar e excluir registros.

Obs: Somente as propriedades que foram alteradas para um valor diferente do padrão serão apresentadas. Para as demais utilize o padrão do sistema ou o valor que desejar, desde que não comprometa a funcionalidade do sistema.

Formulário

Nome: FProduto
Largura: 19cm
Altura: Cabeçalho (1cm) / Detalhe (10cm)
Legenda: Sistema de Vendas
Estilo da borda: fino
Seletores de registro: Não
Botões de navegação: Não
Linhas divisórias: Não
Barras de rolagem: Nenhuma
Caixa de controle: Sim
Botão Fechar: Sim
Botões Min Max: Nenhum
Popup: Sim
Janela Restrita: Não

Controle Listbox

Nome: lstProduto *
Origem da linha: SELECT Produto.codProduto, Produto.descricao, 
                 Produto.unidade, Produto.valorUnitario, Produto.estoqueMinimo,
                 Produto.qtdEstoque FROM Produto ORDER BY Produto.descricao; *
Tipo de Origem da Linha: Tabela/Consulta *
Coluna acoplada: 1 *
Número de colunas: 6 *
Largura das colunas: 0cm;5cm;1cm;2cm;1cm;1cm *
Largura: 10cm
Cor do fundo: Cinza claro

Controles Textbox

Nome: txtPesquisa *
Cor do fundo: Amarelo
Alinhamento: Esquerda

Nome: txtCodigo *
Ativado: Não *
Bloqueado: Sim *
Cor do fundo: Cinza
Alinhamento: Centro

Nome: txtDescricao *
Cor do fundo: Azul claro
Alinhamento: Esquerda

Nome: txtUnidade *
Cor do fundo: Azul claro
Alinhamento: Esquerda

Nome: txtValorUnitario *
Cor do fundo: Azul claro
Alinhamento: Direita
Formato: Unidade Monetária

Nome: txtQtdEstoque *
Cor do fundo: Azul claro
Alinhamento: Centro
Formato: 00

Nome: txtEstoqueMinimo *
Cor do fundo: Cinza
Alinhamento: Centro
Formato: 00

Botões de Comando

Nome: btnNovo *
Legenda: Novo
Cor da Fonte: Azul escuro

Nome: btnSalvar *
Legenda: Salvar
Cor da Fonte: Azul escuro

Nome: btnExcluir *
Legenda: Excluir
Cor da Fonte: Vermelho escuro

Como sugestão de design os campos deverão estar posicionados conforme demonstrado na figura a seguir, assim como devem ser adicionadas as legendas dos campos, as quais não foram descritas anteriormente:

Classe no Access 2007/2010

 

Códigos do Formulário

Para que nosso formulário seja capaz de manipular os dados dos objetos produto deveremos implementar as funcionalidades necessárias que permitam criar um novo produto, buscar um produto já cadastrado, editar seus dados, salvá-lo ou excluí-lo.

Sendo assim criaremos algumas funções genéricas que sejam úteis para quantos procedimentos delas necessitem, reaplicando o conceito da reutilização de código. Além disso incluiremos os códigos dos campos que possuem eventos, além dos botões de comando.

Todos os códigos a seguir deverão ser colocados no módulo do formulário FProduto.

1. Pesquisa de produtos: Para facilitar a busca de produtos por qualquer parte do nome utilizaremos um campo de texto cujo valor será o elemento condicional para o código SQL que será atribuído ao controle lstProduto, atualizando sua propriedade Origem da Linha após cada alteração realizada no campo de pesquisa. Para isto devemos colocar o código no evento Ao Alterar do campo txtPesquisa.

Private Sub txtPesquisa_Change()
 
  lstProduto.RowSource = "SELECT codProduto, descricao, " & _
        "unidade, valorUnitario, estoqueMinimo, qtdEstoque " & _
        "FROM Produto " & _
        "WHERE descricao Like '*" & txtPesquisa.Text & "*' " & _
        "ORDER BY Produto.descricao;"
  lstProduto.Requery
 
End Sub

2. Limpeza dos campos: Para efetuar a limpeza dos campos de preenchimento utilizaremos um procedimento genérico cuja função será a de atribuir o valor nulo a todos os campos de texto e enviar o foco ao campo txtDescricao.

Private Sub limpaCampos()

  txtCodigo = Null
  txtDescricao = Null
  txtUnidade = Null
  txtValorUnitario = Null
  txtQtdEstoque = Null
  txtEstoqueMinimo = Null
  txtDescricao.SetFocus
 
End Sub

3. Novo registro: Para a criação de um novo registro em branco simplesmente iremos chamar o procedimento limpaCampos() no evento Ao Clicar do botão btnNovo.

Private Sub btnNovo_Click()
 Call limpaCampos
End Sub

4. Atualização de campos: Assim como fizemos um procedimento genérico que limpa os campos para a criação de um novo registro teremos também um que preencha os campos com as informações de um objeto produto passadas como parâmetro, ou seja, o procedimento recebe um objeto completo e lança os valores de seus atributos nos campos do formulário.

Private Sub atualizaCampos(argProduto As clsProduto)

  txtCodigo = argProduto.codProduto
  txtDescricao = argProduto.descricao
  txtUnidade = argProduto.unidade
  txtValorUnitario = argProduto.valorUnitario
  txtQtdEstoque = argProduto.qtdEstoque
  txtEstoqueMinimo = argProduto.estoqueMinimo
   
End Sub

5. Escolha de produto: Já que teremos também que trabalhar com produtos já cadastrados, devemos implementar alguma maneira de recuperar suas informações. Faremos isto utilizando a Listbox lstProduto, que utilizará o procedimento atualizaCampos() para preencher os campos com as informações do objeto do produto que foi clicado.

Private Sub lstProduto_Click()

  Dim objProduto As New clsProduto
  Dim codigoProduto As Long
  
  codigoProduto = lstProduto.Value
  
  If objProduto.obter(codigoProduto) Then
    Call atualizaCampos(objProduto)
  End If

End Sub

6. Montagem de um objeto: Esta também é uma função genérica que será utilizada por outros procedimentos ou funções. Seu objetivo é criar um novo objeto produto, coletar os dados digitados nos campos, atribuir ao objeto criado, e devolvê-lo para quem chamou a função.

Private Function buscaCampos() As clsProduto

  Set buscaCampos = New clsProduto

  If IsNull(txtCodigo) Then
    txtCodigo = proximoCodigo("codProduto", "Produto")
  End If
  
  buscaCampos.codProduto = txtCodigo
  buscaCampos.descricao = txtDescricao
  buscaCampos.unidade = txtUnidade
  buscaCampos.valorUnitario = txtValorUnitario
  buscaCampos.qtdEstoque = txtQtdEstoque
  buscaCampos.estoqueMinimo = txtEstoqueMinimo

End Function

7. Salvando um produto: Depois de informados os dados de um novo produto, ou alterados os dados de um produto já cadastrado, necessitaremos de um procedimento que efetue a gravação destes dados. Para isto o botão btnSalvar conterá o código necessário no evento Ao Clicar. Ele fará uso da função buscaCampos(), a qual montará o objeto a ser salvo, e também o método salvar() do objeto, apresentando uma mensagem ao usuário com o resultado da operação. Após salvar os dados de um produto também deveremos atualizar a Listbox para que apresente estes dados, sejam eles novos ou apenas alterados.

Private Sub btnSalvar_Click()

  Dim objProduto As clsProduto
  
  If Not IsNull(txtDescricao) And Not IsNull(txtUnidade) And _ 
  Not IsNull(txtValorUnitario) Then
    
    Set objProduto = buscaCampos
    
    If objProduto.salvar Then
      MsgBox "O produto foi salvo com sucesso.",vbInformation,"Salvar produto"
      lstProduto.Requery
      Call atualizaCampos(objProduto)
    Else
      MsgBox "Ocorreu um erro durante o salvamento.", vbExclamation, _ 
      "Salvar produto"
    End If
  Else
    MsgBox "Informe os dados do produto.", vbExclamation, "Salvar produto"
  End If

End Sub

8. Excluindo um produto: Além de criar e alterar os dados de um produto, é importante que também possamos excluí-lo definitivamente de nosso cadastro. Logo devemos também implementar a funcionalidade para o botão btnExcluir, que conterá o código necessário também no evento Ao Clicar. Ele também deverá fazer uso da função buscaCampos() para a montagem do objeto a ser excluído, pois caso contrário a classe não saberá que objeto deve ser excluído. Em seguida utilizaremos o método excluir() do objeto, apresentando uma mensagem ao usuário com o resultado da operação. É claro que após excluir um produto também deveremos atualizar a Listbox para que a mesma reflita as alterações realizadas.

Private Sub btnExcluir_Click()
 
  Dim objProduto As clsProduto
  
  If Not IsNull(txtCodigo) Then
    
    If MsgBox("Confirma a exclusão do registro?", vbQuestion + vbYesNo, _ 
    "Excluir produto") = vbYes Then
      
      Set objProduto = buscaCampos
      
      If objProduto.excluir Then
        MsgBox "O registro foi excluído com sucesso.", vbInformation, _
        "Excluir produto"
        lstProduto.Requery
        Call limpaCampos
      Else
        MsgBox "Ocorreu um erro durante a exclusão.", vbExclamation, _
        "Excluir produto"
      End If
      
    End If
    
  End If
   
End Sub

Sistema de Exemplo

Novamente será disponibilizado o link para download do sistema de vendas, já atualizado com todos os recursos do estado de desenvolvimento em que se encontrar o projeto.

Mais uma vez recomendo aos desenvolvedores que o consultem apenas para tirar dúvidas e realizar comparações. Aqueles que realmente quiserem aprender façam toda a codificação e a montagem das telas manualmente. Somente assim a sua mente irá se defrontar com as dificuldades do processo e assimilará os passos necessários para a resolução dos problemas e a conclusão dos objetivos.

Segue o link para download:

Caso ainda não esteja com uma tela principal abra o formulário FProduto diretamente na janela Banco de Dados (Access 2003-) ou no Painel de Navegação (Access 2007+).

Conclusão

Nesta fase não encontramos praticamente nada de novo, mas tivemos a chance de relembrar a maioria dos procedimentos vistos até o momento. A codificação das funcionalidades da classe Produto são muito semelhantes à codificação da classe Cliente. Porém este era o nosso objetivo: relembrar o passo-a-passo necessário para utilizar objetos em sistemas informatizados no MS-Access/VBA.

Com relação à parte realmente prática da série de artigos estamos chegando na reta final. No próximo artigo, que será o último em que trabalharemos com a programação de classes, poderemos perceber um pouco mais da dinâmica de troca de informações entre os objetos de um sistema. Ao realizarmos vendas de produtos para clientes estaremos englobando a utilização de todas as nossas classes de uma só vez, trabalhando com vários objetos instanciados simultaneamente para a conclusão das tarefas.

Com toda certeza você, caro leitor que nos acompanha, já deve estar imaginando os objetos se interagindo, os métodos realizando tarefas e retornando valores, os atributos recebendo e fornecendo valores, os objetos sendo enviados inteiramente para métodos de outros objetos, e assim sucessivamente.

É isto aí, orgulhe-se de dizer: Agora estou quase dominando essa tal de OO!

Encontro vocês no próximo então...


 

 


3 comentários

Luis Eugenio Riquelme Pino   09/02/2012 02:08:07

Este é um dos melhores sites sobre MS Access, muito bom e profundo, bem explicado, Obrigado Sr Plinio

Plinio Mabesi   09/02/2012 11:27:15

Obrigado Luis...
Eu é que agradeço a sua visita no site do amigo Avelino.
Visite também meu site: www.mabesi.com

Lázaro Kiosa   29/06/2012 07:46:31

ainda não explorei o site porque so descobri agora,
mais ja da para ti parabenizar pelo site Sr Plinio


Envie seu comentário: