Dica 1 - Abrindo automaticamente um controle Combobox
Para fazer com que o controle Combobox abra automaticamente, basta usar a propriedade Dropdownno evento "Ao receber o foco". Private sub NomeDaCombo_GotoFocus() Me!NomeDaCombo.dropdown End sub Dica 2 - Inibindo mensagens do Access Ao executar uma consulta de ao (DELETE, INSERT ou UPDATE) com o comando Docmd.RunSQL, uma mensagem do Access exibida informando a quantidade de registros afetadas pela consulta. Veja a imagem:
Para desativar esta mensagem usamos o comando docmd.SetWarnings Docmd.SetWarnings false 'Desativa a mensagem do Access Docmd.RunSQL "DELETE * FROM tblClientes;" Docmd.SetWarnings true 'Ativa a mensagem do Access Minha preferncia utilizar o comando Currentdb.Execute que no retorna a mensagem do Access e assim economizo duas linhas na digitao. 'No retorna mensagem do Access ao executar a consulta Currentdb.Execute "DELETE * FROM tblClientes;" Pode tambm inibir esta mensagem, configurando o seu Access pelas "Opes" do Access. Veja aquineste meu artigo. Dica 3 - Abrindo formulrio de cadastro na posio novo registro Na chamada do formulrio basta utilizar o valor acFormAdd do argumento DataMode 'Abre o formulrio direto na posio novo registro Docmd.OpenForm "NomeDoFormulrio",,,,acFormAdd Uma outra forma passar a propriedade "Entrada de dados" do formulrio para SIM
Esta tcnica acelera a abertura do formulrio, pois o Access deixa de carregar os registros existentes, contribuindo em muito para o desempenho do seu aplicativo, principalmente se estiver trabalhando em rede. Dica 4 - Contando as linhas de uma ListBox Na propriedade Fonte do Controle do campo que ir receber a contagem, coloque: =[NomeDoCampoListBox].ListCount Dica 5 - Alterando as primeiras letras dos nomes para Maisculas Para corrigir as letras iniciais dos nomes podemos utilizar a funo srtConv() strConv("avelino sampaio",vbProperCase) :::> Avelino Sampaio Se deseja atualizar todos os registros de um campo especfico, utilize uma consulta Atualizao com a seguinte configurao: 'Ateno: Realize um backup antes de aplicar a consulta Currentdb.Execute "UPDATE NomeTabela SET NomeCampo = strConv(NomeCampo,3);"
'vbProperCase no reconhecido pelo VBA quando colocado entre as aspas; por 'isso foi utilizado o seu valor numrico correspondente(3). Dica 6 - Reconhecendo valores de senhas Case Sensitive. J teve a necessidade de implementar senhas, diferenciando caracteres maisculos de minsculos ? Para esta finalidade utilizamos a funo strComp(). strComp("avelino","Avelino",vbBinaryCompare) :::> 1
'A funo retorna 0(zero) para strings iguais e 1 para strings diferentes. Veja como pode ser aplicado numa condicional IF. ... strSenhaUsuario = Dlooukup("senha","tblUsurios",idUsuario =" & me!idUsuario) If strComp(me!CampoSenha,strSenhaUsuario,vbBinaryCompare) = 1 then msgbox "Senha incorreta....",vbInformation ,"Aviso" ... end if ... Dica 7 - Conhecendo a funo eval() para analisar expresses. Gosto muito desta funo que facilita bastante a programao em vrias situaes. A funo retornaTrue (-1) ou False(0) conforme a anlise da expresso. Exemplo bem simples: eval("1=2") :::>Retorna false(0) eval("1=1") :::>Retorna true(-1) Vamos supor que voc queira que um determinado boto de seu formulrio seja ativado apenas nos horrios entre s 9 horas e 11 horas da manh: me!NomeBoto.Enabled = eval("time() Between #9:00 am# And #11:00 am#") Agora, vamos supor que voc queira esconder um Campo_B, caso o Campo_A tenha sido preenchido com um dos seguintes valores: Azul, Preto ou Prata. me!Campo_B.visible = eval("""" & me!Campo_A & """ IN('Azul','Preto','Prata')") Dica 8 - Fazendo Download de uma pgina Web para um arquivo local no formato txt. O objeto XMLHTTP usado para baixar a pgina. E a instruo OPEN do Access para criar e gravar em arquivo txt. Leia com ateno os comentrios: Public Sub fncDownloadPagina(Url As String, DestFileName As String) Dim HttpReq As Object Dim hFile As Integer On Error GoTo trataErro Set HttpReq = CreateObject("Msxml2.ServerXMLHTTP.6.0") '-------------------------- 'Abre a pgina Web indicada '--------------------------- HttpReq.Open "GET", Url, False '-------------------------------------- 'Passa a pgina para a varivel HttpReq '-------------------------------------- HttpReq.send hFile = FreeFile '--------------------------------------------------------------- 'Cria o arquivo txt no local indicado pela varivel DestFileName '--------------------------------------------------------------- Open DestFileName For Output As #hFile '------------------------------------------------------------------------- 'Passa o cdigo Html/Xml, que est na varivel HttpReq, para o arquivo txt '------------------------------------------------------------------------- Print #hFile, StrConv(HttpReq.ResponseBody, vbUnicode) '------------------- 'Fecha o arquivo txt '------------------- Close #hFile MsgBox "Pgina salva com sucesso...", vbInformation, "Aviso" Sair: Exit Sub trataErro: MsgBox "No foi possvel gravar a pgina. Verifique se o endereo da _ pgina est correto...", vbInformation, "aviso" Resume Sair: End Sub Mais detalhes sobre o objeto XMLHTTP aqui Exemplo de chamada: fncDownloadPagina "http://www.usandoaccess.com.br","c:\SuaPasta\PaginaUA.txt" Dica 9 - Mantendo o foco depois de usar o mtodo Requery, em um formulrio contnuo. Ao usar o mtodo Requery para atualizar a base de dados de um formulrio contnuo, o ponteiro deslocado para o primeiro registro e isto muitas das vezes no o desejado. Ento, para manter o foco no registro atual, aps o uso do Requery, pode ser utilizado o seguinte cdigo: Dim rs rs = Me.Bookmark Me.Requery Me.Bookmark = rs Dica 10 - Usando a instruo NAME do Access para renomear arquivos. raramente utilizada, mas no custa nada voc saber que existe. Uma vez precisei renomear todos os arquivo JPG de uma pasta, acrescentando o ano 2013. Veja o procedimento utilizado e atente para os comentrios: Public Sub fncRenomearJpg(strCaminho as string, Ano as Integer) Dim strArquivo As String Dim strMod as String '--------------------------------------------------- 'Carrega todos os arquivo jpg na varivel strArquivo '---------------------------------------------------- strArquivo = Dir$(strCaminho & "*.jpg") '------------------------------------------------------------------- 'Percorre a lista de arquivos jpg, armazenada na varivel strArquivo '-------------------------------------------------------------------- Do While Len(strArquivo) > 0 '--------------------------------------------- 'Acrescenta ao nome do arquivo o ANO informado '--------------------------------------------- strMod = strCaminho & Replace(strArquivo, ".", "_" & Ano & ".") '--------------------------------------------------------- 'Renomeia o arquivo utilizando a instruo NAME do Access '--------------------------------------------------------- Name strCaminho & strArquivo As strMod '-------------------------------------- 'Passa para o arquivo seguinte da lista '-------------------------------------- strArquivo = Dir$() Loop MsgBox "Arquivos renomeados com sucesso!", vbInformation, "Aviso" End Sub Chamando pelo procedimento: fncRenomearJpg "c:\inter\Imagens\",2013 Sucesso!
100 Dicas - parte 2 Dica 11 - Ativar/desativar por cdigo, as teclas Num Lock, Caps Lock e Scroll Lock. Com a API GetKeyState() possvel identificar o status de cada uma das teclas Num Lock, Caps Lock e Scroll Lock. Para isso, basta informar o cdigo correspondente ao da tecla na API e obter como resultado o valor 0 ou 1. O valor 0 indica que a tecla est desativada (Led apagado) e o valor 1 que a tecla est ativada (Led aceso). Valores das teclas: Num Lock = 144 ou pode fazer ser uso da constante vbKeyNumlock. Caps Lock = 20 ou pode fazer ser uso daconstante vbKeyCapital. Scroll Lock = 145 Option Compare Database #If VBA7 Then 'verses 2010 e 2013 Public Declare PtrSafe Function GetKeyState Lib "user32"(ByVal nVirtKey As Long) As Long #Else 'verses 2007 e anteriores Public Declare Function GetKeyState Lib "user32"(ByVal nVirtKey As Long) As Long #End if
-------------------------------------------------------------------------------------- Public Sub fncAtivarDesativarTecla(Tecla&, Ativar As Boolean) Dim ws As Object Dim T$ Set ws = CreateObject("WScript.shell")
T = switch(Tecla=144,"{numlock}",Tecla=20,"{capslock}",Tecla= 145,"{scrolllock}") If Ativar Then 'Ativar tecla que se encontra desativada If GetKeyState(Tecla) = 0 Then ws.SendKeys T Else 'Desativar tecla que se encontra ativada If GetKeyState(Tecla) = 1 Then ws.SendKeys T End If Set ws = Nothing End Sub Para ativar a tecla Caps Lock: Call fncAtivarDesativarTecla (20, true) Para desativar a tecla Scroll Lock: Call fncAtivarDesativarTecla (145, false) Dica 12 - Como fazer o cdigo VBA esperar por uma informao do usurio. Em alguns casos necessrio interromper a execuo de um cdigo para aguardar por uma informao do usurio. Nestes casos, utiliza-se do argumento WindowMode setado para acDialog, do comando Docmd.OpenForm. No exemplo abaixo, o cdigo aguarda pelo fechamento do formulrio frmRegistro para ento processar as linhas seguintes. Observe os comentrios: Public Sub fncCapturaRegistro() On Error Resume Next '----------------------------------------------------------------------------- 'Abre o formulrio frmRegistro, solicitando a interrupo do cdigo (acDialog) '---------------------------------------------------------------------------- DoCmd.OpenForm "frmRegistro", , , , , acDialog, 1 '--------------------------------------------------------------------------- 'A rotina prossegue a partir deste ponto, somente quando o usurio fechar 'o formulrio. 'A varivel global booRegistrado tem seu valor definido no formulrio 'frmRegistro, por isso necessrio que a rotina aguarde por este valor. '--------------------------------------------------------------------------- If booRegistrado = False Then 'Sai do aplicativo DoCmd.Quit acQuitSaveAll End If End Sub Dica 13 - Como atrasar a execuo de um cdigo Para atrasar a execuo de um cdigo usamos da API Sleep(). Option Compare Database #If VBA7 Then 'verses 2010 e 2013 Public Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) #Else 'verses 2007 e anteriores Public Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long) #End If
Atrasando o cdigo por 3 segundos: Call sleep(3*1000) Veja um exemplo prtico AQUI no meu artigo sobre BINGO. Dica 14 - Disparar eventos de um formulrio A atravs de um formulrio B possvel disparar qualquer evento de um formulrio estando com o foco em outro formulrio. Para isso necessrio trocar o escopo PRIVATE do evento que se deseja disparar para o escopo PUBLIC. Como exemplo, veja o cdigo abaixo de um boto chamado btExcluir do formulrio A. Public Sub btExcluir_Click() On Error Resume Next DoCmd.RunCommand acCmdDeleteRecord End Sub Para chamar o evento acima pelo Formulrio B, basta utilizar o seguinte comando: forms("NomeFormulrioA").btExcluir_Click Dica 15 - Esconder o Access Com a combinao de algumas APIs possvel definir o grau de transparncia do Access e/ou seus objetos. O grau de transparncia tem um range que vai de 0 a 255. O valor zero(0) torna o aplicativo totalmente oculto e 255 totalmente visvel. No cdigo abaixo utilizei apenas os valores 0 e 255, mas nada impede que seja feita uma pequena alterao e outros valores sejam testados. Nota: As APIs sofreram alteraes na sua escrita a partir da verso 2010 do Access. Veja todos os detalhes desta mudana neste meu artigo. Adaptei o cdigo abaixo para atender as diversas verses. Option Compare Database
#If VBA7 Then '------------------------------------------- ' verses 2010 e 2013 - 32 e 64 bits '-------------------------------------------- Declare PtrSafe Function SetLayeredWindowAttributes Lib "user32" _ (ByVal hwnd As LongPtr,ByVal crKey As Long,ByVal bAlpha As Byte,ByVal dwFlags As Long) As Long
Declare PtrSafe Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _ (ByVal hwnd As LongPtr, ByVal nIndex As Long) As Long
Declare PtrSafe Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _ (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
#Else '------------------- 'verso 2007 '------------------ Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" _ (ByVal hwnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" _ (ByVal hwnd As Long, ByVal nIndex As Long) As Long
Declare Function SetLayeredWindowAttributes Lib "user32" _ (ByVal hwnd As Long,ByVal crKey As Long,ByVal bAlpha As Byte,ByVal dwFlags As Long) As Long
Private Function fncOcultarAccess(Ocultar As Boolean) As Boolean Dim lngHwnd As Long Dim bytNivel As Byte lngHwnd = Application.hWndAccessApp bytNivel = IIf(Ocultar, 0, 255) SetWindowLong lngHwnd, GWL_EXSTYLE, GetWindowLong(lngHwnd, GWL_EXSTYLE) Or WS_EX_LAYERED SetLayeredWindowAttributes lngHwnd, 0, bytNivel, LWA_ALPHA fncOcultarAccess = True End Function Esconder o Access: Call fncOcultarAccess(True) Retornar a visualizar o Access: Call fncOcultarAccess(false) Dica 16 - Como realizar busca de contedo aqui no site UsandoAccess O site possui um excelente sistema de busca utilizando o Google. Est presente nas pginas Tutoriais e Dicas. Faa um teste entrando com palavras ou frases do seu interesse no campo de pesquisa e clique no boto "Pesquisar o site". Exemplo de palavras para pesquisar: somar, contar, ribbons, horas extras, ...
Dica 17 - Trabalhar com vrios tipos de dados na consulta INSERT Tenho certeza que voc j teve algum grau de dificuldade para fazer funcionar corretamente uma consulta de ao INSERT. Geralmente, a razo principal desta dificuldade est associada aos tipos de dados (string, data, nmeros, ...) envolvidos no processo. Tenho uma regra para voc: utilize apstrofe ou aspas duplas, independentemente do tipo de dado. Observe com ateno, no cdigo abaixo, os diversos tipos de dados: Private Sub btInsert_Click() Dim strSql$
End Sub Para o campo NomeCliente utilizei aspas duplas pelo fato de poder surgir nomes no cadastro com apstrofe. Exemplo: Alexandre D'avila Segue o arquivo exemplo para voc praticar: ConsultaInsert.zip Veja como fica o cdigo utilizando campos de um formulrio: Private Sub btInsert_Click() Dim strSql$
End Sub Nota: para os campos do tipo Mltiplos Valores e Anexo, a tcnica utilizada est neste meu artigo. Dica 18 - Ultrapassando a limitao do operador MOD (resto da diviso) O operador MOD funciona at o numero 2.147.483.647 Resultados: 2147483647 MOD 97 ::::> 65 2147483648 MOD 97 ::::> Erro de execuo 6 (ESTOURO) Para substituir o operador MOD possvel utilizar esta frmula :: Dividendo - INT(Dividendo/divisor)*Divisor Exemplo: 2147483648 - Int(2147483648/97)*97 ::::> 66 Dica 19 - Tipos de variveis representadas por smbolos Ganhar tempo na digitao sempre benvindo e um dos artifcios que voc tem que conhecer a utilizao de smbolos para definir os tipos de variveis. Veja a tabela abaixo: Tipo Smbolo Integer % Long & String $ Currency @ Single ! Double # Byte Nenhum Variante Nenhum Boolean Nenhum Date Nenhum
Exemplo de criao de variveis de diversos tipos: Dim intPedido as integer Dim lngPopulacao as long Dim strNome as string Dim curValorUnitario as Currency Dim sglQuantidade as Single Dim dblPi as Double Que podem ser digitadas desta forma: Dim intPedido% Dim lngPopulacao& Dim strNome$ Dim curValorUnitario@ Dim sglQuantidade! Dim dblPi#
Ou assim
Dim intPedido%, lngPopulacao&, strNome$, curValorUnitario@, sglQuantidade!, dblPi# Observe as variveis declaradas abaixo: Dim A, B, C, D, E as Integer Somente a varivel E que do tipo Integer, o restante do tipo Variante. Para que todas as variveis acima sejam declaradas como as do tipo Integer, necessrio que sejam escritas da seguinte forma: Dim A as Integer, B as Integer, C as Integer, D as Integer, E as Integer
Ou utilizar o smbolo correspondente do Integer
Dim A%, B%, C%, D%, E%
Dica 20 - Usando os dois pontos (:) para representar uma nova linha no VBA Para o VBA, o uso de dois pontos (:) significa que est passando para a prxima instruo. Exemplo de um trecho de cdigo sem o uso de dois pontos. Select Case strcar case "A" to "Z" strTipo = "Maiscula" case "a" to "z" strTipo = "Minscula" case "0" to "9" strTipo = "Nmero" case else strTipo = "Caracter desconhecido" end select
For k = 1 to 100 j = j + k Next Ento, possvel compactar a escrita desta forma: Select Case strCar case "A" to "Z" : strTipo = "Maiscula" case "a" to "z" : strTipo = "Minscula" case "0" to "9" : strTipo = "Nmero" case else : strTipo = "Caracter desconhecido" end select For = k = 1 to 100 : j= j+ k : next Bom estudo!
100 Dicas - parte 3 Dica 21 - Registros afetados por Consultas de Ao Para obter o nmero de registros afetados por Consultas de Ao, utiliza-se a propriedadeRecordsAffected do mtodo CurrentDb. No entanto, para que funcione, preciso passar o mtodoCurrentDb para uma varivel. Veja como fica o cdigo: Dim bd As DAO.Database 'Passando o mtodo para a varivel bd Set bd = CurrentDb 'Executando a consulta de Excluso bd.execute "DELETE * FROM tblOS WHERE year(DataAbertura) < year(date)-7" 'Informando a quantidade de registros excludos MsgBox "Foram excludos " & bd.RecordsAffected & " registros...", _ vbInformation, "Aviso" Dica 22 - Interceptar cancelamento do InputBox Com a funo StrPtr() possvel interceptar se a caixa de entrada InputBox foi cancelada ou fechada pelo usurio.
Nos dois casos, a funo StrPtr() retorna o valor zero(0) : Dim x as Variant x = InputBox("Clique em cancelar ou fechar", "Testando Cancelar") If StrPtr(x) = 0 Then MsgBox "Voc cancelou!" Else 'Trabalhe aqui o valor informado. End If Agora, se desejar tambm, detectar se o usurio clicou no boto OK sem ter entrado com a informao na caixa de texto, basta verificar se a varivel x, que do tipo Variant, continua com o seu valor padro Empty (vazio). Dim x as Variant x = InputBox("Clique em cancelar ou fechar", "Testando Cancelar") If x = empty Then MsgBox "Voc cancelou ou clicou no boto OK sem entrar com o valor...!" Else 'Trabalhe aqui o valor x informado. End If Dica 23 - Modificar estrutura de tabelas do back-and atravs do front-end Com as instrues CREATE TABLE, ALTER TABLE, CREATE INDEX e DROP possvel criar, deletar e modificar tabelas. Por exemplo: para adicionar um campo de nome PrecoUnitario do tipo Currencyem uma tabela de nome tblEstoque, utiliza-se a seguinte instruo: CurrentDb.Execute "Alter Table tblEstoque Add Column PrecoUnitario CURRENCY;" Esta instruo funciona bem para as tabelas locais, porm para as vinculadas preciso indicar na instruo a sua real localizao. Agora, imagine que o back-end esteja localizado na pastac:\MinhaPasta\meuBd_be.accdb. Para este caso, a instruo deve ter a seguinte estrutura: Dim strCaminhoBe As String
strCaminhoBe = "c:\MinhaPasta\meuBd_be.accdb"
CurrentDb.Execute "Alter Table [" & strCaminhoBe & "].tblEstoque Add Column PrecoUnitario CURRENCY;" Se o back-end possuir senha de acesso, a instruo esta: Dim strCaminhoBe As String
Nota: A tabela no pode estar sendo utilizada no momento da alterao, pois receber mensagem de erro. O aplicativo Telemax possui uma rotina bem interessante que adiciona tabelas inteiras ao back-end, alm de acrescentar novos campos e criar relacionamentos. um aprendizado muito til se voc tiver a necessidade de atualizar o back-end pelo front-end, sem precisar ir ao local. Clique aqui para ter acesso ao Telemax. Dica 24 - Vincular e executar consulta de front-end desvinculado Tem a mesma estrutura apresentada da Dica 23, observe: Dim strCaminhoBe As String
CurrentDb.Execute "DELETE * FROM [" & strCaminhoBe & "].tblEstoque WHERE Descontinuado = -1;"
Veja uma variao na estrutura quando utiliza-se o operador IN: Dim strCaminhoBe As String
strCaminhoBe = "IN '' [;DATABASE=c:\MinhaPasta\meuBd_be.accdb;pwd=MinhaSenha] "
CurrentDb.Execute "DELETE * FROM tblEstoque " & strCaminhoBe & " WHERE Descontinuado = -1;"
Dica 25 - Chave de segurana em funes pblicas Funes com escopo Public devem receber sua especial ateno, pois podem oferecer uma brecha na segurana, mesmo no caso do aplicativo estar na extenso ACCDE. Se o invasor estiver acesso ao Painel de Navegao e chegar at a Janela Imediata do VBA possvel que tente executar tais funes, com a inteno de extrair algo. Por exemplo: vamos supor que voc tenha a funo abaixo no seu aplicativo para descriptografar senha ou outros tipos de informaes sigilosas. Public Function fncDCrip(varChave) As Variant Dim i%, k%, strBuff$, strpwd$ On Error GoTo trataErro strpwd = "MNBVCXZLKJ039RTY4U6W" For i = 1 To Len(varChave) k = Asc(Mid$(varChave, i, 1)) k = k - Asc(Mid$(strpwd, i, 1)) strBuff = strBuff & Chr$(k) Next i fncDCrip = strBuff sair: Exit Function trataErro: fncDCrip = 0: Resume sair End Function Da forma como se encontra a funo acima, qualquer programador com um pouco de experincia poder utilizar a funo, que voc deixou com livre acesso, para decifrar os dados criptografados que voc tenha armazenado em uma tabela. fncDcrip("") :::::> avelino Soluo: Crie uma chave numrica que impea o funcionamento da funo, caso esta no seja informada corretamente. Veja a alterao da funo: Public Function fncDCrip(varChave, Optional lngChave as long =0) As Variant Dim i%, k%, strBuff$, strpwd$ On Error GoTo trataErro '------------------------------------------------------ 'Se no informar a correta chave de segurana, a funo 'passar ao valor 0(zero) '------------------------------------------------------ if lngChave <> 131520 then fncDCrip = 0 Exit Function end if strpwd = "MNBVCXZLKJ039RTY4U6W" For i = 1 To Len(varChave) k = Asc(Mid$(varChave, i, 1)) k = k - Asc(Mid$(strpwd, i, 1)) strBuff = strBuff & Chr$(k) Next i fncDCrip = strBuff sair: Exit Function trataErro: fncDCrip = 0: Resume sair End Function O programador ao executar a funo sem a chave ou com a chave incorreta receber como resultado o valor 0. fncDcrip("") :::::> 0 fncDcrip("",131520) :::::> avelino Quer ir a fundo sobre tcnicas de segurana para o seu aplicativo? Adquira minha vdeo-aula oferecida no item 3. Clique aqui. Dica 26 - Valor padro de varivel As variveis assumem um valor padro correspondente quando as criamos. Veja o quadro: Tipo Varivel Valor padro Numrica 0 (zero) String "" (comprimento zero) Boolean False Date 00:00:00 Variant Empty (vazia) Object Nothing
Agora, observe bem o procedimento: Public Sub fncValorPadraoVariavel() Dim strA As String Dim intA As Integer Dim blnA As Boolean Dim dtaA As Date Dim varA As Variant Dim objA As Object Dim strLista$
MsgBox strLista, vbInformation, "Valor padro de varivel...." End Sub Executando o procedimento acima possvel comprovar o valor padro de cada varivel.
Dica 27 - Permitir fechar o Access apenas por botes especficos Para impedir o fechamento do Access pelo boto fechar (canto superior direito), pela combinao de teclas ALT+F4 ou pela Ribbon necessrio que um formulrio de controle se mantenha aberto (podendo ficar oculto). Veja o cdigo utilizado no evento "Ao descarregar" deste formulrio de controle, que impede a sada do Access sem a devida autorizao. Private Sub Form_Unload(Cancel As Integer) If blnSair = False Then MsgBox "Para sair do Access clique no boto [Sair] do formulrio...", _ vbInformation, "Aviso" Cancel = True Else 'Sair do Access DoCmd.Quit End If End Sub Observe que o evento possui o argumento Cancel que permite cancelar o fechamento do formulrio e como conseqncia impede o fechamento do Access. A varivel blnSair com escopo Public deve ser criada em um mdulo global. Public blnSair as boolean Como voc aprendeu na dica 26 acima, a varivel do tipo boolean tem o valor padro False. Para ento ser possvel o fechamento do formulrio e conseqentemente o fechamento do Access necessrio passar a varivel blnSair para True. Observe o cdigo abaixo do boto btSair do formulrio principal, utilizado no exemplo abaixo: Private Sub btSair_Click() blnSair = True DoCmd.Close acForm, "frmControleSaida" End Sub Segue um pequeno exemplo para voc testar. NaoSair.zip Ao rodar o aplicativo exemplo, os formulrios frmPrincipal e frmControlesaida sero carregados, sendo que o formulrio frmControleSaida estar oculto. Nota: Para impedir o carregamento dos formulrios, mantenha a tecla SHIFT pressionada na inicializao. Dica 28 - Como abrir um determinado arquivo atravs do Access Com o mtodo FollowHyperlink, o aplicativo de origem aberto para o carregamento do arquivo solicitado. Veja abaixo: 'O aplicativo Word ser aberto para carregar o arquivo Docx application.FollowHyperlink "c:\SuaPasta\SeuArquivo.docx" 'O Adobe Reader ser aberto para carregar o arquivo PDF application.FollowHyperlink "c:\SuaPasta\SeuArquivo.pdf" 'O Windows Media Player ser aberto para carregar o arquivo wmp application.FollowHyperlink "c:\SuaPasta\SeuArquivo.wmp" 'O navegador padro ser aberto para carregar o site application.FollowHyperlink "http://www.usandoaccess.com.br" Nota: No chame o site sem o Http:// , pois o Access exibir uma mensagem de segurana, conforme voc pode observar na imagem abaixo:
No carregamento do site com o FollowHyperlink o navegador no abre maximizado. Se houver a necessidade de abrir o navegador maximizado, possvel utilizar como alternativa o comando RUN do Scripting. Veja a funo abaixo: Public Sub fncAbrirSite(strSite As String) Dim ws As Object, x Set ws = CreateObject("WScript.Shell") x = ws.Run(strSite, vbMaximizedFocus, False) Set wShell = Nothing End Sub Para carregar o site, basta chamar pela funo call fncAbrirSite("http://www.usandoaccess.com.br") Dica 29 - Como abrir uma pasta atravs do Access Com a API SHELL possvel abrir uma pasta ou executar um arquivo. Basta copiar a API abaixo para um mdulo global do seu projeto: Option Explicit '-------------------------------------------------------------------------------------- 'Copie o cdigo abaixo para um mdulo global do seu projeto '------------------------------------------------------------------------------------- #If VBA7 Then 'verses 2010 e 2013 Declare PtrSafe Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As LongPtr, _ ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, _ ByVal nShowCmd As Long) As LongPtr #Else 'verses 2003 e 2007 Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" (ByVal hwnd As Long, _ ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String, ByVal lpDirectory As String, _ ByVal nShowCmd As Long) As Long #End If '-------------------------------------------------------------------------------- Exemplo de um boto abrindo uma pasta de nome fotos, localizada no mesmo diretrio do aplicativo: Private Sub btExemplos_Click() Call ShellExecute(0&, "open", CurrentProject.Path & "\fotos", "", "", 1) End Sub A API sendo utilizada para abrir uma pgina Web: Dim strSite$ strSite ="http://www.usandoaccess.com.br" Call ShellExecute(0&, "",strSite, "", "", 3) Abrindo o teclado virtual do Windows: Call ShellExecute 0, vbNullString, "osk.exe", vbNullString, "C:\", 1 Dica 30 - Manipulando pastas e arquivos com a classe FileSystem Observe na imagem abaixo, a classe FileSystem e seus Membros. Lista obtida atravs do Pesquisador de Objetos do VBA.
Veja alguns exemplos de uso desta classe pelo Access: Excluir um arquivo FileSystem.Kill "c:\temp\SeuArquivo.pdf" Criar uma pasta FileSystem.MkDir "c:\temp" Excluir uma pasta FileSystem.RmDir "c:\temp"
Nota: A pasta no pode ter arquivos. Use primeiro o kill para excluir os arquivos Ocultar uma pasta FileSystem.SetAttr "c:\temp", vbHidden Ocultar um arquivo FileSystem.SetAttr "c:\temp\SeuArquivo.docx", vbHidden Identificar se a pasta est oculta FileSystem.GetAttr ("c:\temp") = vbHidden Tamanho do arquivo FileSystem.FileLen ("c:\temp\SeuArquivo.accdb") :::> 1056768 Retornar a Data e a Hora da criao ou da ltima modificao FileSystem.FileDateTime ("c:\temp\seuBd.accdb") :::> 20/04/2014 11:00:19 Copiar um arquivo FileSystem.FileCopy "c:\temp\foto.gif", "d:\imagens\foto_bkp.gif"
Nota 1: Arquivo no pode estar em uso.
Nota 2: Observe que podemos copiar alterando o nome do arquivo
Saiba como explorar o HELP do VBA atravs desta minha vdeo-aula.
Bom estudo!
100 Dicas - parte 4 Dica 31 - Nmeros Hexadecimais, Octais e Binrios O VBA disponibiliza as funes Hex() e Oct() para transformar um nmero Decimal em Hexadecimal e em Octal, respectivamente. hex(302010) :::> 49BBA Oct(302010) :::> 1115672 No caso de passar o valor de Hexadecimal ou Octal para Decimal, utiliza-se uma das funes de converso Val(), Clng, Cint(), ... com os prefixos &h e &o Clng("&h" & "49BBA") :::> 302010 Clng("&o" & 1115672) :::> 302010 Para passar de Decimal para Binrio, utiliza-se a frmula clssica que a de ir agrupando o resto das sucessivas divises por 2. Exemplo: vamos achar o binrio do valor decimal 35: 35 / 2 :::> resto 1 Resultado 17 17 / 2 :::> resto 1 Resultado 8 8 / 2 :::> resto 0 Resultado 4 4 / 2 :::> resto 0 Resultado 2 2 / 2 :::> resto 0 Resultado 1 1 / 2 :::> resto 1 Resultado 0
Juntando em seqncia, os valores obtidos do resto, obtm-se como resultado, o valor binrio correspondente. 35 :::> 100011 Observe a funo que realiza o clculo e retorna com o valor Binrio: Public Function fncDecBin(dec) Dim bin$ If dec = 0 Then bin = "0" Do While Not dec = 0 bin = (dec - Int(dec / 2) * 2) & bin dec = Int(dec / 2) Loop fncDecBin = bin End Function De Binrio para Decimal, utiliza-se a frmula que usa o valor de cada posio binria. Exemplo: 2 5 2 4 2 3 2 2 2 1 2 0 :::> 32-16-8-4-2-1 (32 * 1) + (16 * 0) + (8 * 0) + (4 * 0) + (2 * 1) + (1 * 1) = 35 Observe a funo que realiza o clculo e retorna com o valor Decimal: Public Function fncBinDec(bin) Dim k Dim dec For k = Len(bin) To 1 Step -1 dec = dec + ((2 ^ (k - 1)) * Mid(bin, ((Len(bin) + 1) - k), 1)) Next fncBinDec = dec End Function Veja agora, o uso da funes acima nestes casos. Para passar de Hexadecimal para Binrio: fncDecBin(Clng("&h" & "49BBA")) :::> 1001001101110111010 Para passar de Octal para Binrio: fncDecBin(Clng("&o" & 1115672)) :::> 1001001101110111010 Para passar de Binrio para Hexadecimal: Hex(fncBinDec("1001001101110111010")) :::> 49BBA Dica 32 - Criptografia com resultado binrio Aproveitando o que voc aprendeu na dica acima, quero mostrar uma utilidade prtica que a criao de um cdigo de criptografia de nvel 3. Observe bem a funo: Public Function fncCripBin(Senha, Optional Chave As Long = 0) As String Dim cv As Byte, comp If Chave <> 153045 Then 'Gerando um falso resultado, caso a chave de segurana esteja incorreta. fncCripBin = "101010101010110101010" Exit Function End If If Len(Senha) > 7 Then MsgBox "Comprimento mximo de 7 dgitos...", vbInformation, "Aviso" Exit Function End If Randomize cv = Int((Rnd() * 126)) + 1 comp = String(7 - Len(fncDecBin(CLng(cv))), "0") fncCripBin = fncDecBin(Oct(senha * cv)) & comp & fncDecBin(cv) End Function Observe que temos trs criptografias embutidas na funo para gerar a criptografia final. por isso que aqui chamo de criptografia de nvel 3. A primeira criptografia gerar um valor OCTAL da multiplicao da senha informada (valor decimal) pela chave randmica (cv). A chave randmica (cv) varia de 1 a 127: Oct(Senha * cv) Vamos supor que a senha informada seja 102030 e que o valor da chave seja 81. Como resultado da primeira criptografia teremos: Oct(102030*81) :::> 37415356 A segunda criptografia a gerao do valor Binrio do resultado Octal. fncDecBin(37415356) :::> 10001110101110100110111100 A chave randmica (cv) incorporada ao cdigo Binrio final para que possamos descriptografar a senha. Esta seria a terceira criptografia utilizada. fncDecBin(81) = 1010001 Como resultado final da criptografia, teremos: fncCripBin(102030, 153045) ::::> 100011101011101001101111001010001 Observe que cada vez que rodarmos a funo, com a mesma senha, podemos obter at 127 resultados diferentes de cdigo Binrio. Exemplo: fncCripBin(102030, 153045) :::> 110111110010011010101000010011 fncCripBin(102030, 153045) :::> 110110101101011100011001101111010 O bom nisso que dificulta, ao extremo, qualquer tentativa de engenharia reversa. Segue abaixo a funo para descriptografar o cdigo Binrio gerado. Public Function fncDCripBin(strBin As String, Optional Chave As Long = 0) Dim cv If Chave <> 153045 Then 'Gerando um falso resultado, caso a chave de segurana esteja incorreta: fncDCripBin = "908070" Exit Function End If cv = fncBinDec(Right(strBin, 7)) fncDCripBin = CLng("&o" & fncBinDec(Mid(strBin, 1, Len(strBin) - 7))) / cv End Function Aplicando a funo temos como resultado: fncDCripBin("110110101101011100011001101111010", 153045) :::> 102030 Nota 1: A razo do argumento CHAVE utilizado nas funes pblicas, voc encontra clicando AQUIneste meu artigo - dica 25. Nota 2: Observe que as funes fncDecBin() e fncBinDec() esto presentes na dica 31 acima. Dica 33 - Cuidado com o que voc coloca nas constantes e variveis pblicas Se voc passou o projeto para ACCDE e colocou senha de acesso no VBA e acha que seu cdigo est totalmente seguro; sinto em dizer que voc pode estar cometendo uma falha de segurana. E uma das falhas que costumo observar o programador usar valores sigilosos, principalmente o uso de senha, em constantes ou em variveis pblicas. Exemplo: Option Compare Database Public Const SenhaBe = 102030 Como afirmei, a constante SenhaBe acima pode ser lida facilmente pela Janela de Verificao Imediata, mesmo estando o VBA protegido por senha. Para sua proteo, utilize a criptografia em valores sigilosos, armazenados nas constantes. Por exemplo, o valor da senha 102030 sendo armazenado no formato Binrio, usando a funo da dica 32 acima: Option Compare Database Public Const SenhaBe = "110110101101011100011001101111010"
Basta utilizar a funo de descriptografia para recuperar o valor da constante SenhaBE. Observe a parte em vermelho: Dim strCaminhoBe As String strCaminhoBe = "c:\MinhaPasta\meuBd_be.accdb;pwd=" & fncDCripBin(SenhaBe, 153045) CurrentDb.Execute "Alter Table [" & strCaminhoBe & "].tblEstoque Add Column PrecoUnitario CURRENCY;" Nota 1: Se a senha for do tipo string, voc pode utilizar as funes da dica 25. Nota 2: Se quiser ir a fundo sobre segurana em cdigo, clique aqui e adquira a vdeo-aula do item 3. Dica 34 - Convertendo valor de cor, no formato HTML(Hexadecimal) para Decimal At a verso 2003 era utilizado o valor Decimal nas propriedade de um objeto para identificar a cor, porm a partir da verso 2007 passou a ser utilizado o valor HTML (Hexadecimal). Observe na imagem abaixo, o valor selecionado de uma cor (#FCE6D4) para configurar o fundo de um campo.
Se necessitar utilizar a cor(#FCE6D4) pelo VBA, ter que passar para o formato Decimal. Exemplo de como podemos transformar este valor no formato HTML (Hexadecimal) para Decimal: Cint("&h" & "FC") :::> 252 Cint("&h" & "E6") :::> 230 Cint("&h" & "D4") :::> 212 Pegamos os valores decimais, obtidos de cada parte e passamos para a funo RGB(). RGB(252,230,212) :::> 13952764 (valor decimal da cor #FCE6D4) Para configurar a cor de fundo de um campo, pelo VBA, podemos utilizar os dois formatos vlidos: me!NomedoCampo.BackColor = 13952764 'ou me!NomedoCampo.BackColor = RGB(252,230,212) Segue a funo que converte o valor HTML para o valor Decimal, vlido no VBA: Public Function fncCorDec(strHTML As String) As Long Dim p(2) as integer p(0) = CInt("&h" & Mid(strHTML, 2, 2)) p(1) = CInt("&h" & Mid(strHTML, 4, 2)) p(2) = CInt("&h" & Mid(strHTML, 6, 2)) fncCorDec = RGB(p(0),p(1),p(2)) End Function Exemplo de uso da funo: me!NomeDoCampo.backColor = fncCorDec("#FCE6D4") Dica 35 - Desmarcar itens selecionados em um controle Listbox Observe, na imagem abaixo, um item da lista selecionado pelo clique do mouse.
Para remover a marcao da lista, basta atribuir um valor negativo ao controle Listbox. Neste exemplo, quando o campo Filtrar recebe o foco, a lista desmarcada. Private Sub txtFiltro_GotFocus() Me!Lista = -1 End Sub Agora observe o controle Listbox abaixo, configurado para Selees Mltiplas:
A tcnica para desmarcar a lista passar o valor da propriedade Selected(item) da Listbox paraFalse. Private Sub txtFiltro_GotFocus() Dim n As Integer '------------------------------------------------------ 'Percorre a lista do ltimo item para o primeiro item '------------------------------------------------------ For n = (Me!Lista.ListCount - 1) To 0 Step -1 '------------------------------ 'Vai desmarcando item por item '------------------------------ Me!Lista.Selected(n) = False Next End Sub Se desejar marcar todos os itens da lista, atravs de um boto, basta passar o valor da propriedadeSelected(item) para True. Private Sub btSelecionaTudo_Click() Dim n As Integer For n = (Me!Lista.ListCount - 1) To 0 Step -1 '------------------------------ 'Vai marcando item por item '------------------------------ Me!Lista.Selected(n) = True Next Me!txtFiltro.SetFocus End Sub Dica 36 - Exibir relatrio dos itens selecionados de uma ListBox Observe, na imagem abaixo, os itens selecionados na Listbox:
Foram selecionados os itens de nmeros 2, 19, 21 e 24. Podemos realizar a filtragem do relatrio atravs destes nmeros selecionados, utilizando o operador IN(), conforme o cdigo apresentado abaixo: Docmd.OpenReport "rltFrutas",acViewPreview ,,"IdFruta in(2,19,21,24)" Ou podemos tambm selecionar pelo nome da fruta (campo do tipo string): Dim strFiltro as string strFiltro ="NomeFruta IN('Abacate','banana','laranja,'melo')" Docmd.OpenReport "rltFrutas",acViewPreview ,,strFiltro A propriedade do controle Listbox que nos permite capturar os itens selecionados a ItemsSelected. E para percorrer e capturar cada um dos itens selecionados, fazemos uso do lao For Each . O cdigo exemplo abaixo monta a lista do operador IN() com o nmeros exclusivos. Private Sub btRelatorio_Click() Dim strFiltro As String, Sel As Variant, j As Boolean
strFiltro = "in(" '---------------------------------------- 'Percorre cada item selecionado da lista '---------------------------------------- For Each Sel In Me!Lista.ItemsSelected '------------------------------------------------------- 'Adiciona o item selecionado da lista no operador IN() '------------------------------------------------------- strFiltro = strFiltro & Me!Lista.Column(0, Sel) & "," j = True Next strFiltro = Mid(strFiltro, 1, len(strFiltro) - 1) & ")" strFiltro = "idfruta " & strFiltro
If j = False Then Exit Sub 'Aborta, caso no haja item selecionado DoCmd.OpenReport "rltFrutas", acViewPreview, , strFiltro End Sub Nota 1: Para poder selecionar mltiplos itens em um controle Listbox, altere a propriedade Selees Mltiplas para Simples. Nota 2: Baixe o exemplo, aqui apresentado, neste meu artigo. Dica 37 - Como atrasar um cdigo sem usar API Na dica 13 foi apresentado a API sleep(), com o objetivo de atrasar a execuo de uma rotina. Uma alternativa de cdigo para a mesma finalidade fazermos uso da funo timer() do Access. Observe o cdigo: Public Sub fncAguardar(lngMilesegundos) Dim varStart varStart = Timer 'Tempo inicial Do While Timer < varStart + (lngMilesegundos / 1000) DoEvents 'Libera outros processos Loop End Sub Como teste, experimente utilizar o procedimento antes da abertura de um relatrio: call fncAguardar(5000) 'Aguarda por 5 segundos Docmd.OpenReport "NomeRelatrio", acViewPreview Dica 38 - Configurar atalho do seu aplicativo no desktop para realizar algumas tarefas Veja, na imagem abaixo, um exemplo de atalho simples, criado no Desktop:
Observe o campo DESTINO do atalho. Neste campo podemos introduzir um ou mais comandos, com o objetivo de se executar tarefas especficas na inicializao. Destino : c:\Maestro\Open_v3.accdr<espao>/comando<espao>/comando Veja, na tabela abaixo, alguns destes comandos: /Excl Abre o aplicativo para uso exclusivo. Utilize para troca de senha. /Ro Abre o aplicativo para uso apenas como leitura. /Repair Repara o Banco de Dados e depois fecha o Access. /Compact Compacta e Repara o aplicativo. Utilize para realizar Backup. /X NomeDaMacro Executa uma macro na partida. No use espao no nome da macro. /Decompile Manuteno e limpeza do cdigo VBA. Faa um backup de segurana do seu Banco de Dados, antes de aplicar este comando. /Runtime Inicia o Access no modo Runtime para testes ou para evitar que o usurio entre no modo estrutura. /NoStartup No mostrar a caixa de dilogo de abertura do Access
Com o comando /Compact podemos criar um atalho para realizar um backup DESTINO: c:\maestro\maestro_be.accdb /compact d:\maestro\backup\maestro_be_bkp.accdb Cuidado com os nomes compostos, contendo espaos. Se este for o seu caso, dever acrescentar as aspas, conforme exemplo na linha abaixo: DESTINO: "c:\Sua Pasta\Seu Bd.accdb" /compact d:\SuaPasta\backup\SeuBd_bkp.accdb Observe que a linha aonde se informa o destino do backup (d:\SuaPasta\backup\SeuBd_bkp.accdb) no pode conter espao nos nomes, pois acarretar em erro na execuo do atalho. Nota: Procure no utilizar espaos no nome das pastas e no nome dos seus aplicativos. Exemplo de nomes compostos sem o uso de espaos: c:\UsandoAccess\ProtecMaestro.accdb Pode realizar o backup para uma pasta compartilhada, em outra mquina na rede. DESTINO: "c:\Sua Pasta\Seu Bd.accdb" /compact \\NomeMquina\SuaPasta\backup\SeuBd.accdb Se o IP da mquina for fixo, pode ser usado tambm. DESTINO: c:\SuaPasta\SeuBd.accdb /compact \\192.168.1.200\SuaPasta\backup\SeuBd.accdb Dica 39 - Como abrir o Access na verso correta, tendo duas ou mais verses na mquina ? Vamos supor que voc tenha instalado em uma mquina o Access 2010 e o Access 2007 Runtime e deseja que seu aplicativo abra sempre na verso runtime 2007. A tcnica para isso a de criar um atalho do Executvel, da verso desejada. Observe na imagem abaixo, que ao selecionar o executvel do Access Runtime 2007 com o boto da direita do Mouse, temos a opo Enviar para > Ambiente de trabalho (criar atalho).
Abrindo a propriedade do atalho criado, temos a linha completa de chamada do executvel do Access Runtime no campo DESTINO. Isso garante que o Access Runtime 2007 seja aberto, mesmo que o Access 2010 esteja como padro.
Basta acrescentar, depois da linha do executvel, o caminho e o nome do aplicativo a ser aberto. Observe a parte sublinhada:
Se o caminho ou nome do seu aplicativo contiver espao, deve utilizar as aspas. DESTINO: "...\MSACCESS.EXE" "c:\Sua pasta\Seu BD.accdb" Dica 40 - Teclas de atalhos para botes Observe, na imagem abaixo, o nome &Salvar na propriedade Legenda do boto btSalvar:
A smbolo & na frente do caractere desejado, determina o atalho especfico para o boto. Observe a letra S sublinhada no boto.
Para acionar o boto, basta manter pressionada a tecla ALT e imediatamente pressionar a tecla S. Refaa o atalho do boto para que seja acionado pela letra "a" (S&alvar) e faa um teste. (ALT + a) Dica 41 - Manipulando strings com a classe Strings Observe, na imagem abaixo, a classe Strings e seus Membros. Lista obtida atravs do Pesquisador de Objetos do VBA.
Veja alguns exemplos de uso desta classe pelo Access: Funo Descrio Exemplo Retorno Asc Retorna o valor numrico ANSI do caractere como um Integer. Asc("C") 67 Chr Retorna o caractere correspondente ao valor numrico ANSI como um string. Chr(67) Chr(10) C Avan o de linha Format Formata uma expresso de acordo com os strings de formato apropriado. Format(Date,"dd-mm-yy") 12-06-14 InStr Retorna a posio de uma string dentro da outra. Instr("ABCDE","D") 4 Lcase Retorna o valor de string com letras minsculas. Lcase("ABCD") abcd Left Retorna os caracteres da esquerda de uma string. left("ABCDE",2) AB Len Retorna o nmero de caracteres em uma string como tipo Long. len("ABCDE") 5 LTrim Remove os espaos iniciais da string. LTrim(" ABCD") ABCD Mid Retorna uma parte de uma string. Mid("ABCDE",2,3) Mid("ABCDE",2) BCD BCDE Right Retorna os caracteres da direita de um string. Right("ABCDE",2) DE RTrim Remove os espaos finais de uma string. RTRim("ABCD ") ABCD Space Retorna uma string contendo um nmero especfico de espao. Space(2) & "ABCD" __ABCD str Converte o valor numrico de qualquer tipo de dados para uma string. str(123,45) 123,45 String Retorna uma string contendo os caracteres especficos repetidos. string(5,"A") AAAAA Trim Remove os espaos iniciais e finais de uma string. trim(" ABCDE ") ABCDE UCase Retorna a verso de uma string com letras maisculas UCase("abcDe") ABCDE Replace Substitui uma parte por outra em uma sentena. Replace("ABC","B","2") A2C Split Separa uma sentena com base em um ou mais caractere determinado. j=Split("ab cd"," ") j(0)::> ab j(1)::> cd Join Forma uma nica string de uma matriz.
k(0)='ab' k(1)='cd' Join(k," ")
ab cd WeekdayName Retorna uma string, indicando o dia da semana especificado. WeekdayName(1) WeekdayName( 3) Domingo Tera
Saiba como explorar o HELP do VBA atravs desta minha vdeo-aula.