Utilizando Classe no Access - As Classes Auxiliares
Nota importante: para ter acesso aos vídeos e arquivos exemplos deste site, adquira um dos planos apresentados abaixo. Você pode comprar em até 5x no Cartão de Crédito, através do Paypal.
Veja como comprar e saiba mais sobre o material oferecido, clicando aqui.
Por: Plinio Mabesi
No último artigo vimos a modelagem do sistema. Agora chegou a hora de começarmos a codificar nossas primeiras classes.
As classes auxiliares serão responsáveis por realizar tarefas genéricas que atendem a solicitações de diversas outras classes ou mesmo outros módulos do sistema.
Poderíamos criar inúmeras classes auxiliares, com funções agrupadas pelo tipo de tarefa a ser realizada, assim como a classe ConexaoBD que trata de questões de conexão com banco de dados e a classe Utilitario que contempla funções de validação e conversão de dados.
A idéia principal aqui é a reutilização de código, um dos pilares da orientação a objetos. Percebam que nós codificaremos a classe ConexaoBD apenas uma única vez em toda a nossa vida. No próximo sistema que montarmos simplesmente a importaremos para o novo software, e a classe já deverá estar pronta para ser usada. Pode ser que a codifiquemos para outro tipo de banco de dados, por exemplo uma ConexaoBDMySql ou uma ConexaoBDSqlServer, mas cada codificação será única e praticamente eterna.
Vamos então rever a descrição de cada classe. Em seguida faremos a codificação. O código das funções será apresentado apenas com comentários mas sem detalhamento, já que (novamente) a criação de algoritmos e a estruturação de procedimentos e funções não é o foco deste curso.
A Classe Utilitario
Objetivo: oferecer funcionalidades de validação de dados e transformação de valores, necessárias para o correto funcionamento da classe Cliente, ou qualquer outra classe ou função que venha a precisar dela, a qualquer momento. Isto se deve ao fato da classe possuir métodos genéricos e reutilizáveis, podendo ser reaproveitados, sem nenhuma alteração, em qualquer sistema.
Método validaCpf(argCpf As String) As Boolean: recebe como argumento um texto contendo um CPF, sem pontos nem traço, e devolve um valor booleano, verdadeiro ou falso, indicando se o CPF é ou não válido;
Function validaCPF(argCpf As String) As Boolean 'Função que verifica a validade de um CPF. Dim wSomaDosProdutos Dim wResto Dim wDigitChk1 Dim wDigitChk2 Dim wStatus Dim wI 'Inicia o valor da Soma wSomaDosProdutos = 0 'Para posição I de 1 até 9 For wI = 1 To 9 'Soma = Soma + (valor da posição dentro do CPF x (11 - posição)) wSomaDosProdutos = wSomaDosProdutos + Val(Mid(argCpf, wI, 1)) * (11 - wI) Next wI 'Resto = Soma - ((parte inteira da divisão da Soma por 11) x 11) wResto = wSomaDosProdutos - Int(wSomaDosProdutos / 11) * 11 'Dígito verificador 1 = 0 (se Resto=0 ou 1 ) ou 11 - Resto (nos casos restantes) wDigitChk1 = IIf(wResto = 0 Or wResto = 1, 0, 11 - wResto) 'Reinicia o valor da Soma wSomaDosProdutos = 0 'Para posição I de 1 até 9 For wI = 1 To 9 'Soma = Soma + (valor da posição dentro do CPF x (12 - posição)) wSomaDosProdutos = wSomaDosProdutos + (Val(Mid(argCpf, wI, 1)) * (12 - wI)) Next wI 'Soma = Soma (2 x dígito verificador 1) wSomaDosProdutos = wSomaDosProdutos + (2 * wDigitChk1) 'Resto = Soma - ((parte inteira da divisão da Soma por 11) x 11) wResto = wSomaDosProdutos - Int(wSomaDosProdutos / 11) * 11 'Dígito verificador 2 = 0 (se Resto=0 ou 1 ) ou 11 - Resto (nos casos restantes) wDigitChk2 = IIf(wResto = 0 Or wResto = 1, 0, 11 - wResto) 'Se o dígito da posição 10 = Dígito verificador 1 E 'dígito da posição 11 = Dígito verificador 2 Então If Mid(argCpf, 10, 1) = Mid(Trim(Str(wDigitChk1)), 1, 1) And _
Mid(argCpf, 11, 1) = Mid(Trim(Str(wDigitChk2)), 1, 1) Then 'CPF válido validaCPF = True Else 'CPF inválido validaCPF = False End If End Function
Método validaEmail(argEmail As String) As Boolean: recebe como argumento um texto contendo um e-mail e devolve um valor booleano, verdadeiro ou falso, indicando se o e-mail é ou não válido, sendo que a verificação é feita apenas no seu formato;
Function validaEmail(eMail As String) As Boolean 'Função de validação do formato de um e-mail. Dim posicaoA As Integer Dim posicaoP As Integer 'Busca posição do caracter @ posicaoA = InStr(eMail, "@") 'Busca a posição do ponto a partir da posição 'do @ ou então da primeira posição posicaoP = InStr(posicaoA Or 1, eMail, ".") 'Se a posição do @ for menor que 2 OU 'a posição do ponto for menor que a posição 'do caracter @ If posicaoA < 2 Or posicaoP < posicaoA Then 'Formato de e-mail inválido validaEmail = False Else 'Formato de e-mail válido validaEmail = True End If End Function
Método nomeProprio(argNome As String) As String: recebe como argumento um texto qualquer e devolve o mesmo texto com as inicias dos nomes em maiúsculas e o restante em minúsculas, levando em consideração as partículas de ligação de nomes, as quais permanecem em minúsculas;
Function nomeProprio(argNome As String) As String 'Função recursiva para converter a primeira letra 'dos nomes próprios para maiúscula, mantendo os 'aditivos em caixa baixa. Dim sNome As String Dim lEspaco As Long Dim lTamanho As Long 'Pega o tamanho do nome lTamanho = Len(argNome)
'Passa tudo para caixa baixa
argNome = LCase(argNome)
'Se o nome passado é vazio 'acaba a função ou a recursão 'retornando string vazia If lTamanho = 0 Then nomeProprio = "" Else 'Procura a posição do primeiro espaço lEspaco = InStr(argNome, " ") 'Se não tiver pega a posição da última letra If lEspaco = 0 Then lEspaco = lTamanho 'Pega o primeiro nome da string sNome = Left(argNome, lEspaco) 'Se não for aditivo converte a primeira letra If Not InStr("e da das de do dos ", sNome) > 0 Then sNome = UCase(Left(sNome, 1)) & LCase(Right(sNome, Len(sNome) - 1)) End If 'Monta o nome convertendo o restante através da recursão nomeProprio = sNome & nomeProprio(LCase(Trim(Right(argNome, lTamanho - lEspaco)))) End If End Function
Método desacentua(argTexto As String) As String: recebe como argumento um texto qualquer e devolve o mesmo texto sem acentos ou símbolos;
Function desacentua(ByVal argTexto As String) As String 'Função que retira acentos de qualquer texto. Dim strAcento As String Dim strNormal As String Dim strLetra As String Dim strNovoTexto As String Dim intPosicao As Integer Dim i As Integer 'Informa as duas sequências de caracteres, com e sem acento strAcento = "ÃÁÀÂÄÉÈÊËÍÌÎÏÕÓÒÔÖÚÙÛÜÝÇÑãáàâäéèêëíìîïõóòôöúùûüýçñ" strNormal = "AAAAAEEEEIIIIOOOOOUUUUYCNaaaaaeeeeiiiiooooouuuuycn" 'Retira os espaços antes e após argTexto = Trim(argTexto) 'Para i de 1 até o tamanho do texto For i = 1 To Len(argTexto) 'Retira a letra da posição atual strLetra = Mid(argTexto, i, 1) 'Busca a posição da letra na sequência com acento intPosicao = InStr(1, strAcento, strLetra) 'Se a posição for maior que zero If intPosicao > 0 Then 'Retira a letra na mesma posição na 'sequência sem acentos. strLetra = Mid(strNormal, intPosicao, 1) End If 'Remonta o novo texto, sem acento strNovoTexto = strNovoTexto & strLetra Next 'Devolve o resultado desacentua = strNovoTexto End Function
Método abreviaNome(argNome As String) As String: recebe como argumento um texto qualquer e devolve o mesmo texto com a penúltima parte do nome abreviada, levando em consideração as partículas de ligação de nomes, as quais permanecem inalteradas.
Function abreviaNome(argNome As String) As String 'Função que abrevia o penúltimo sobrenome, levando 'em consideração os aditivos de, da, do, dos, das, e. 'Define variáveis para controle de posição e para as 'partes do nome que serão separadas e depois unidas 'novamente. Dim ultimoEspaco As Integer, penultimoEspaco As Integer Dim primeiraParte As String, ultimaParte As String Dim parteNome As String Dim tamanho As Integer, i As Integer 'Tamanho do nome passado 'no argumento tamanho = Len(argNome) 'Loop que verifica a posição do último e do penúltimo 'espaços, utilizando apenas um loop. For i = tamanho To 1 Step -1 If Mid(argNome, i, 1) = " " And ultimoEspaco <> 0 Then penultimoEspaco = i Exit For End If If Mid(argNome, i, 1) = " " And penultimoEspaco = 0 Then ultimoEspaco = i End If Next i 'Caso i chegue a zero não podemos 'abreviar o nome If i = 0 Then abreviaNome = argNome Exit Function End If 'Separação das partes do nome em três: primeira, meio e última primeiraParte = Left(argNome, penultimoEspaco - 1) parteNome = Mid(argNome, penultimoEspaco + 1, ultimoEspaco - penultimoEspaco - 1) ultimaParte = Right(argNome, tamanho - ultimoEspaco) 'Para a montagem do nome já abreviado verificamos se a parte retirada 'não é um dos nomes de ligação: de, da ou do. Caso seja usamos o método 'recursivo para refazer os passos. 'Caso seja necessário basta acrescentar outros nomes de ligação para serem 'verificados. If parteNome = "da" Or parteNome = "de" Or parteNome = "do" Or _
parteNome = "dos" Or parteNome = "das" Or parteNome = "e" Then abreviaNome = abreviaNome(primeiraParte & " " & parteNome) & " " & ultimaParte Else abreviaNome = primeiraParte & " " & Left(parteNome, 1) & ". " & ultimaParte End If End Function
A Classe ConexaoBD
Objetivo: oferecer funcionalidades de consulta e atualização do banco de dados. Possui também métodos genéricos que podem ser reaproveitados em qualquer sistema. Uma das maiores vantagens de se utilizar uma classe de conexão é que no caso de mudança do tipo de Sistema Gerenciador de Banco de Dados (SGBD) somente ela deverá ser alterada, permanecendo todas as outras intocadas, desde que seja mantida a interface de comunicação dos métodos. Um exemplo seria a troca do back-end para MySql, Postgres ou Sql Server.
Declaração de Atributo de Banco de Dados a Nível de Classe
Criaremos um atributo que será responsável por receber e disponibilizar o banco de dados para ser utilizado pelos métodos da classe.
'Cria um database que será utilizado para toda a classe Private db As Database
Função logicoSql(ByVal argValor As Boolean) As String: recebe como parâmetro um valor booleano e devolve um texto contendo os valores True ou False, necessário para códigos SQL;
Function logicoSql(ByVal argValor As Boolean) As String 'Função que troca os valores lógicos Verdadeiro/Falso 'para True/False para utilização em consultas SQL 'Se o valor for verdadeiro If argValor Then 'Troca por True logicoSql = "True" Else 'Senão troca por False logicoSql = "False" End If End Function
Função pontoVirgula(ByVal varValor As Variant) As String: recebe como parâmetro um valor decimal em que o padrão de separação da parte inteira e a decimal é a vírgula, e devolve um texto contendo o mesmo valor agora separado por ponto, necessário para códigos SQL;
Function pontoVirgula(ByVal varValor As Variant) As String 'Função que troca a vírgula de um valor decimal por 'um ponto para utilização em consultas SQL Dim strValor As String Dim strInteiro As String Dim strDecimal As String Dim intPosicao As Integer 'Converte o valor em string strValor = CStr(varValor) 'Busca a posição da vírgula intPosicao = InStr(strValor, ",") 'Se há uma vírgula em alguma posição If intPosicao > 0 Then 'Retira a parte inteira strInteiro = Left(strValor, intPosicao - 1) 'Retira a parte decimal strDecimal = Right(strValor, Len(strValor) - intPosicao) 'Junta os dois novamente incluindo 'agora o ponto no lugar da vírgula pontoVirgula = strInteiro & "." & strDecimal Else 'Senão devolve o mesmo valor pontoVirgula = strValor End If End Function
Função dataSql(ByVal argData As Date) As String: recebe como parâmetro uma data em qualquer formato e devolve um texto contendo a data no padrão #mm/dd/yyyy#, necessário para códigos SQL;
Function dataSql(ByVal argData As Date) As String 'Função que formata uma data para o modo SQL 'com a cerquilha: #mm/dd/yyyy# Dim strDia As String, strMes As String, strAno As String 'Retira dia, mês e ano strDia = Day(argData) strMes = Month(argData) strAno = Year(argData) 'Remonta no formato adequado dataSql = "#" & strMes & "/" & strDia & "/" & strAno & "#" End Function
Função valorSql(ByVal argValor As Variant) As String: recebe como parâmetro um valor qualquer, verifica o seu formato e devolve um valor no formato padrão dos códigos SQL, fazendo uso das funções anteriores, caso necessário;
Function valorSql(ByVal argValor As Variant) As String 'Função que formata valores para utilização 'em consultas SQL 'Seleciona o tipo de valor informado Select Case VarType(argValor) 'Caso seja vazio ou nulo apenas 'devolve a string Null Case vbEmpty, vbNull valorSql = "Null" 'Caso seja inteiro ou longo apenas 'converte em string Case vbInteger, vbLong valorSql = CStr(argValor) 'Caso seja simples, duplo, decimal ou moeda 'substitui a vírgula por ponto Case vbSingle, vbDouble, vbDecimal, vbCurrency valorSql = pontoVirgula(argValor) 'Caso seja data chama a função dataSql() Case vbDate valorSql = dataSql(argValor) 'Caso seja string acrescenta aspas simples Case vbString valorSql = "'" & argValor & "'" 'Caso seja lógico chama a função logicoSql() Case vbBoolean valorSql = logicoSql(argValor) End Select End Function
Função executa(codigoSql As String) As Long: recebe como argumento um texto contendo um código SQL de inserção, exclusão ou alteração, executa o código e devolve o número de registros afetados na operação;
Function executa(codigoSql As String) As Long On Error GoTo Err_executa 'Atualiza dados no Banco utilizando o código Sql passado à função, 'retornando o número de registros afetados caso a operação ocorra 'com sucesso ou 0 caso ocorra algum problema Set db = Currentdb db.Execute codigoSql executa = db.RecordsAffected Exit_executa: Set db = Nothing Exit Function Err_ executa: executa = 0 Resume Exit_executa End Function
Função consulta(codigoSql As String, Optional editavel As Boolean = False) As Recordset: recebe como argumento um texto contendo um código SQL de consulta de registros e um valor lógico que define o modo de bloqueio de execução, permitindo ou não a edição dos dados durante a operação, e devolve um recordset contendo o conjunto de registros que atenderem aos critérios;
Function consulta(codigoSql As String, Optional editavel As Boolean = False) As Recordset On Error GoTo Err_consulta 'Consulta os dados no Banco utilizando o código Sql passado à função, 'retornando um recordset com o resultado da consulta Set db = Currentdb If editavel Then Set consulta = db.OpenRecordset(codigoSql, , dbInconsistent, dbOptimistic) Else Set consulta = db.OpenRecordset(codigoSql, dbOpenSnapshot, dbReadOnly) End If Exit_consulta: Set db = Nothing Exit Function Err_consulta: MsgBox "Erro SQL: " & codigoSql Set consulta = Nothing Resume Exit_consulta End Function
Após criar os métodos salve as classes, mas não se esqueça que para salvar convencionamos que seria utilizado o prefixo acl para classes auxiliares. Então salvaremos as classes com os nomes aclUtilitario e aclConexaoBD.
Instanciação dos Objetos
Com as classes já codificadas e salvas podemos instanciá-las a partir de qualquer módulo do nosso aplicativo. Vamos fazer um teste com cada uma das classes criadas. Para isto voltaremos ao nosso módulo padrão TesteClasse.
Primeiro a classe Utilitario. Vamos criar o procedimento TesteUtilitario:
Sub TesteUtilitario() 'Declarando o objeto da classe Utilitario Dim objUtil As New aclUtilitario 'Testando um método da classe, convertendo um 'nome em minúsculas para o padrão de nomes próprios 'com a primeira letra maiúscula MsgBox objUtil.nomeProprio("plinio mabesi") End Sub
Perceba que após digitarmos o ponto depois do nome do objeto os métodos disponíveis são listados no menu suspenso do editor do VBA.
Com isso você pode digitar o nome do método ou escolher um deles na lista suspensa. Conforme já vimos antes para executar o código basta posicionar o cursor dentro do procedimento e pressionar F5, ou F8 para acompanhar a execução passo-a-passo.
O resultado será uma caixa de mensagem exibindo o nome informado no formato de um nome próprio, com as iniciais maiúsculas:
Agora a classe ConexaoBD. Vamos criar o procedimento TesteConexao:
Sub TesteConexaoBD() 'Declarando o objeto da classe ConexaoBD Dim objCon As New aclConexaoBD 'Testando um método da classe, convertendo 'uma data para o padrão SQL MsgBox objCon.dataSql("12/06/10") End Sub
Assim como no objeto da classe Utilitario, ao digitarmos o ponto após o nome do objeto da classe ConexaoBD veremos a lista suspensa com os métodos disponíveis:
Com certeza você notou que o atributo db (Database) não foi apresentado, devido ao fato de ser um atributo privado (Private).
Perceba também que quando digitamos o primeiro parêntese após o nome do método o editor do VBA nos mostra quais são os parâmetros exigidos, o seu tipo e o tipo de dado de retorno do método.
No caso do método dataSql() deveremos informar o parâmetro argData que será passado por valor (ByVal) e é do tipo Date, e teremos como retorno uma String. Veja:
Ao executarmos este procedimento teremos como resultado uma caixa de mensagem exibindo a data informada no padrão de utilização do SQL, conforme figura abaixo.
No padrão SQL veja que o mês vem em primeiro lugar, seguido pelo dia e depois pelo ano, tudo delimitado pela cerquilha. Todos os códigos SQL devem estar com as datas neste formato, caso contrário ocorrerá um erro e o código não será executado.
Você não só pode como deve fazer testes com os outros métodos. Crie exemplos de utilização para cada um deles. Se encontrar dificuldade aguarde os próximos artigos, nos quais faremos uso intenso destas duas classes. Mesmo assim o melhor é nunca desistir...
Conclusão
Nosso sistema começa a tomar forma de um software de verdade. Nesta etapa vimos como codificar as classes auxiliares e tivemos uma noção de como instanciá-las para utilizar os métodos disponibilizados.
Apesar de não ter sido detalhada a criação da estrutura dos comandos e dos algoritmos dos métodos, os comentários o ajudarão a compreender o mínimo necessário para produzir seus próprios códigos. Caso não tenha entendido algum trecho pesquise sobre as funções, comandos e tipos utilizados.
Conforme salientado no início deste artigo, o principal conceito que deve ser lembrado no momento é o da reutilização de código. A reutilização se refere a qualquer procedimento, função ou método que possa ser diretamente empregado em qualquer projeto imediatamente, sem necessidade de ajuste ou adaptação. Com a orientação a objetos procuramos fazer isto com classes inteiras. As classes Utilitario e ConexaoBD são dois exemplos de classes reutilizáveis que não requerem qualquer modificação para funcionarem em um projeto do Access.
Claro que alguém poderia dizer que estaria faltando um ou outro método ou atributo, ou que na verdade os métodos existentes não são os melhores, mas o importante no momento é o conceito da reutilização e não a modelagem mais eficiente e mais correta. Entenda que após projetar a classe mais perfeita possível e codificá-la, então ela poderá ser distribuída para ser importada e incorporada por qualquer projeto.
Em nossa próxima etapa poderemos enfim ver o sistema de vendas funcionando pela primeira vez, pois iremos implementar a classe Cliente, bem como a interface gráfica para cadastro e manuseio dos dados, tudo isto sem campos acoplados, apenas usando os objetos da classe.
Até lá então...
Artigos Relacionados
Utilizando Classe no Access - Introdução
Utilizando Classe no Access - Parte 1 - Orientação a Objetos
Utilizando Classe no Access - Parte 2 - Programação OO no Access/Vba
Utilizando Classe no Access - Parte 4 - As Classes Auxiliares
Utilizando Classe no Access - Parte 5 - A Classe Cliente
Utilizando Classe no Access - Parte 6 - A Classe Produto
Utilizando Classe no Access - Parte 7 - As Classes Venda e Detalhe de Venda
Utilizando Classe no Access - Parte 8 - Finalização do Sistema
Utilizando Classe no Access - Parte 9 - Genesis: A Ferramenta Case
Utilizando Classe no Access - Parte 10 - Conclusão
Como estudar com o Pesquisador de Objetos
13 comentários Sandro 10/04/2023 22:58:09 Bom dia! Tentei usar a função nomeproprio e não consegui, vc não tem algum arquivo com esta função sendo utilizada? Desde já agradeço! Plinio Mabesi 09/10/2020 16:05:37 Olá Ader Primeiramente muito obrigado. Sobre o erro não encontrei nenhum bloco faltando o fechamento com End If. Utilizo o Access 2007 para montar todos os exemplos, salvando em formato anterior, e até o momento não tive nenhum problema deste tipo. Se puder verificar novamente seu código para ver se o erro está em outro local e me avisar, agradeço. Caso não encontre o problema e queira me mandar o bd com o trecho que está dando erro estarei a disposição. Até mais... Ader Santos 06/10/2020 13:27:21 Grande Plínio, sucesso total! Só tem uma coisinha, na função nomeProprio, falta fechar um bloco com End If, senão dá "tipos incompatíveis" no Access 2007. Abração. Gilson Gindre 24/06/2020 07:35:09 Plinio, fiquei sem palavras, não sei como agradecer seu tamanho esforço para com todos nós da area ! para se ter uma ideia eu já estou programando em Php MySql, mas a paixão pela facilidade do access fala mais alto, e agora com estes recuros todos, estou sem palavras para agradecer você e o Avelino, e parabens pelo site, que veio para ficar ! Renato Novelli 23/06/2020 10:46:46 Exceleeeeente artigo! Muito obrigado por compartilhar com todos essa valiosíssima informação. Será de muita utilidade para o desenvolvimento de minhas aplicações. Esse tipo de material é realmente muito útil e valoriza em muito o trabalho dos desenvolvedores de aplicações em Access. Estou ansioso para ver o próximo artigo! Parabéns! Plinio Mabesi - Anápolis-GO 20/06/2020 12:59:31 Olá Rodrigo Obrigado a vc e a todos que nos prestigiam... Se vc colocar esta função em um módulo padrão (que não seja de classe nem de formulário) vc poderá fazer exatamente desta maneira que fez, porém coloque no evento Após Atualizar. Rodrigo Monteiro 20/06/2020 12:37:56 Caríssimo Plinio...... Meus parabéns por sua disposição em compratilhar conhecimento.... Fiquei muito interessado na função "nomeProprio"...... Mas não consegui aplicá-la numa caixa de texto..... tentei assim no evento "ao atualizar": Campo=nomeProprio(Campo) Poderia me dizer como pode ser usada essa função?! Desde já agradeço muito!!! João Martins/Joinville/SC 19/06/2020 21:46:55 Parece-me que a parceria de Avelino e o Profº Plinio esta produzindo resultados positivos e quiçá seja duradoura; tenho aprendido muito. Visionários e vencedores se destacam assim: - compartilhando seus conhecimentos, pois de nada servem enclausurados nas suas cabeças. Parabéns aos dois! Falou Access, falou www.usandoaccess.com.br Américo 18/06/2020 16:42:57 Show de bola. Tem uma aplicação feita para ilustrar um livro (Desenvolvendo Aplicativos Com Visual Basic e Uml) que usa conceitos de programação orientada a objetos, com uma GUI web. Praticamente tudo que foi implementado nesses exemplos pode ser importado e adaptado para VBA. Os fontes estão em: http://www.jacksonreed.com/VBUML.HTM. Obs.: Para visualizar o projeto completo é necessário o VB6 instalado. Márcio Melo - Rio de Janeiro/RJ 17/06/2020 22:47:45 Material nota 10, muito show, parabéns por pensar nessas funçoes, quem trabalhar com OO vai precisar muito, isso mostrar um trabalho completo e maduro, cada vez o site vai se tornando forte referência no access avançado... Sou mais Brasil! Marcos_Novack 22/04/2020 18:54:44 Sem duvida muito bom os ensinamentos Notei que, no testeUtilitario() foi trocado o inicio do nome da classe, de "cls" para "acl" nos testes anteriores começava com "cls"; notei porque deu erro. obrigado. Alex Sandro Risso 04/03/2020 14:46:32 MUITO OBRIGADO Agradeço deveras as explicações, tornado essa fonte ama ajuda grandiosa para os iniciantes como eu Obrigado! Alex Sandro Risso 04/03/2020 14:46:11 MUITO OBRIGADO Agradeço deveras as explicações, tornado essa fonte ama ajuda grandiosa para os iniciantes como eu Obrigado! |