universidade vba

265

Click here to load reader

Upload: diogo-ferreira

Post on 01-Jan-2016

525 views

Category:

Documents


55 download

TRANSCRIPT

Page 1: Universidade VBA

PARCERIA JÚLIO BATTISTI - DIGERATI • Este e-book é uma parceria entre o meu site

www.juliobattisti.com.br e a Editora Digerati, com a qual eu mantenho contrato para revenda deste e-book, em formato PDF, através do meu site.

Nota sobre direitos autorais: IMPORTANTE: Nas propriedades do E-book estão gravados o nome completo, e-mail e demais dados do comprador. Se for repassada cópia para outros usuários e este E-book for parar em um site ou Blog, para download gratuito, quem será responsabilizado Criminalmente, conforme previsto nas Leis 9118 e 9610, será o comprador do E-book, que foi quem repassou cópias para outros usuários, O QUE É PROIBIDO. Seja honesto. Este E-book é de uso pessoal, individual, não compartilhado. NÃO REPASSE CÓPIAS!!! Ao adquirir este E-book você tem o direito de lê-lo na tela do seu computador e de imprimir uma cópia para o seu uso pessoal. É vetada a distribuição deste arquivo, mediante cópia ou qualquer outro meio de reprodução, para outras pessoas. Se você recebeu este E-book através do e-mail ou via ftp de algum site da Internet, ou através de um CD de Revista ou via e-mail recebido de um “amigo”, saiba que você está com uma cópia pirata, não autorizada. A utilização de uma cópia pirata, não autorizada, é crime de Violação de Direitos Autorais conforme Leis 9118 e 9610, sujeita a pena de 2 a 5 anos de Cadeia. Denuncie o site ou revista que está disponibilizando a cópia, através do e-mail [email protected] Se você tiver sugestões sobre novos cursos que gostaria de ver disponibilizados, entre em contato pelo e-mail: [email protected]. Visite periodicamente o site www.juliobattisti.com.br para ficar por dentro das novidades:

• Mais de 900 cursos e vídeos-aula em diversos assuntos. • Artigos e dicas sobre Certificações da Microsoft. • Artigos sobre Carreira e Trabalho. • Centenas de Livros sobre os mais Variados Assuntos. • Dicas de livros e sites sobre diversos assuntos. • Simulados gratuitos, em português, para os exames da Microsoft.

PARCERIA JÚLIO BATTISTI - DIGERATI

Page 2: Universidade VBA
Page 3: Universidade VBA

Capítulo 1 Introdução à lógica de programação

cap01.indd 11 1/11/2006 15:46:34

Page 4: Universidade VBA

12 universidade VBA

Código e programação

Imagine que você precisa fazer muitos cálculos até amanhã, para apresentá-los de forma organizada em uma reunião bem cedo. É estafante, mas nada que o Excel não consiga fazer, não é verdade?

No entanto, no meio da tarde alguém liga para o seu ramal. Querem que as planilhas não apenas contenham dados e sejam bem formatadas, mas também que sejam dinâmicas, pois a empresa pretende adotar uma solução definitiva para a forma como dados são inseridos em uma planilha, criando uma interface e rotinas para salvamento do conteúdo. Ou seja, querem um sistema de planilhas dinâmicas e programáveis.

E agora? Fazer “planilhinhas” no Excel, com fórmulas simples, é uma coisa. Ago-ra, trabalho de programador, com funções e sistemas de armazenamento de dados parecidos com os feitos em bancos de dados é outra bem diferente...

Porém, na verdade não é. Ao trabalhar com o Excel, temos à nossa disponibili-dade uma interface de programação amigável, o VBA (Microsoft Visual Basic for Applications), a forma mais simples de trabalhar com componentes do Microsoft Office – especialmente com as planilhas do Word e com os bancos de dados do Excel, construindo mini-aplicações ou soluções de automação.

Trabalhar com o VBA é simples: é possível utilizar tanto o sistema de gravação direta de macros (que veremos com detalhes no Capítulo 2, Macros e VBA) quanto o editor de código. No entanto, se deseja um trabalho realmente profissional, terá de aprender algumas coisas sobre como criar e administrar um código, a chamada lógica de programação.

Em vista disso, nessa introdução daremos alguns pilares da lógica de programação, para que você aprenda a se organizar no momento de montar uma aplicação VBA. Além disso, a leitura é necessária para a compreensão integral tanto dos conceitos como das ferramentas de criação de códigos do VBA.

Algoritmos

Para resolver o problema indicado no tópico anterior, devemos encontrar uma seqüência de passos que conduzam à sua resolução; seqüência que deve facilitar a resolução do problema, e não complicá-lo. A essa ordem de execução do trabalho damos o nome de algoritmo.

De um modo geral, define-se algoritmo como uma descrição, passo a passo, de um método que conduz à resolução de um problema ou à execução de uma tarefa,

cap01.indd 12 1/11/2006 15:46:34

Page 5: Universidade VBA

Introdução à lógica de programação 13

1capítulo

ou seja, consiste na divisão de um problema em problemas (ou etapas) menores, procurando a resolução de micro-tarefas, cada uma em separado.

Programação consiste na codificação precisa de um algoritmo, segundo uma linguagem de programação específica. Existem, portanto, três fases distintas na elaboração de programas:

• Análise do problema (especificação do problema, análise de requisitos, pres-supostos etc.);

• Concepção do algoritmo;• Tradução desse algoritmo na linguagem de programação, ou seja, em uma lin-

guagem inteligível para a máquina (computador), para um determinado aplicativo ou para um determinado serviço.

O exemplo mais simples que podemos utilizar para demonstrar o funcionamento de algoritmos é o clássico exemplo da receita de bolo, que você já deve ter visto em alguma aula de Matemática do ensino médio.

Uma receita é a descrição de um conjunto de passos, ou ações, que integram a combinação de um conjunto de ingredientes para que possamos obter um produto em particular. A combinação não é aleatória, por isso os passos devem ser cumpridos em uma determinada ordem para alcançarmos um resultado final satisfatório. Da mesma maneira, todas as etapas do processo devem ser mantidas: a substituição de etapas, além de acabar com a noção de algoritmo como exercício dividido em etapas mais simples, redundaria em fracasso, pois os ingredientes seriam misturados ao acaso, sem método. A representação gráfica do algoritmo para a ”receita de bolo” pode ser observada na Figura 1.1:

Manteiga

Farinha de trigo

Açúcar Leite RECEITA

Fermento

Ovos

Sal

Figura 1.1.

cap01.indd 13 1/11/2006 15:46:34

Page 6: Universidade VBA

14 universidade VBA

A elaboração da receita trabalha com um conjunto de entradas (os ingredientes) de forma a obter um resultado agradável ou útil (o bolo). Supondo que estão sendo utilizadas as entradas corretas para alcançar o objetivo, a partir delas, trabalhamos na montagem das instruções dos algoritmos, representados aqui pelos passos da receita.

1. Quebrar dois ovos (primeiras entradas utilizadas).

2. Separar a clara da gema.

3. Bater duas claras em neve.

4. Adicionar duas gemas.

5. Adicionar uma xícara de açúcar.

6. Adicionar duas colheres de manteiga.

7. Adicionar uma xícara de leite.

8. Adicionar farinha e fermento.

9. Misturar tudo.

10. Colocar em uma forma e levar ao forno em fogo brando.

Traduzindo o modelo apresentado em regras técnicas, obtemos um modelo or-denado de como é preciso construir um algoritmo:

1. Compreender o problema: alguns ingredientes devem ser misturados para produzir um bolo.

2. Identificar os dados de entrada: quais ingredientes devem ser usados?

3. Identificar os dados de saída: o que resultará da mistura dos ingredientes?

4. Determinar o que é preciso fazer para transformar os dados de entrada em dados de saída. Observe:

• Usar a estratégia de dividir para conquistar;• Observar regras e limitações;

cap01.indd 14 1/11/2006 15:46:34

Page 7: Universidade VBA

Introdução à lógica de programação 15

1capítulo

• Identificar todas as ações a realizar;• Eliminar ambigüidades (o algoritmo deve ser simples).

5. Construir o algoritmo.

6. Testar o algoritmo.

7. Executar o algoritmo.

O método para conquistar

Também conhecido como método cartesiano (foi René Descartes quem o inven-tou), método descendente (top-down method) ou, ainda, método de refinamento passo a passo, esse conjunto de procedimentos define com clareza como um algoritmo deve se portar. Por meio dele, um problema de grande porte deve ser dividido em partes menores (ou sub-problemas) de modo que seja mais fácil atingir sua resolução. Como exemplo, suponha que o problema maior seja a necessidade de consertar uma parte do telhado de casa. Assim, temos a proposição geral ou objetiva “consertar o telhado”, que, por sua vez, é seguida da pergunta “como consertar?”, que pode ser resolvida com a divisão do problema em tarefas menores. Observe a figura seguinte:

Como consertar o telhado da casa?

|

Comprar material

|

Posicionar escada

|

Subir no telhado

|

Retirar telhas quebradas

|

Substituir por telhas inteiras Descer da escada e finalizar a tarefa

Figura 1.2.

Esse método é passo a passo, ou seja, cada ponto do problema é completado antes do início do próximo. Tomando o exemplo da Figura 1.2, não podemos subir no telhado sem antes posicionar a escada, e não podemos retirar a telha estragada sem subir no telhado.

cap01.indd 15 1/11/2006 15:46:35

Page 8: Universidade VBA

16 universidade VBA

Características de um algoritmo de programação

Com base na utilização do método cartesiano, definimos que um algoritmo deve ter cinco características fundamentais:

• Finitude: um algoritmo deve terminar sempre após um número finito de passos. Uma boa dica é definir que esse número de passos não pode ser maior do que a capacidade que uma pessoa normal tem de se lembrar de todas as etapas de um processo sem a ajuda de lápis e papel, computadores etc. Além disso, o al-goritmo deve ser tão curto quanto simples, a ponto de ser repetido diversas vezes sem dificuldade;

• Definição: cada passo de um algoritmo deve ser precisamente definido. As ações devem ser fixadas rigorosamente e sem ambigüidades;

• Entradas: um algoritmo deve ter zero ou mais entradas, ou seja, quantidades ou parâmetros que lhe são fornecidas antes do algoritmo iniciar;

• Saídas: um algoritmo deve ter uma ou mais saídas, ou quantidades relacionadas especificamente com as entradas;

• Eficiência: um algoritmo deve ser eficiente. Isso significa que todas as opera-ções devem ser suficientemente básicas de modo que possam ser executadas com precisão em um tempo finito por um ser humano comum.

Tradução do algoritmo

Criado o algoritmo, devemos traduzi-lo para uma linguagem inteligível. No nosso caso, para os parâmetros de uma linguagem de programação. A maioria das linguagens de programação trabalha com os algoritmos, transformando-os matema-ticamente em equações ou instruções. Cada linguagem de programação, por sua vez, possui uma forma própria de codificação de instruções. Essa seqüência é chamada de estrutura de controle.

Em meados da década de 1960, alguns matemáticos provaram que qualquer progra-ma poderia ser construído por meio da combinação de três estruturas básicas: seqüência, seleção e repetição. Também foi definido que essas estruturas devem ter um início e um final, que passou a ser chamado de módulo. Um conjunto de módulos ou funções (são a mesma coisa) pode ser chamado, para fins de separação do código, de bloco.

Estruturas de montagem de um algoritmo

Os comandos ou módulos do algoritmo fazem parte de uma seqüência, em que é relevante a ordem na qual eles se encontram, pois serão executados um de cada

cap01.indd 16 1/11/2006 15:46:35

Page 9: Universidade VBA

Introdução à lógica de programação 17

1capítulo

vez, estritamente, de acordo com essa ordem. De uma forma genérica, poderíamos expressar uma seqüência da seguinte maneira:

Comando-1Comando-2Comando-3:Comando-12Comando-13

Temos aqui uma seqüência de n comandos, na qual os comandos serão executados na ordem em que aparecem, ou seja, o comando de ordem i+1 (veja o tópico seguinte) só será implementado após a execução do de ordem i. Utilizando a ordem natural (números ordinais), diríamos que o terceiro comando só será executado após a reali-zação do segundo, o quarto após a finalização do terceiro, e assim por diante.

Notação lógica

Para fins de representação, tanto no processo da montagem de algoritmos como na passagem do algoritmo para uma linguagem de programação, costuma-se utilizar uma notação própria, muito semelhante à empregada em Álgebra, para definir a inter-relação entre comandos e demais elementos de um algoritmo.

Essa notação é chamada de notação lógica, e determina que a localização de um comando ou elemento pode ser representada pela letra i. Graficamente, essa notação poderia ser exemplificada como algo semelhante ao ponto em que o cursor do computador está posicionado na tela, ou ao ponto desenhado em uma folha de papel com o auxílio de uma régua e um lápis.

Assumindo que i é a posição atual de um elemento, é possível movimentar-se para frente utilizando a notação i+1, que indica que devemos avançar um comando em relação ao comando atual. Para avançar dois comandos na seqüência do algoritmo, podemos utilizar a notação i+2, e assim por diante. A notação lógica será muito utilizada neste livro ao trabalharmos, tanto em sua forma corrente, que apresentamos aqui, quanto em modelos de notação baseados em células, linhas, colunas e planilhas, elementos específicos do Excel.

Estrutura de decisão ou seleção

Além de estruturas puramente cumulativas, que nos permitem avançar para um novo comando, como em i+1, é possível utilizar outros tipos de estruturas na tradução de um algoritmo para uma linguagem de programação.

cap01.indd 17 1/11/2006 15:46:35

Page 10: Universidade VBA

18 universidade VBA

Em alguns casos, por exemplo, pode ser necessário fazer com que o algoritmo se divida em dois caminhos, de acordo com a seqüência de comandos apresentada. Como só é possível adotar uma solução para cada seqüência de comandos, deve-se adotar uma forma de representar a continuidade que será dada a uma determinada seqüência de ações. Esse tipo de notação é chamado de estrutura de decisão ou seleção, mas também pode ser chamada de estrutura condicional, já que o caminho que será adotado pelo algoritmo será traçado de acordo com a veracidade de uma condição. Observe seu funcionamento:

Se <condição>

então <seq. de comandos-1>

senão <seq. de comandos-2>

Em notação lógica, utilizamos as alíneas (’ ou ’’) para definir uma estrutura condicional:

Se x>1

então <i’=i+1>

senão <i’’=i+2>

Se a <condição> for verdadeira será executado <seq. de comandos-1>. Em caso contrário, teremos a execução da <seq. de comandos-2>.

A decisão deve ser tomada quando há necessidade de testar alguma condição e, em função dela, tomar uma atitude. Em nosso dia-a-dia, estamos sempre tomando decisões com base em condições. No caso das aplicações VBA em planilhas do Excel, as decisões podem ser tomadas com base em condicionais representadas por elementos próprios ao Excel, como pastas, planilhas, linhas, colunas etc.

Repetição ou iteração

Uma estrutura muito utilizada em programação é a da repetição, ou iteração, também conhecida como looping. O looping existe praticamente em todas as lin-guagens de programação, pois com ele é possível declarar em um código a repetição de tarefas individuais por um número determinado de vezes, ou quantas vezes uma condição lógica permitir. Observe alguns exemplos:

cap01.indd 18 1/11/2006 15:46:35

Page 11: Universidade VBA

Introdução à lógica de programação 19

1capítulo

• Virarei as páginas do livro até que terminem;• Escolherei cinco figuras do livro;• Enquanto o livro possuir páginas não lidas, eu o lerei.

No primeiro exemplo, repetimos a ação de virar as páginas do livro, obedecen-do à ordem seqüencial (i+1) até que seja satisfeita a condição para que as pági- nas terminem.

No segundo exemplo, há a repetição da atitude de escolher uma figura por um número determinado de vezes (cinco). Note que, aqui, o comando será associado, provavelmente, a uma estrutura de decisão, pois não ficou determinado que sejam escolhidas, por exemplo, as cinco primeiras figuras do livro (i+1, i+2, i+3, i+4, i+5), mas sim que seja satisfeita a condição de se ter cinco figuras, não importa quais.

No terceiro exemplo, temos uma condição mais claramente atrelada ao looping: para continuarmos a ler o livro, devem existir páginas ainda não lidas. Quando não existirem mais tais páginas, o processo será interrompido.

cap01.indd 19 1/11/2006 15:46:35

Page 12: Universidade VBA

cap01.indd 20 1/11/2006 15:46:35

Page 13: Universidade VBA

Macros e VBA 21

2capítulo

Capítulo 2 Macros e VBA

cap02.indd 21 1/11/2006 15:46:51

Page 14: Universidade VBA

22 universidade VBA

O VBA

A introdução apresentada no capítulo anterior serve não só para os estudos de VBA, mas para qualquer linguagem de programação. Por isso, salientamos que é importante se familiarizar com os conceitos ali apresentados se deseja se tornar um especialista em VBA, capaz de criar suas próprias macros e códigos, e não um simples compilador (no sentido de quem copia mesmo) de códigos tirados de livros ou de sites da Internet.

O VBA (Visual Basic for Application) é uma implementação do Visual Basic da Microsoft incorporada em todos os programas do Microsoft Office, bem como em outras aplicações da Microsoft, como o Visio. Também é possível encontrá-la, pelo menos parcialmente, em programas de terceiros, como o AutoCAD.

O VBA substitui e estende o potencial das linguagens de programação para ma-cros anteriores – incluindo as implementações para gravadores de macros presentes no Office antes da versão 2000.

O VBA pode ser utilizado, primariamente, para controlar os aspectos relacionados com a aplicação anfitriã, incluindo a manipulação da interface do usuário, tais como menus, barras de ferramentas, formulários desenhados pelo usuário e caixas de diálogo. No entanto, indo um pouco além, o VBA também pode ser utilizado para criar scripts de automação das aplicações, mediante o VBA Script, a resposta da Microsoft ao JavaScript. O VBA Script trabalha com uma janela de criação de códigos, já incorporada à interface de criação de aplicações no VBA, o VBA Editor, nas novas funções do Office.

Como o nome sugere, o VBA é muito parecido com o Visual Basic; uma escolha óbvia, já que boa parte do Office é criado a partir de códigos do Visual Basic. No entanto, o VBA só pode correr um código dentro da aplicação, no lugar de operar como aplicação separada. Porém, pode ser usado para controlar uma aplicação a partir de outra.

O VBA, assim como o Visual Basic, é uma linguagem orientada a objetos. Definindo de forma simples, uma linguagem orientada a objetos é uma técnica de programação que se concentra nos dados (ou objetos), e nas interfaces que têm esse objeto. Conceitual-mente, a linguagem orientada a objetos trabalha com a noção de que tudo que existe à nossa volta, incluindo nós mesmos, pode ser estruturado como objeto. Alguns, como carros, bancos e cadeiras são objetos concretos. Já outros, como a conta bancária, uma opinião ou uma dívida com alguém são classificados como objetos abstratos.

O importante em uma linguagem orientada a objetos é construir objetos confiá-veis, ou seja, que correspondam à finalidade para a qual foram criados. Os meios utilizados para a criação desse objeto são de importância secundária.

cap02.indd 22 1/11/2006 15:46:52

Page 15: Universidade VBA

Macros e VBA 23

2capítulo

Procedimentos para gravação de macros

Uma macro é um programa escrito ou gravado por um usuário capaz de armaze-nar uma série de comandos de Excel para que possam ser utilizados posteriormente como um único comando. Com as macros, podemos automatizar tarefas complexas, assim como é possível reduzir o número de passos necessários para a execução de uma tarefa (o conceito de algoritmo, no Capítulo 1, Introdução à lógica de progra-mação) executada com freqüência.

Macros são o meio de trabalho padrão em VBA. Uma macro, dentro do Micro-soft Office, pode ser gravada de duas maneiras: mediante o gravador de macros – opção rudimentar, baseada no antigo gravador de macros do Office 97 – ou com o Editor de Visual Basic, embutido no Microsoft Office. A utilização do grava-dor é boa o suficiente para a montagem de pequenas rotinas, ou para entender o funcionamento de algumas funcionalidades do VBA, mas não é a ferramenta mais adequada para a produção de aplicativos complexos. Nesses casos, deve ser utilizado o Editor de VBA.

Utilização do gravador de macros

1. Para empregar o gravador de macros, defina, antes de tudo, qual função será criada. Lembre-se de toda a nossa conversa sobre algoritmos, no Capítulo 1, Intro-dução à lógica de programação, e você verá como ela será importante a partir de agora. Podemos até mesmo utilizar o expediente muito prático de abrir o Microsoft Excel para anotar, em uma folha de papel ou no Bloco de notas, quantas operações ou etapas são necessárias para finalizar a tarefa. Lembre-se do método cartesiano: divida o problema em problemas menores, para resolvê-lo da melhor forma, e orga-nize-o no formato passo a passo, ou seja, uma etapa só deve ser iniciada quando a anterior for terminada.

2. Isso feito, abra o Microsoft Excel. Siga o menu Arquivo > Novo ou utilize o atalho Ctrl + O se quiser criar a macro em um novo documento. Se quiser criar a macro a partir de uma planilha existente, clique em Arquivo > Abrir e escolha a planilha desejada, ou utilize o atalho Ctrl + A.

Para gravar a macro, clique no menu Ferramentas > Macro > Gravar no- va macro.

cap02.indd 23 1/11/2006 15:46:52

Page 16: Universidade VBA

24 universidade VBA

Figura 2.1.

3. Será aberta a janela Gravar macro. Clique na linha Nome da macro para dar um nome à macro que será gravada. Dê-lhe um nome coerente; de preferência um que faça sentido no momento da documentação, ou para alguém que acaba de chegar na empresa e precise utilizá-la. Nomes padrões, como Macro1 e Macro2 não ajudam muito, mas são melhores do que apelidos e palavrões. O ideal é que o nome da macro inclua uma brevíssima descrição do que ela faz. Uma macro que seleciona colunas, por exemplo, pode tranqüilamente chamar-se SelecColuna.

4. Se você deseja que a macro possua um atalho de teclas, selecione a caixa ao lado da linha Ctrl + e digite uma letra, um número ou um símbolo. Se quiser que além de Ctrl o atalho também contenha a tecla Shift, aperte-a no momento em que digitar a letra na caixa.

Figura 2.2.

cap02.indd 24 1/11/2006 15:46:52

Page 17: Universidade VBA

Macros e VBA 25

2capítulo

5. No espaço Armazenar macro em, podemos escolher entre três opções:• Esta pasta de trabalho: a macro será gravada na mesma pasta que armazena

as planilhas atualmente utilizadas, e passa, portanto, a fazer parte do projeto;• Nova pasta de trabalho: armazena a macro em uma pasta diferente da pasta

com as planilhas atualmente manipuladas;• Pasta pessoal de macros: indicamos ao Office que a macro deve ser armazenada,

juntamente com outras macros, em uma pasta personalizada, apenas para macros. Aqui, vamos supor que tenhamos escolhido a última opção.

6. Na linha Descrição, dê algumas informações sobre a função da macro. É pos-sível utilizar as indicações algorítmicas formuladas, caso as tenha especificado. O importante é não deixar de documentar o que está sendo feito. Mantenha a indicação da data e do usuário no comentário original. Clique em OK.

7. Agora, é preciso gravar as ações da macro. Note que no meio da planilha surgirá uma pequena barra de ferramentas. Nela, encontramos um botão quadrado que se chama Parar gravação; e é ele que você deve utilizar para interromper a gravação da macro após realizar todas as tarefas.

Vamos supor que a ação diga respeito à seleção das colunas A, B e C de uma pla-nilha do Excel. Após selecionar as três colunas, clique no botão Parar gravação.

8. Para visualizar o resultado da macro, utilize a combinação de teclas Alt + F8 para acessar a janela Macro. Nela, você terá listadas todas as macros do sistema, incluindo a gravada agora há pouco.

Figura 2.3.

9. Em seguida, clique na macro criada anteriormente e, depois, em Executar. Se a ação for realizada, obtivemos sucesso na criação da macro. Também faça um teste com o atalho atribuído à macro.

cap02.indd 25 1/11/2006 15:46:53

Page 18: Universidade VBA

26 universidade VBA

10. Agora vem a parte realmente interessante. Além de criar uma macro simples, podemos aprender como o editor de macros se comporta, descobrindo, inclusive, quais elementos foram utilizados para criar a macro. Para tanto, clique na macro criada e aperte o botão Editar. Aparecerá o Editor do Microsoft Visual Basic, que veremos com detalhes mais adiante. Nele, estará inscrito todo o código VBA Script utilizado pela macro gravada anteriormente.

Figura 2.4.

11. O código ficará parecido com o que vemos a seguir:

Sub Macro3()‘‘ Macro3 Macro‘ Macro gravada em 12/1/2006 por Teste‘‘ Atalho do teclado: Ctrl+Shift+H‘ Range(“A:C,A:C”).Select

cap02.indd 26 1/11/2006 15:46:53

Page 19: Universidade VBA

Macros e VBA 27

2capítulo

Range(“A15”).ActivateEnd SubSub Macro4()‘‘ Macro4 Macro‘ Macro gravada em 12/1/2006 por Teste‘‘ Atalho do teclado: Ctrl+Shift+S‘ Columns(“A:F”).Select Range(“A15”).ActivateEnd Sub

Há vários elementos dignos de nota. Vejamos:• Observe que o sistema das macros é uma cópia quase literal da ordem do algo-

ritmo, em que ela se baseia. A macro tem um início, sempre definido pela abertura de uma sub-rotina (Sub). Logo após, são declaradas as informações referentes à macro, incluindo as teclas de atalho que podem ser utilizadas para ativá-la;

• Note que essas informações são declaradas como comentários; partes do código que não são lidos pelo interpretador do Visual Basic, sendo encarados como comentá-rios do código. No VBA, o caractere ‘ é utilizado como indicador de comentário;

• Quando declaramos a ação de selecionar as colunas (o escopo do nosso exemplo) sempre deve ser obedecida a seguinte ordem: propriedade – parâmetros – evento. Na primeira linha após os comentários, por exemplo, temos a estrutura Range(“A:C,A:C”).Select, em que utilizamos, primeiramente, a propriedade Range para mostrar que será definido um intervalo (range) de células, linhas ou colunas, justamente declarado a seguir, entre parênteses; elemento utilizado para isolar parâmetros no VBA. O ponto após o parêntese de fechamento é utilizado para separar a declaração do parâmetro da chamada do evento, que no caso é Select;

• Por último, é preciso observar que, quando falamos em uma planilha de Ex-cel, estamos falando de um documento sempre ativo. Não existem planilhas 100% estáticas: se a planilha está aberta, mesmo que não esteja sendo editada, ela possui ao menos um elemento (uma célula, linha, coluna ou um intervalo de células) ativo. É o que o final do nosso código de macros mostra quando utiliza a propriedade Range novamente, mas, desta vez, aplicada a um parâmetro que representada uma coordenada do Excel ((“A15”)) seguido do evento Activate. De acordo com uma convenção informal, quando a posição de uma célula ou coordenada após a execução

cap02.indd 27 1/11/2006 15:46:53

Page 20: Universidade VBA

28 universidade VBA

de uma macro ou script não é relevante, costuma-se ancorar o final do comando no início da planilha, na célula A1.

Edição de macros

Como já dissemos, o gravador de macros é uma boa forma de criar macros simples sem a necessidade de editar scripts, ou mesmo sem precisar criar macros para, depois, com o auxílio do botão Editar, observar como elas são processadas em formato de código pelo VBA (como fizemos anteriormente).

Porém, não podemos fazer a mesma observação com relação à criação de scripts complexos, com vários parâmetros ou seqüências de eventos. O que dizemos é ainda mais verdadeiro ao considerarmos (lembre-se da montagem de algoritmos) que uma seqüência de eventos não é necessariamente estática, e pode evoluir para duas ou mais variáveis.

Mostraremos a seguir, a utilização do editor, criando logo após, com seu auxílio, uma macro ainda relativamente simples.

Iniciando o uso do editor de macros

1. Abra o Microsoft Excel e selecione uma planilha. Em seguida, abra o menu Ferramentas > Macro > Editor do Visual Basic. Também podemos utilizar a com-binação de teclas Alt + F11 para abrir o Editor.

2. Será aberta uma janela do Microsoft Visual Basic, como podemos ver na Fi-gura 2.5. Existem, acopladas, duas janelas à esquerda. À janela superior chamamos de Projeto – VBAProject, e à janela inferior damos o nome de Propriedades. Na primeira, estão os elementos que fazem parte do projeto. Na segunda janela são listadas as propriedades dos objetos que porventura podem ser incorporados às nossas macros.

IMPORTANTE

A partir de agora, projeto deve ser entendido como o grupo de macros e de planilhas de Excel utilizados para uma determinada funcionalidade.

cap02.indd 28 1/11/2006 15:46:53

Page 21: Universidade VBA

Macros e VBA 29

2capítulo

Figura 2.5.

3. Apresentada a interface do editor, vamos dar início à sua utilização. Para tanto, vamos clicar no menu Inserir > Módulo.

Observe que na janela Projeto – VBAProject surge um novo diretório, chamado Módulo1, ou Módulo2, se você está utilizando um projeto que já havia sido iniciado. Dentro desse módulo, serão armazenadas as macros que criaremos, a partir de agora, para o projeto.

4. Note que também será aberta, na janela central, uma janela em branco, de-nominada Pasta1 – MóduloX (Código). Em que X é o número do módulo aplicado e a denominação Pasta1 pode ser substituída pelo nome da planilha que está sendo utilizada. Essa janela é a interface para a inserção dos comandos, onde inscreveremos os códigos que farão parte de nossa macro.

cap02.indd 29 1/11/2006 15:46:54

Page 22: Universidade VBA

30 universidade VBA

Figura 2.6.

5. Agora, vamos criar uma macro simples, que terá como função mudar a planilha ativa presente na tela do Excel (a conhecida planilha Plan1).

Na tela central do editor de macros, escreva o seguinte código:

Sub Alterar _ Folha de dados()

Worksheets(2).Activate

End Sub

6. Entre o princípio e o final da macro, escrevemos as instruções que desejamos que se realizem. No nosso caso, como já foi explicado, desejamos que a segunda planilha da pasta (Plan2) torne-se a planilha ativa.

Se quisermos simplesmente guardar a macro, é preciso salvar a planilha ativa com o nome que desejamos dar à macro, seguindo o menu Arquivo > Salvar <Nome da planilha>, ou utilizando a combinação de teclas Ctrl + B.

Criamos, assim, nossa primeira macro. É preciso prestar atenção, porém, a um detalhe: ao transplantar a planilha para outro computador, ou mesmo quando tenta-

cap02.indd 30 1/11/2006 15:46:54

Page 23: Universidade VBA

Macros e VBA 31

2capítulo

mos executar a macro nela contida em nosso Excel, é possível não obtermos sucesso. O que estará acontecendo?

Esse problema ocorre devido às opções de segurança do Microsoft Office. Há não muito tempo atrás (na verdade, até meados do ano 2000), a principal forma de contaminação de computadores por vírus e softwares maliciosos era, depois dos dis-quetes, os documentos do Microsoft Office e suas macros. Sabendo disso, a Microsoft criou opções de segurança para execução de macros, que podem ser acessadas, em qualquer programa do Office, por meio do menu Ferramentas > Macro > Segu-rança. Em seguida, escolha a opção Baixo. A própria opção vem inscrita como Não recomendável, e ela o é realmente: você só deve habilitá-la para testar suas próprias macros em seu computador, ou ao se deparar com problemas para rodar macros ab-solutamente necessárias em outros computadores também de sua responsabilidade. Salvo isso, mantenha a opção de segurança em Alto.

Figura 2.7.

Vamos conferir, agora, mais alguns exemplos simples de macros. Esses exemplos servirão como exercícios de fixação, para que você se familiarize com a produção de macros e botões e se prepare para os próximos capítulos, em que abordaremos macros de produção reais.

Primeiro exemplo

O objetivo da macro será abrir uma pasta de planilhas já existente. Saiba como construí-la:

cap02.indd 31 1/11/2006 15:46:54

Page 24: Universidade VBA

32 universidade VBA

1. Abra o editor de macros clicando em Ferramentas > Macro > Editor do Visual Basic.

2. Clique no menu Inserir > Módulo e, depois, clique na tela de escrita do código.

3. Inscreva o seguinte código:

Sub AbrirPasta()

Workbooks.Open (“E:\Documents and Settings\Admi-nistrador\Meus documentos\Monitores.xls”)

End Sub

Observe que colocamos o caminho do arquivo entre parênteses e aspas duplas, justamente para mostrar para a função Workbooks.Open que o parâmetro corres-ponde a uma coordenada que deve ser acessada; no caso, um arquivo que deve ser aberto. Esse arquivo deve ser obrigatoriamente uma planilha de Excel. Portanto, bancos de dados DBF, formulários do FoxPro e mesmo outros formatos de planilha, como o Quattro Pro, ainda que salvos no Excel e convertidos para seu formato, não serão abertos por essa macro VBA, pois a extensão de arquivos não corresponde ao padrão do Excel (extensão .xls)

Além disso, tanto o arquivo quanto o caminho devem existir, ou a macro nos retornará erro (Figura 2.8):

Figura 2.8.

Dessa forma, se o arquivo for movido desse diretório, ou se o próprio diretório mudar de nome, a macro deve ser atualizada manualmente. Se você tiver dúvidas sobre o erro apresentado na macro, utilize o botão Depurar para que o erro no código seja realçado em amarelo (Figura 2.9):

cap02.indd 32 1/11/2006 15:46:54

Page 25: Universidade VBA

Macros e VBA 33

2capítulo

Figura 2.9.

Segundo exemplo

O objetivo dessa macro é ativar uma pasta já aberta. Vejamos como estruturá-la:

1. Repita o primeiro e o segundo passos do primeiro exemplo, ou utilize a mesma planilha do exemplo anterior para criar essa nova macro.

2. Inscreva na tela de edição do código as seguintes instruções:

Sub AtivarPasta()

Workbooks(“Monitor.xls”).Activate

End Sub

Observe que, nessa macro, não indicamos o caminho em que se encontra o ar-quivo, pois ele deve estar aberto (portanto, dentro da memória RAM) para que a macro funcione.

cap02.indd 33 1/11/2006 15:46:55

Page 26: Universidade VBA

34 universidade VBA

3. Como esse é apenas mais um exemplo, para uma melhor organização o ideal seria juntar as macros do primeiro exercício em uma única macro, já que Activate, obrigatoriamente, deve ser utilizado para ativar um elemento da planilha.

Terceiro exemplo

O objetivo da macro é criar uma nova pasta de planilhas. Saiba como fazê-la:

1. Repita o primeiro e o segundo passos do primeiro exemplo, ou utilize a mesma planilha do exemplo anterior para criar essa macro.

2. Inscreva na tela de edição do código as seguintes instruções:

Sub NovaPasta()

Workbooks.Add

End Sub

3. Se você alterar uma planilha criada por essa macro, o Excel perguntará se deseja salvar as alterações. Note, portanto, que tanto a função quanto o comportamento dessa macro e das pastas de planilhas por ela criadas são exatamente as mesmas do botão Novo da barra de ferramentas padrão do Excel, ou da opção Novo do menu Arquivo.

Botões na barra de ferramentas

Até aqui, criamos diversas macros e vimos como colocá-las em funcionamento com o comando Macro, localizado no menu Ferramentas. Em algumas ocasiões, no entanto, pode ser necessária uma forma mais simples de acessar a macro recém-criada, seja por sua importância, seja pela necessidade freqüente de ativá-la. Por isso, terminaremos este capítulo criando uma barra de ferramentas personalizada, na qual será possível inserir todas as nossas macros.

Criação de uma nova barra de ferramentas

1. Abra o menu Exibir > Barras de ferramentas e selecione a opção Personalizar.

2. Será aberta a janela Personalizar. Clique na aba Barra de Ferramentas e depois em Nova.

cap02.indd 34 1/11/2006 15:46:55

Page 27: Universidade VBA

Macros e VBA 35

2capítulo

3. Aparecerá uma janela chamada Nova barra de ferramentas, na qual é preciso especificar o nome que daremos à nossa barra. Como exemplo, podemos citar Minhas macros ou Macros de trabalho.

4. Clique em OK e observe que a lista de barras de ferramentas disponíveis é acrescida do nome que demos à nossa barra. À direita do nome surgirá uma indica-ção, na caixa de verificação, de que essa barra está visível.

5. Clique na aba Comandos. Na lista de categorias, selecione a opção Macros. Na parte direita dessa mesma janela surgirão duas opções: Personalizar item de menu e Personalizar botão. Clique em Personalizar botão.

Figura 2.10.

6. Arraste esse botão até a nova barra de ferramentas. Os botões arrastados até ela serão anexados em tempo real à barra.

7. Na janela Personalizar, clique no botão Modificar seleção e selecione a opção Alterar imagem do botão, escolhendo, a seguir, o ícone que desejar.

Figura 2.11.

cap02.indd 35 1/11/2006 15:46:55

Page 28: Universidade VBA

36 universidade VBA

8. Clique novamente no botão Modificar seleção e, em seguida, na opção Nome. Dê o nome que desejar ao botão de macro.

9. Clique novamente no botão Modificar seleção e selecione a opção Atribuir macro. Aparecerá uma nova janela chamada Atribuir macro. Escolha a macro que deseja atribuir ao botão (pode ser uma das que criamos). Selecionada a macro, cli-que em OK e feche a janela Personalizar. Nossa barra de macros está pronta, sendo possível adicionar outros botões, se assim desejarmos.

cap02.indd 36 1/11/2006 15:46:55

Page 29: Universidade VBA

Capítulo 3 Elementos e base do VBA

cap03.indd 37 1/11/2006 15:47:10

Page 30: Universidade VBA

38 universidade VBA

Elementos e base do VBA

O VBA (Visual Basic for Applications) é, como o próprio nome diz, um kit de criação de scripts e aplicações baseado no Visual Basic. Por script entendemos um conjunto de procedimentos que conduz a uma determinada ação. Por aplicação, entendemos um conjunto de scripts voltados para uma ou mais ações e suas facetas. Pode-se, por exemplo, criar um script para ativar a correção ortográfica de uma tabela, o que é di-ferente de se criar uma ferramenta de correção ortográfica utilizando-se um conjunto de scripts sob a tutela de uma estrutura gráfica.

E é ao falar em estrutura gráfica que adentramos no reino do Visual Basic. O Visual Basic é uma linguagem de programação dirigida por eventos (event driven) e um ambiente de desenvolvimento integrado (IDE – Integrated Development En-vironment). O Visual Basic permite o desenvolvimento rápido de aplicações (RAD – Rapid Application Development) utilizando-se, para isso, da movimentação de objetos via interface gráfica (GUI – Graphical User Interface). Além disso, é pos-sível utilizar o Visual Basic para a criação de ActiveX controls. Um programador moderadamente talentoso pode fácil e rapidamente construir uma aplicação simples usando os componentes fornecidos com o VB.

O Visual Basic for Applications (VBA) é uma linguagem baseada no Visual Basic e voltada para a criação de macros, e está integrada a todos os produtos da família Microsoft Office.

Uma macro se assemelha muito a um script: ela é uma seqüência de instruções simples cujo objetivo é automatizar tarefas de pequena complexidade, enquanto existem scripts que podem ser complexos e realizar tarefas de grande complexidade. Podemos citar como utilidades típicas das macros:

• Abrir e fechar tabelas, perguntas, formulários e relatórios;• Imprimir dados;• Fazer uma pergunta;• Definir valores;• Procurar dados;• Construir um menu personalizado e executar comandos de menus;• Controlar a apresentação e o foco;• Executar outra aplicação.

O VBA trabalha com a criação de macros de duas maneiras diferentes: pelo ar-mazenamento do código da macro em módulos, ou como parte de um Formulário ou Relatório.

cap03.indd 38 1/11/2006 15:47:10

Page 31: Universidade VBA

Elementos e base do VBA 39

3capítulo

Módulos e seus elementos

Um módulo é um conjunto de declarações seguido de procedimentos. As instruções de declaração são utilizadas para nomear e definir procedimentos, variáveis, matrizes e constantes – estas, portanto, declaram que algo vai ser evocado, de forma direta, pelo código. A declaração costuma ser direcionada, via de regra, para procedimentos, porque são eles os responsáveis diretos pelo movimento de finalização – a seqüência de ações lógicas para que um código ou programa atinja o fim para o qual foi criado.

Um procedimento é uma seqüência lógica de instruções executadas como uma unidade. Um nome de procedimento é sempre definido em termos de módulo, como por exemplo quando um módulo é iniciado, e ao mesmo tempo nomeado, por Sub. Todo código executável deve estar contido em um procedimento. Procedimentos não podem ser aninhados dentro de outros procedimentos.

O exemplo a seguir contêm três declarações:

Sub ApplyFormat() Const limite As Integer = 33 Dim minhaCélula As Range ‘ Mais instruçõesEnd Sub

A instrução Sub (com a instrução End Sub correspondente) declara um procedimen-to nomeado ApplyFormat. Todas as instruções entre as instruções Sub e End Sub serão executadas sempre que o procedimento ApplyFormat for chamado ou executado.

Variáveis

Em algumas situações e códigos mais complexos, uma instrução pode conter uma variável. As variáveis são, do ponto de vista lógico, um local de armazenamento no-meado que pode conter dados, os quais podem ser modificados durante a execução do programa. Do ponto de vista lógico, as variáveis funcionam como potências: elas armazenam situações ou recursos que podem ser utilizados, mas que só se transformam em atos quando evocados pelo interpretador da linguagem de programação.

Cada variável possui um nome que a identifica com exclusividade dentro de seu escopo. Convencionou-se que os nomes de variáveis devem começar com um caractere alfabético, devem ser exclusivos dentro do mesmo escopo, não podem ter mais de 255 caracteres e também não podem conter um ponto ou caractere de declaração de tipo incorporado.

cap03.indd 39 1/11/2006 15:47:10

Page 32: Universidade VBA

40 universidade VBA

O tempo durante o qual uma variável retém o seu valor é conhecido como a sua vida útil. O valor de uma variável pode mudar no decorrer da sua vida útil, mas ela re-tém algum valor. Quando uma variável perde o escopo, ela deixa de ter um valor.

Quando você declara uma variável de objeto, o espaço é reservado na memória, mas o seu valor é definido como Nothing até você atribuir uma referência de objeto a ele através da instrução Set.

Caso o valor de uma variável não seja alterado durante a execução do seu código, ela reterá o valor inicial até perder o escopo. Caso os procedimentos chamem outros procedimentos, a variável reterá o seu valor enquanto esses procedimentos também estiverem sendo executados.

Quando tem início a execução de um procedimento, todas as variáveis são inicia-das. Uma variável numérica é iniciada como zero, uma seqüência de caracteres de comprimento variável é iniciada como uma seqüência de caracteres de comprimento zero (“”) e uma seqüência de caracteres de comprimento fixo é preenchida com o caractere representado pelo código de caractere ASCII 0 ou Chr(0).

Se existirem muitos dados a se trabalhar dentro de um código, pode-se utilizar o sistema de matriz. Uma matriz é uma variável única com muitos compartimentos para armazenar valores, enquanto uma variável típica tem somente um compartimento de armazenamento, no qual pode armazenar somente um valor. Uma matriz pode ser declarada para trabalhar com um conjunto de valores do mesmo tipo de dados, assim como pode ser utilizada para fazer referência a todos os valores que contém, assim como a valores individuais. Cada elemento de uma matriz possui um número de índice identificador exclusivo. As alterações feitas em um elemento de uma matriz não afetam os outros elementos.

Formulários

Um formulário é um tipo de objeto de banco de dados usado principalmente para inserir ou exibir dados em um banco de dados, e funciona, portanto, como uma interface entre o banco de dados ao qual está ligado e a aplicação que é sua usuária. Em alguns casos, formulários também podem ser utilizados para manipular um conjunto de dados esparsos (nomes de funcionários em uma planilha, uma lista de cores) e não um banco de dados na concepção exata do termo.

Um formulário também pode ser usado como um menu de controle que abre outros formulários e relatórios no banco de dados, ou como uma caixa de diálogo personalizada que aceita entrada de usuário e executa uma ação com base nessa mesma entrada. Boa parte das implementações para VBA é feita seguindo esses dois últimos modelos.

Cada formulário deve possuir, portanto, uma base ou fonte de registro. A fonte do registro de um formulário refere-se aos campos nas tabelas e consultas base. Um

cap03.indd 40 1/11/2006 15:47:10

Page 33: Universidade VBA

Elementos e base do VBA 41

3capítulo

formulário não precisa conter todos os campos de cada uma das tabelas ou consultas em que se baseia.

O vínculo entre um formulário e sua respectiva fonte de registro dá-se através de objetos gráficos chamados controles. O tipo mais comum de controle utilizado para exibir e inserir dados é a caixa de texto.

Controles

Quando criamos uma aplicação VBA utilizando formulários, inserimos nesta os controles que facilitarão a entrada e saída de dados ou informações – criamos, portanto, uma interface de comunicação. Dentro do arsenal de recursos do VBA, a coleção de objetos responsável pela construção de controles chama-se Controls.

Nessa coleção cada objeto possui um índice exclusivo cujo valor pode ser um número inteiro ou uma seqüência. O valor de índice do primeiro controle de uma coleção é 0, o do segundo controle é 1, e assim por diante. Esse valor indica a ordem na qual os controles foram adicionados à coleção.

Se o índice for uma cadeia, representará o nome do controle. A propriedade Name de um controle especifica também um nome de controle.

Você pode utilizar a coleção Controls para enumerar ou contar controles indivi-duais e para definir suas propriedades. Por exemplo, você pode enumerar a coleção Controls de um determinado formulário e definir a propriedade Height de cada controle com um valor específico.

No VBA a manipulação de controles é feita de forma mista, ou seja, arranjando os dados graficamente, ao mesmo tempo em que se faz ajustes finos na estrutura de alguns controles com o auxílio de código escrito e scripts.

O conjunto de controles disponíveis no VBA forma a entidade chamada Caixa de Ferramentas, de onde podemos retirar as unidades. Uma Caixa de Ferramentas é diferente de um conjunto de controles conceitual ou logicamente relacionado: controles conceituais geralmente são visualizados juntos, mas não necessariamente afetam uns aos outros, enquanto os controles logicamente relacionados afetam uns aos outros. Por exemplo, configurar um botão em um grupo de botões de opção con-figura o valor de todos os outros botões no grupo como Falso. Da mesma maneira, escolher uma cor dentre uma lista proposta em uma caixa de listagem com opção única faz com que todas as outras cores sejam descartadas do processo.

No decorrer deste livro serão implementados projetos utilizando tanto a estrutura de módulos (sobretudo quando se tratar do Microsoft Excel) quanto a de formulários (ao lidarmos com o Microsoft Access e o Outlook).

cap03.indd 41 1/11/2006 15:47:11

Page 34: Universidade VBA

cap03.indd 42 1/11/2006 15:47:11

Page 35: Universidade VBA

Recursos de programação VBA 43

4capítulo

Capítulo 4 Recursos de programação VBA

cap04.indd 43 1/11/2006 15:47:25

Page 36: Universidade VBA

44 universidade VBA

Estrutura

Estando familiarizado com os conhecimentos teóricos que um programador deve ter, e também com os mecanismos de produção de macros e códigos do VBA, chegou o momento de trabalhar diretamente com os comandos de VBA.

A estrutura dos códigos VBA, como já dissemos anteriormente, é organizada na forma propriedade – parâmetros – evento. Ou seja, em toda a linha do VBA são de-finidas, em primeiro lugar, as propriedades que vamos utilizar, depois os parâmetros com os quais será aplicada a propriedade e, por último, o evento que deve resultar da junção dos dois elementos anteriores.

Porém, também podemos pensar o VBA como uma estrutura modular (formada por módulos). A estrutura de módulos, ou modulada, consiste na construção de programas ou códigos extensos por meio da divisão em etapas menores, que são os módulos ou subprogramas.

A primeira dessas etapas, por onde começa a execução do trabalho, recebe o nome de programa principal, ao passo que as outras são os subprogramas propria-mente ditos, executados sempre que ocorre uma chamada, o que é feito por meio da especificação de seus nomes. Utilizar subprogramas, como faz o VBA, traz inúmeras vantagens:

• Economia de código;• Desenvolvimento modular, em que se pensa no algoritmo por partes;• Facilidade de depuração (correção e acompanhamento);• Facilidade para alteração do código;• Generalidade de código com o uso de parâmetros: algoritmos são escritos para

situações genéricas.

Há duas espécies de subprogramas: o procedimento e a função.

Procedimento

Um subprograma do tipo procedimento é um programa que tem vida própria, mas que, para ser processado, tem que ser solicitado pelo programa principal que o armazena, por outro subprograma, ou por ele mesmo. Basicamente, um procedimento funciona da seguinte maneira:

Public Static Sub <nome do procedimento()

declaração dos objetos locais ao Procedimento

cap04.indd 44 1/11/2006 15:47:26

Page 37: Universidade VBA

Recursos de programação VBA 45

4capítulo

comandos do Procedimento

End Sub

Funções

Além dos procedimentos, temos as funções. As funções são, na verdade, micro-programas evocados dentro de um programa maior (no nosso caso, um código VBA) e são utilizados para adicionar funcionalidades a um código, sem carregá-lo com divisões de código. Isso é possível, pois as funções funcionam como materiais pré-fabricados empregados na construção de casas: eles estão ali, à mão, prontos para serem utilizados, e basta combiná-los da forma desejada para que eles funcionem. Observe, a seguir, a estrutura de uma função:

Function Nom(………..) As …….. …………………… …………………… ……………………End Function

No parêntesis ao lado do nome da função, temos de inserir os argumentos da função e declará-los. Tais argumentos são sempre números ou conjuntos de variá-veis numéricas.

Os argumentos de uma função são os valores necessários para que ela possa ser executada. Se executássemos uma função parecida com Media(2,3) habilitaríamos a função Media para indicar a utilização dos valores n1=2 y n2=3 como argu-mentos de execução.

Uma função sempre retorna algum valor como resultado, sendo que o valor que desejamos obter deve ser declarado no código da função. Se quiséssemos, por exemplo, criar uma função que nos desse o produto de dois números multiplicados por dois, seria preciso declarar essa intenção utilizando o argumento As Double (é o dobro).

Para que isso ocorra, a construção da função deve conter a relação entre os argu-mentos de entrada e o valor de saída (a média, em nosso caso). Esse tipo de trabalho pode ser feito utilizando a seguinte expressão matemática:

Media = (n1 + n2) / 2

No decorrer do livro,entraremos em contato com exemplos mais práticos de procedimentos e funções.

cap04.indd 45 1/11/2006 15:47:26

Page 38: Universidade VBA

46 universidade VBA

Criação de variáveis no Visual Basic

Uma variável é um objeto criado pelo usuário no qual podemos introduzir valores que serão utilizados em cálculos ou em outros tipos de procedimentos.

Para criar uma variável em um programa VBA, no Editor do Visual Basic, siga o menu Ferramentas > Opções > Editor. Em seguida, selecione a opção Requerer declaração de variável e, logo após, clique em OK.

A partir desse momento, a primeira linha de cada módulo passará a se chamar ”Option Explicit” e será preciso declarar a variável a ser criada mediante o seguinte código:

Dim varMinhaVariável as String

Esse código fará com que o VBA reconheça todas as variáveis criadas, indi-cando, ao mesmo tempo, uma instrução que contenha um erro de ortografia ou de execução.

Tipos de variáveis

Para declarar uma variável no início de cada procedimento, deve-se definir o tipo de variável, escrito apenas com letras maiúsculas. Existem, essencialmente, quatro tipos principais de variáveis: String, Double, Date e Variant. É importante frisar que elas podem conter diversas outras variáveis especializadas.

String

Para conjuntos com até 65.000 caracteres (texto). Utiliza-se esse tipo de variável para conjuntos de caracteres, incluindo a definição de repositórios locais (C:\. D:\) ou de rede (\\192.168.1.20, \\josejoaquim), nomes de arquivos (gastos.xls), endereços de células ($A$1$) e todos os elementos de texto ou sobre os quais não efetuaremos cálculo. É o equivalente VBA das strings que definem as propriedades das células de uma planilha do Excel: não é possível fazer cálculos com células de texto, ao mesmo tempo em que não se pode utilizar funções de texto em células numéricas.

Double Variável aplicada em números com ou sem casas decimais. Double é uma variá-

vel genérica capaz de comportar muitas outras variáveis especializadas, que serão vistas adiante.

cap04.indd 46 1/11/2006 15:47:26

Page 39: Universidade VBA

Recursos de programação VBA 47

4capítulo

Bytes As variáveis Byte são armazenadas como números de 8 bits (1 byte), sem sinal,

únicos, que variam, em valor de 0 a 255. O tipo de variável Byte é útil para conter dados binários (0 e 1).

Integer

As variáveis Integer são armazenadas como números de 16 bits (2 bytes) com valor no intervalo de -32.768 a 32.767. O caractere de declaração de tipo para In-teger é o sinal de porcentagem (%).

As variáveis Integer também podem ser usadas para representar valores enu-merados. Um valor enumerado pode guardar um conjunto finito de números intei-ros exclusivos, cada um com um significado especial no contexto em que é usado. Valores enumerados oferecem uma forma conveniente de seleção entre um número conhecido de opções em um formulário. Por exemplo, preto = 0, branco = 1 e assim por diante. Pode-se definir constantes mediante a instrução CONST para cada valor enumerado.

Long

As variáveis Long (inteiro longo) são armazenadas como números de 32 bits (4 bytes), sinalizados, no intervalo de -2.147.483.648 a 2.147.483.647. O caractere de declaração de tipo para Long é o “e comercial” (&).

Single

As variáveis Single (vírgula flutuante de precisão simples) são armazenadas como números de vírgula flutuante com 32 bits (4 bytes), e têm um valor no inter-valo de -3,402823E38 a -1,401298E-45 para valores negativos e de 1,401298E-45 a 3,402823E38 para valores positivos. O caractere de declaração de tipo para Single é o ponto de exclamação (!). Single é a última das strings usadas para representar valores numéricos armazenados dentro da variável Double.

Date

Variável utilizada para a declaração de datas. As variáveis Date são armazenadas como números de ponto flutuante de 64 bits (8 bytes) responsáveis por representar as datas que variam de 1 de janeiro do ano 100 a 31 de dezembro de 9999, abrangendo também as horas de 0:00:00 a 23:59:59, segundo o modelo internacional de 24 horas.

cap04.indd 47 1/11/2006 15:47:27

Page 40: Universidade VBA

48 universidade VBA

Qualquer valor reconhecível e literal de data (não representado de maneira exclusi-vamente numérica) pode ser atribuído a variáveis Date. Os literais Date devem estar entre sinais (#), por exemplo, #1 de janeiro de 1993# ou #1 jan 93#.

As variáveis Date exibem as datas de acordo com o formato reconhecido por seu computador, assim como as horas (12 ou 24 horas). Para mais informações sobre como operar a configuração de data e hora, leia o tópico Configurações de data e hora, neste mesmo capítulo.

As datas manipuladas pela variável estão localizadas, normalmente, nas células das planilhas. É possível, portanto, copiar o conteúdo das células para o interior da variável Date sem prejuízo nenhum no desenrolar do código.

Variant

O tipo de variável Variant é utilizado para todas as variáveis não explicitamente declaradas como de algum outro tipo (usando instruções como Dim, Private, Pu-blic ou Static). O tipo de dados Variant não possui caractere de declaração.

Uma Variant é um tipo especial de variável que pode guardar qualquer dado, exceto dados String de comprimento fixo. Uma Variant também pode conter os valores especiais Empty, Error, Nothing e Null. É possível determinar como os da-dos em uma Variant são tratados mediante as funções VarType ou TypeName.

Os dados numéricos podem ter qualquer valor de número inteiro ou real no intervalo de -1,797693134862315E308 a -4,94066E-324 para valores negativos e de 4,94066E-324 a 1,797693134862315E308 para valores positivos. Geralmente, os dados numéricos Variant são mantidos em seu tipo original no interior da variável.

Variant pode ser utilizado em códigos que guardam uma grande quantidade de cálculos a serem processados, pois essa variável é capaz de trabalhar com mais de 4000 cálculos por vez.

Configurações de data e hora

Para fazer alterações na forma como seu sistema operacional trabalha com parâ-metros de data e hora, abra o menu Iniciar > Configurações > Painel de controle > Opções regionais > Geral. Em seguida, clique em Inglês (Estados Unidos) e, depois, em Aplicar, se deseja utilizar o modelo americano, que divide o dia em duas partes iguais, representadas por AM (horas do dia) ou PM (horas da noite).

As configurações para as horas podem ser feitas por meio das configurações da aba Hora. Na seção Formato de hora, podemos especificar de que maneira a hora atual será exibida na tela. A programação pode ser feita manualmente, por meio da digitação de combinações de letras e símbolos:

cap04.indd 48 1/11/2006 15:47:27

Page 41: Universidade VBA

Recursos de programação VBA 49

4capítulo

Tabela 4.1.

Não é preciso programar configurações no separador ou no símbolo de visuali-zação das horas, pois estes são padrões internacionais.

Agora, vamos implementar as configurações de data. Para tanto, ainda em Opções regionais, selecione a aba Data.

Para

Exibir a hora em um formato de 24 horas.

Exibir a hora em um formato de 12 horas.

Suprimir a exibição de zeros à esquerda em segundos, minu-tos ou horas em um dígito.

Exibir uma única letra para indicar AM ou PM.

Exibir duas letras para indicar AM ou PM.

Exibir texto.

Digite

Digite H ou HH para a hora. Uma só letra H mostrará a hora no formato de um único dígito (por exemplo, 9). Duas letras mos-trarão a hora no formato de dois dígitos (por exemplo, 09).

Digite h ou hh para a hora. Uma só letra h mostrará a hora no formato de um único dígito (por exemplo, 9). Duas letras mos-trarão a hora no formato de dois dígitos (por exemplo, 09).

Digite um único H, em letra maiúscula ou minúscula, como, por exemplo, em H:m:s.

Digite um t minúsculo no final da declaração dos valores, como por exemplo em HH:mm:ss t.

Digite tt minúsculos no final da declaração dos valores, como por exemplo em HH:mm:s tt.

Digite aspas simples (’) ao redor do texto.

Figura 4.1.

Na seção Calendário, é possível configurar como o sistema vai se comportar quan-do um ano for digitado com apenas dois dígitos. Existe uma limitação de 100 anos

cap04.indd 49 1/11/2006 15:47:27

Page 42: Universidade VBA

50 universidade VBA

no complemento de datas abreviadas do Windows, que estabelece, por padrão, que apenas os anos entre 1930 e 2029 são reconhecidos. Para modificar essa configuração, basta ir à segunda caixa da seção em que está o valor 2029, alterando-o por um valor de sua escolha. Note que o primeiro valor também é alterado. Dessa forma, se alte-rarmos 2029 para 2050, o número anterior será imediatamente alterado para 1951.

Na seção Data abreviada, mais precisamente na linha Exemplo de data abreviada, nos é exibida a forma como uma data abreviada será mostrada no sistema. Esse layout afeta diretamente a maneira como as datas serão mostradas em um aplicativo VBA.

O modo como a data abreviada é exibida pode ser alterado reconfigurando a linha Formato de data abreviada de acordo com os parâmetros seguintes:

Para

Exibir números de um dígito sem um zero à esquerda.

Exibir zeros à esquerda com números de um dígito.

Exibir os dois últimos dígitos do ano.

Exibir quatro dígitos para o ano.

Exibir abreviações para o dia ou mês.

Exibir o nome completo do dia ou mês.

Exibir texto adicional.

Digite

Digite um único caractere. Digite d para o tipo de configuração referente ao dia, digite a para a configuração referente ao ano e M para a configuração referente ao mês. Assim, por exemplo, para produzir uma data como 9/9/9, digite d/M/a.

Digite dois caracteres. Digite dd para a configuração referente ao dia, digite aa para a configuração referente ao ano e MM para a configuração referente ao mês. Por exemplo, para produzir 09/06/06, digite dd/MM/aa.

Digite aa para a configuração referente ao ano.

Digite aaaa para a configuração referente ao ano. Por exemplo, para obter 10/12/2005, digite dd/MM//aaaa.

Digite três caracteres. Digite ddd para a configuração referente ao dia e MMM para a configuração referente ao mês. Dessa forma, se você pretende que uma quarta-feira, dia 18 do mês de janeiro de 2006, surja como quarta 18/jan/2006, digite ddd/MMM/aaaa.

Digitar quatro caracteres. Digite dddd para a configuração referente ao dia e MMMM para a configuração do mês. Assim, se você deseja que 10/02/2007 seja mostrado como quinta-feira, 10 de fevereiro de 2007, digite dddd/MMMM/aaaa.

Digite aspas simples (’) ao redor do texto.

Tabela 4.2.

Loops

Com as instruções de estrutura (também chamadas de estruturas de controle), podemos criar códigos no Visual Basic capazes de tomar decisões e repetir ações. No Capítulo 1, Introdução à lógica de programação, ao falarmos sobre algoritmos discor-

cap04.indd 50 1/11/2006 15:47:28

Page 43: Universidade VBA

Recursos de programação VBA 51

4capítulo

remos sobre a necessidade de utilizar estruturas de repetição na produção de soluções que demandam a repetição contínua de procedimentos ou a escolha entre duas ou mais variáveis, seguida do reposicionamento do código em posição original.

Se precisarmos repetir o código, podemos utilizar o loop, permitindo a execução de um grupo de instruções repetidamente. Alguns loops repetem instruções até que uma condição seja False (Falso), ao passo que outros repetem as instruções até uma condição ser True (Verdadeiro). Também há loops que repetem instruções um número específico de vezes ou em cada objeto de uma coleção.

Do...Loop Quando precisamos de um loop que persista até que uma condição seja True,

utilizamos a instrução Do...Loop. Na forma de uma instrução simples, ele pode ser utilizado para continuar a execução de uma macro de forma indiscriminada, como mostramos agora, no tópico Exercício 1:

Exercício 1

1. Abra uma planilha do Excel e preencha-a com os seguintes dados:

1234567891011121314151617181920

A

Max20222729252524232221272022262329272825

B

Min172123202116172026211617201823212220

C

Media

D

Data01/03/200102/03/200103/03/200104/03/200105/03/200106/03/200107/03/200108/03/200109/03/200110/03/200111/03/200112/03/200113/03/200114/03/200115/03/200116/03/200117/03/200118/03/200119/03/2001

Tabela 4.3.

2. Agora, utilize o atalho Alt + F11 para acessar o editor de VBA em uma pla-nilha em branco.

cap04.indd 51 1/11/2006 15:47:28

Page 44: Universidade VBA

52 universidade VBA

3. Dentro da janela do editor, insira o código de loop que exibimos a seguir. Os co-mentários assinalados com ‘ (apóstrofo simples) são indicações nossas e as utilizamos apenas para documentar o código, introduzindo informações sobre novos conceitos.

Sub Loop1()‘ O loop irá apenas até a célula seguinte da coluna, de cima

para baixo, caso os parâmetros estabelecidos sejam cumpridos (True). Do contrário, o processo de migração para a próxima coluna será interrompido.

Do‘Do é utilizado para especificar o que devemos fazer em um

determinado caso. Em um loop, Do tem a função de condicional, sendo utilizado para definir a condição True da estrutura.

ActiveCell.FormulaR1C1 = “=Average(RC[-1],RC[-2])”

‘ActiveCell.FormulaR1C1 indica que a macro começará a ser utilizada em conjunto com a fórmula R!C!, pertencente à fun-ção Average (Média, na versão em português do Excel). A cada vez que o cálculo da média for realizado pela presença dos dados, o looping será executado, repetindo a utilização da fórmula na próxima célula da coluna.

ActiveCell.Offset(1, 0).Select

Loop Until IsEmpty(ActiveCell.Offset(0, 1))

‘É estabelecido que deve haver um loop a partir da célula ativa (ActiveCell) direcionada; utiliza-se a função Offset para indicar direcionamento. Os parênteses após Offset indi-cam as coordenadas que serão aplicadas no direcionamento. Na forma (1,0), 1 indica que o looping sempre deslocará a formula uma linha abaixo da célula atualmente ativa e 0 indica que o deslocamento será na mesma coluna.

End Sub

cap04.indd 52 1/11/2006 15:47:28

Page 45: Universidade VBA

Recursos de programação VBA 53

4capítulo

4. Inscrito o código (é claro que podemos omitir os comentários), volte para a planilha em que você inseriu os dados, selecione a célula C2 e utilize o atalho Alt + F8, rodando a macro criada logo em seguida.

É possível utilizar essa macro para criar planilhas que calculem diariamente a cotação de uma moeda, como por exemplo juros mensais ou os rendimentos de um determinado conjunto de papéis no mercado de ações.

Do...While Para verificar se a condição é verdadeira ou falsa, utilizamos a palavra-chave

While>. A princípio, While era a instrução utilizada para criar sistemas de loop em programas até que uma opção fosse dada como True. Como loop, no entanto, é uma solução mais estruturada, convencionou-se empregar While como uma “âncora” para a chamada de True. A sintaxe da expressão é:

While condition[statements]Loop

A sintaxe da instrução While possui as seguintes partes:

Parte

condition

statements

Descrição

Obrigatória. Expressão numérica ou expressão de seqüência avaliada como True ou False. Se condition for Null, será tratada como False, de acordo com as regras da lógica da programação, que estabelecem que um valor nulo, equivalente a 0, costuma ser um valor False.

Opcional. Uma ou mais instruções executadas enquanto a condição for True. Na verdade, não há muito sentido em criar uma função While sem a presença dos statements.

Tabela 4.4.

No tópico seguinte, utilizaremos a função While para definir um loop até o ponto em que uma condição não seja mais verdadeira (True), ou seja, apareça como False. Na prática, ela faz a mesma coisa que a macro do tópico Exercício 1, mas, desta vez, procura por uma condição verdadeira na coluna ao lado, e não na célula abaixo, localizada na mesma coluna.

cap04.indd 53 1/11/2006 15:47:28

Page 46: Universidade VBA

54 universidade VBA

Exercício 2

1. Abra uma planilha do Excel e preencha-a com os mesmos dados exibidos no tópico Exercício 1.

2. Em seguida, abra o editor do Visual Basic e digite o seguinte código (os co-mentários, novamente, são nossos):

Sub Loop2()

‘ Este loop roda enquanto existir um valor verdadeiro na coluna ao lado

Do While IsEmpty(ActiveCell.Offset(0, 1)) = False

‘Do While utiliza aqui a função IsEmpty, empregada para retornar um valor booleano (0 ou 1, Verdadeiro ou Falso) que indica se uma variável foi iniciada. No caso anterior, ele só será executado se as coordenadas expressas (0,1) equivalerem à mesma linha utilizada atualmente na planilha, conferindo, porém, os dados presentes na coluna seguinte.

ActiveCell.FormulaR1C1 = “=Average(RC[-1],RC[-2])”

ActiveCell.Offset(1, 0).Select

Loop

End Sub

3. Salve a macro. Vá até a planilha editada anteriormente, posicione o cursor sobre a célula C2 e rode a macro que acabamos de criar.

For...Next A função For...Next utiliza um contador para executar instruções um deter-

minado número de vezes. A sintaxe do comando é a seguinte:

cap04.indd 54 1/11/2006 15:47:29

Page 47: Universidade VBA

Recursos de programação VBA 55

4capítulo

For counter = start To end [Step step] [statements] [Exit For] [statements]

Next [counter]

Em que:• counter é uma instrução obrigatória, empregada como um contador dos loops

que serão realizados. A variável não pode ser um valor booleano nem uma matriz;• start é o valor inicial de counter;• end é o valor final de counter, o momento em que o loop será interrompido;• Step é o valor da alteração do contador sempre que passar pelo loop. Se Step

não for especificado, o padrão será 1 (um).

O exercício seguinte mostra um loop criado com a instrução For...Next e capaz de avançar por dez células até ser interrompido.

Exercício 3

1. Abra qualquer planilha do Excel como, por exemplo, a planilha em que inse-rimos os dados dos modelos anteriores. Depois, abra o editor de VBA.

2. Crie um novo módulo, clicando com o botão direito do mouse na pasta Módulos, localizada à direita da tela, e seguindo o menu Inserir > Novo módulo.

3. Escreva na janela do novo módulo o seguinte código:

Sub Accumulate()Dim n As IntegerDim t As Integer

‘A função Dim, utilizada para definir e armazenar variáveis define que o valor n é um dado Integer. Nesse caso, utilizamos Integer para especificar um conjunto de valores enumerados. A mesma observação vale para Dim trabalhando com a variável t, na linha seguinte.

For n = 1 To 10 t = t + n

cap04.indd 55 1/11/2006 15:47:29

Page 48: Universidade VBA

56 universidade VBA

‘ Note que n, ao mesmo tempo em que é uma variável, será utilizado como contador por For. Definimos o Start da conta-gem como 1, e o End como 10. Na mesma linha, definimos que o produto será igual ao valor do produto da linha anterior mais n. O valor de n é iniciado com 1 e vai até 10.

Next n‘Next é a segunda parte do comando de loop. É nele que

estabelecemos em que resultará o loop

MsgBox “ O total é “ & t‘MsBox é o objeto padrão do VBA utilizado para criar caixas

de texto na tela. Os textos apresentados no box devem ficar entre parênteses. O & (“e comercial”) é utilizado como aglu-tinador do texto, ligando-o ao resultado obtido pela soma da última célula contabilizada pelo counter do looping.

End Sub

4. Grave a macro e execute-a em uma planilha qualquer. O resultado será seme-lhante ao mostrado na Figura 4.2:

Figura 4.2.

Condições lógicas: If...Then...Else /Select Case

Todos os loops exibidos anteriormente são artifícios simples, mesmo quando traba-lham com condicionais. Não vimos, mesmo ao trabalhar com For...Next, escolhas condicionais além da interrupção de um loop, caso uma coluna não corresponda a um determinado parâmetro.

Muito mais complexo, e muito mais útil para uma planilha de dados com o Excel, é fazer com que o loop deixe de lado o preenchimento de células que não correspondem a um determinado requisito, ou que tenham um valor nulo, mas, ao mesmo tempo

cap04.indd 56 1/11/2006 15:47:29

Page 49: Universidade VBA

Recursos de programação VBA 57

4capítulo

conte com a opção de continuar se repetindo nas células posteriores às células com conteúdo False. Um looping desse tipo pode ser obtido com o auxílio da instrução If...Then...Else (traduzindo, Se... Então... De outra maneira).

Essa instrução executa condicionalmente um grupo de instruções, de acordo com o valor de uma expressão, e obedece à seguinte sintaxe:

If condition Then [statements] [Else elsestatements]

Também é possível inserir a sintaxe em forma de bloco:

If condition Then[statements][ElseIf condition-n Then[elseifstatements] ...[Else[elsestatements]]End If

Em qualquer caso, cada um dos elementos corresponde ao seguinte:• condition é um ou mais dos dois tipos de expressão seguintes. Essa expressão

pode ser numérica, avaliada como True ou False. Se condition for Null, será tratada como False;

• statements é opcional na forma de bloco e obrigatória na forma de uma linha que não tenha cláusula Else (De outra maneira). Suporta uma ou mais instruções separadas por dois-pontos, que serão executadas se condition for True;

• condition-n> é opcional, já que é igual a condition;• elseifstatements é opcional e define se uma ou mais instruções serão

executadas se a condition-n associada for True;• elsestatements é opcional e define se uma ou mais instruções serão

executadas se nenhuma expressão condition ou condition-n anterior for True.

No Exercício 4, veremos uma implementação simples de código utilizando somente a instrução If. Nele, faremos com que seja retornado erro caso uma célula esteja vazia, ou seja, caso tenha conteúdo False ou Null.

Exercício 4

1. Abra uma nova planilha do Excel e preencha-a com os dados apresentados, ou com dados parecidos:

cap04.indd 57 1/11/2006 15:47:29

Page 50: Universidade VBA

58 universidade VBA

Tabela 4.5.

2. Em seguida, abra o editor de VBA, crie um novo módulo e digite o seguin- te código:

Sub Loop4() Do

If IsEmpty(ActiveCell) Then

‘ Início da condicional: Se a célula estiver ocupada (com conteúdo), então a condição de prosseguimento será satisfeita.

ActiveCell.FormulaR1C1 = “=Average(RC[-1],RC[-2])”

End If‘ End If marca o fim da condição

ActiveCell.Offset(1, 0).Select

‘A célula que deve ser selecionada como ativa é a da linha seguinte à célula atual, na mesma coluna.

1234567891011121314151617181920

A

Max2022272925

272022262329272825

B

Min1617212320

211617201823212220

C

Media

D

Data01/03/200102/03/200103/03/200104/03/200105/03/200106/03/200107/03/200108/03/200109/03/200110/03/200111/03/200112/03/200113/03/200114/03/200115/03/200116/03/200117/03/200118/03/200119/03/2001

cap04.indd 58 1/11/2006 15:47:30

Page 51: Universidade VBA

Recursos de programação VBA 59

4capítulo

Loop Until IsEmpty(ActiveCell.Offset(0, 1))

‘ O loop será executado se uma célula na mesma linha, mas na coluna seguinte, estiver ocupada.

End Sub

3. Salve o código e vá para a planilha que foi criada no primeiro passo. Selecione a célula C2 e rode a macro criada (Loop4). O resultado será parecido com o que mostramos a seguir:

1234567891011121314151617181920

A

Max2022272925

272022262329272825

B

Min1617212320

211617201823212220

C

Media18,0019,5024,0026,0022,50

#DIV/0!#DIV/0!#DIV/0!#DIV/0!#DIV/0!

24,0018,0019,5023,0020,5026,0024,0025,0022,50

D

Data01/03/200102/03/200103/03/200104/03/200105/03/200106/03/200107/03/200108/03/200109/03/200110/03/200111/03/200112/03/200113/03/200114/03/200115/03/200116/03/200117/03/200118/03/200119/03/2001

Tabela 4.6.

Como podemos notar, as linhas em que não havia dados apresentaram erro du-rante o looping. Isso ocorreu porque a condição estabelecida (If...Then) foi a de que a fórmula seria aplicada repetidamente em cada célula ocupada.

Para que as mensagens de erro não surjam na planilha, fazendo com que as cé-lulas vazias simplesmente sejam ignoradas, utilizaremos no Exercício 5 a instrução If...Then.

Exercício 5

1. Com a planilha montada anteriormente, abra o editor do VBA e produza a macro seguinte. Lembre-se de que os comentários (’) são apenas indicações sobre determinados pontos do programa e, portanto, não fazem parte do código:

cap04.indd 59 1/11/2006 15:47:30

Page 52: Universidade VBA

60 universidade VBA

Sub Loop5()

Do

If IsEmpty(ActiveCell) Then

‘Se a célula está ativa na mesma linha, mas está ocupada na coluna anterior, então...

If IsEmpty(ActiveCell.Offset(0, -1)) And IsEmpty(ActiveCell.Offset(0, -2)) Then

ActiveCell.Value = “ “

‘… Se a célula está ativa na mesma linha, mas nas duas colunas anteriores (0,-1) e (0,-2), não está ocupada por dados, então a célula é preenchida por um espaço vazio, definido por “ “. Note que aqui é utilizada uma condição (If) dentro de outra.

Else

ActiveCell.FormulaR1C1 = “=Average(RC[-1],RC[-2])”

‘ Aqui, utilizamos a condição Else (De outra maneira). Se nenhuma das condições do comando anterior for satisfeita, passa-se para a situação em que se utiliza a função de cál-culo da Média normalmente.

End If

End If

‘ Terminam aqui as condicinais If.

ActiveCell.Offset(1, 0).Select

Loop Until IsEmpty(ActiveCell.Offset(0, 1))‘Enfim, aplica-se o loop mostrado nos exercícios anteriores

para o deslocamento das células da coluna seguinte.End Sub

cap04.indd 60 1/11/2006 15:47:30

Page 53: Universidade VBA

Recursos de programação VBA 61

4capítulo

2. Salve a macro e, na planilha, ative a célula C2. Em seguida, ative a macro Loop5. Note o que ocorre:

1234567891011121314151617181920

A

Max2022272925

272022262329272825

B

Min1617212320

211617201823212220

C

Media18,0019,5024,0026,0022,50

24,0018,0019,5023,0020,5026,0024,0025,0022,50

D

Data01/03/200102/03/200103/03/200104/03/200105/03/200106/03/200107/03/200108/03/200109/03/200110/03/200111/03/200112/03/200113/03/200114/03/200115/03/200116/03/200117/03/200118/03/200119/03/2001

Tabela 4.7.

Como era nossa intenção, as células que dependiam de células nulas da mesma linha foram ignoradas (preenchidas com espaço em branco) e não marcadas com uma mensagem de erro, como no exercício anterior. Essa tática pode ser utilizada para montar planilhas que não apresentam mensagens de erro ou que precisem de mensagens diferenciadas para a ausência de conteúdo em cada tipo de célula.

Select Case

Select Case é uma expressão lógica utilizada para execução um entre os di-versos grupos de instruções presentes em um código. O determinante da execução é o valor da expressão utilizada. A sintaxe de uma expressão Select Case é:

Select Case testexpression [Case expressionlist-n [statements-n]] ... [Case Else [elsestatements]]

End Select

cap04.indd 61 1/11/2006 15:47:30

Page 54: Universidade VBA

62 universidade VBA

em que:

• testexpression corresponde a qualquer expressão numérica, ou de seqüên-cia, necessária para a escolha correta da função;

• expressionlist-n produz uma lista delimitada a partir de algumas das seguintes formas: expression, expression To expression e Is comparisonoperator expression. A palavra-chave To especifica um intervalo de valores. Se você empregar a palavra-chave To, o valor menor deve aparecer antes dela. Aplique a palavra-chave Is com operadores de comparação (exceto Is e Like) para especificar um intervalo de valores. Se não for fornecida, a palavra-chave Is será inserida automaticamente;

• statements-n faz com que uma ou mais instruções sejam executadas se testexpression coincidir com qualquer parte de expressionlist-n. É um recurso opcional;

• elsestatements faz com que uma ou mais instruções sejam executadas se testexpression não coincidir com qualquer das cláusulas Case.

No tópico seguinte, damos um exemplo simples do funcionamento de Select Case montando uma planilha para o cálculo de taxas. Essa pequena planilha pode ser utilizada de forma isolada ou na montagem de uma planilha de taxas um pouco mais elaborada.

Exercício 6

1. Nosso cenário é o seguinte:• Em uma determinada modalidade de taxas, os primeiros R$ 2.500,00 de todo

valor são livres de taxação;• Os valores superiores a R$ 2.500,00 e inferiores a R$ 5.000,00 são taxados

com 5%;• Todo valor maior do que R$ 5.000,00 é taxado em 10%.

2. Para representar esse cenário, vamos utilizar uma planilha em branco do Excel e preenchê-la da seguinte maneira:

• Na célula A1, digitamos Para o valor de, ao passo que na célula B1 digitamos R$ 2.000,00;

• Na célula A2, digitamos Taxa a pagar, enquanto na célula B2, digitamos =taxa(B1).

3. Agora, abra o editor de VBA e digite em um novo módulo o seguinte código (os comentários são nossos):

Public Function taxa()

cap04.indd 62 1/11/2006 15:47:31

Page 55: Universidade VBA

Recursos de programação VBA 63

4capítulo

Select Case income Case Is <= 2500 taxa = 0‘Se o valor for menor ou igual a R$ 2.500,00, a opção es-

colhida será taxa=0 Case Is <= 5000 taxa = (5000 - 2500) * 0.05‘Se o valor for menor ou igual a R$ 5.000,00, a taxa será

de 0,05 ou 5% Case Else taxa = (income - 5000) * 0.1 + 125‘Se o valor for maior que R$ 5.000,00, a taxa deverá ser

multiplicada por 0.1 mais 5% End Select

End Function

4. Salve o módulo e volte para a planilha. Em seguida, ative a célula B2, onde inserimos a expressão que ativa a macro, e aperte a tecla Enter. Veja o resultado:

C

R$ 20.000,001625

A

12

Para o valor deTaxa a pagar

Tabela 4.8.

5. Com um simples arrastar-e-soltar, podemos tornar a planilha muito mais interessante, fazendo com que a macro efetue o cálculo de vários valores. É uma operação muito mais simples do que montar uma função matemática para cada caso de taxação (são três casos diferentes), aplicando-as manualmente ao descobrir em que caso elas se encaixam. Observe:

Para o valor deTaxa a pagar

R$ 20.000,00R$ 1.625,00

R$ 12.000,00R$ 825,00

R$ 250.000,00R$ 24.625,00

R$ 1.900,00R$ 0,00

R$ 25.000,00R$ 2.125,00

Tabela 4.9.

Caixas de texto TextBox

Caixas de texto são utilizadas para implementar a comunicação entre o programa e o usuário ou vice-versa. Um TextBox é o controle mais utilizado para exibir infor-mações, inseridas por um usuário, em uma caixa de texto. Além disso, pode exibir

B

cap04.indd 63 1/11/2006 15:47:31

Page 56: Universidade VBA

64 universidade VBA

conjuntos de dados, como tabelas, consultas, planilhas ou o resultado de cálculos. Caixas de texto são objetos dinâmicos: se um TextBox estiver ligado a uma fonte de dados, a alteração do seu conteúdo vai alterar também o valor da fonte de dados acoplada. Da mesma forma, a formatação aplicada a qualquer parte do texto de um TextBox afetará todo o texto do controle. Como exemplo, se você alterar a fonte ou o tamanho em um ponto de qualquer caractere de um controle, essa alteração afetará todos os caracteres desse controle.

O TextBox é um controle flexível governado pelas seguintes propriedades: Text, MultiLine, WordWrap e AutoSize.

Text contém o texto exibido na caixa. Por outro lado, MultiLine controla se Text-Box pode exibir texto como uma única linha ou como múltiplas linhas. Os caracteres da nova linha identificam onde termina uma linha e onde a outra começa. Se MultiLine for False, o texto ficará truncado em vez de mudar de linha automaticamente.

WordWrap permite que o TextBox mude automaticamente de linha quando as linhas de texto forem maiores que a largura. Quando não utilizamos WordWrap, o TextBox iniciará uma nova linha de texto quando encontrar um caractere que indique o procedimento. Se WordWrap estiver desativado, é possível obter linhas de texto que não se ajustem completamente ao TextBox. O TextBox exibirá as partes do texto que se ajustarem à sua largura e truncará as partes que não se ajustarem. WordWrap não é aplicável, a não ser que MultiLine seja True.

AutoSize controla se o TextBox será ajustado para exibir todo o texto. Ao utilizar AutoSize com um TextBox, a largura deste diminui ou aumenta de acordo com a quantidade de texto e com o tamanho da fonte utilizada.

Uma TextBox é um pouco diferente de uma MsgBox. Se com este comando cria-mos caixas que mostram mensagens na tela, com aquele somos capazes de inserir dados no programa, utilizando, portanto, a funcionalidade da caixa no sentido inverso.

No Exercício 7, criaremos uma caixa de texto simples. Nela, basta teclar Enter (comportamento quase instintivo para os usuários de computadores) para escrever algo na caixa. Novamente, os comentários serão nossos.

Exercício 7

1. Abra uma planilha em branco e, em seguida, o editor de VBA (Alt + F11). Logo após, clique com o botão direito do mouse em Formulários > Inserir > User-Form. Utilizamos a opção UserForm em vez de Módulo, porque, no caso das caixas de texto, criaremos antes de tudo a estrutura gráfica, para depois complementarmos o objeto com o código.

2. Será aberta a área UserForm1 (Figura 4.3). Essa área é utilizada para a inserção de um determinado objeto pré-modelado e sua programação.

cap04.indd 64 1/11/2006 15:47:31

Page 57: Universidade VBA

Recursos de programação VBA 65

4capítulo

Figura 4.3.

3. Vá ao menu Exibir do editor de VBA e clique na opção Caixa de ferramentas. Essa opção ativa a barra de tarefas homônima com vários modelos para objetos de formulário que podem ser anexados a um projeto de VBA. Para tanto, basta arrastar e soltar o objeto escolhido. No caso das caixas de texto, clique no objeto (Figura 4.4) e arraste-o para a área UserForm1. O resultado será parecido com o da Figura 4.5, em que também podemos ver a Caixa de ferramentas.

Figura 4.4.

Figura 4.5.

cap04.indd 65 1/11/2006 15:47:32

Page 58: Universidade VBA

66 universidade VBA

4. Isso feito, edite a caixa de texto. Para tanto, clique duas vezes no objeto e será aberta a janela de inserção de código, com o seguinte conteúdo:

Option Explicit

Private Sub TextBox1 _ Change()

End Sub

Private Sub UserForm _ Click()

End Sub

5. Esse conteúdo equivale ao delineamento de uma caixa de texto simples. User-Form _ Click() é o objeto do VBA que permite a ativação de um formulário, ou de um outro objeto, a partir de uma ação do usuário; um clique do mouse ou o apertar de uma tecla, por exemplo. Por último, vamos inserir o código que permitirá a habilitação da caixa com a tecla Enter:

Private Sub TextBox1 _ KeyDown(ByVal KeyCode As MSForms.ReturnInteger, _

ByVal Shift As Integer)‘ Note que criamos TextBox1 como uma sub-função. Além disso,

deve-se substituir TextBox1 _ Change(), do objeto padrão, por _ KeyDown. KeyDown, um tipo de evento que só ocorre quando um usuário aperta uma determinada tecla.

If KeyCode = 13 Then‘ 13 equivale à tecla Enter na tabela VBKey do VBA. Essa

tabela corresponde às constantes, também chamadas VBKey, uti-lizadas para ligar o objeto VBA a eventos de teclado (teclas pressionadas) ou de mouse (cliques com os botões do dispo-sitivo). Uma lista completa das strings do VBKey pode ser encontrada no Apêndice 1 deste livro.

Sheet1.Range(“A65536”).End(xlUp).Offset(1, 0) = TextBox1TextBox1 = vbNullString‘ Com Sheet1, indicamos que o comando diz respeito à planilha

atualmente ativa. Da mesma forma, a instrução Range(“A65536”)

cap04.indd 66 1/11/2006 15:47:32

Page 59: Universidade VBA

Recursos de programação VBA 67

4capítulo

especifica que todas as células dessa planilha serão consi-deradas ativas. =TextBox1 mostra ao programa que a ativação de qualquer célula da planilha equivale à chamada da caixa de texto. vbNullString é uma constante especial que retorna uma string nula.

End IfEnd Sub

Molduras (frames) e botões de opção (options buttons)

Nesse tópico, continuaremos a trabalhar com objetos gráficos. Dessa vez, no en-tanto, vamos nos concentrar nos frames, ou molduras, parte essencial da manipulação de objetos gráficos no VBA.

O frame, ou moldura, é utilizado para montar um grupo de controles. Um grupo de controles consiste em um conjunto de controles relacionados conceitual ou logi-camente. Como exemplo, podemos configurar um conjunto de botões, fazendo com que um deles seja clicado para acionar uma determinada opção ou funcionalidade de uma planilha, ao passo que o restante será tratado como False.

Todos os botões de opção em um frame são mutuamente exclusivos, portanto, podemos utilizar um frame para criar um grupo de opções, todas verdadeiras. Como exemplo, em um aplicativo que processa pedidos, com nome, endereço e número de conta dos clientes, todas as opções serão True, mas nada impede que elas sejam agrupadas em um único frame ou moldura.

Finalmente, podemos definir os frames como formas passivas, utilizadas para moldar um conjunto de comandos em um determinado layout.

Aqui, vamos mostrar a montagem de uma moldura muito simples, acompanhada de alguns botões de opções. Utilizaremos as ferramentas gráficas do formulário para criação de nosso frame.

Exercício 8

1. Abra o editor do VBA e, na árvore do lado direito da tela, clique com o botão direito do mouse em Formulários, selecionando, em seguida, a opção Inserir > User-Form. Utilize o comando Selecionar objetos (Figura 4.6), da Caixa de ferramentas, e clique no formulário criado.

Figura 4.6

cap04.indd 67 1/11/2006 15:47:32

Page 60: Universidade VBA

68 universidade VBA

2. Posicione o cursor do mouse na lateral da área UserForm até ele se transformar em uma seta com duas pontas. Em seguida, arraste a seta para baixo, para que o espaço útil da área seja aumentado.

Figura 4.7.

3. Logo após, acesse novamente a Caixa de ferramentas e clique duas vezes na opção Quadro (Figura 4.8). É esse o comando utilizado para a montagem de um frame. O cursor do computador será transformado em uma cruz. Arraste-a para criar um frame do tamanho desejado (Figura 4.9):

Figura 4.8.

Figura 4.9.

cap04.indd 68 1/11/2006 15:47:33

Page 61: Universidade VBA

Recursos de programação VBA 69

4capítulo

4. Procure, agora, na Caixa de ferramentas, pelo comando Botão de opção (Fi-gura 4.10). Clique duas vezes no comando e arraste-o para dentro do frame. Repita o processo três vezes, criando uma fileira vertical com três botões de opção, como mostramos na Figura 4.11:

Figura 4.10.

Figura 4.11.

5. Clique com o botão direito do mouse sobre a moldura que circunda o frame e selecione a opção Propriedades. A moldura é o quadrado com hachuras que utili-zamos para movimentar o objeto e alterar seu tamanho. Do lado inferior-esquerdo da tela, surgirá a janela Propriedades, na qual podemos alterar as configurações do objeto por meio de um sistema de formulários em que cada linha equivale a uma das propriedades do frame utilizado.

Figura 4.12.

cap04.indd 69 1/11/2006 15:47:33

Page 62: Universidade VBA

70 universidade VBA

6. Nessa mesma janela, selecione a linha BackColor (Cor de Fundo) e expanda o menu suspenso que aparece ao lado da opção. Altere a cor do frame para a cor padrão da área de trabalho do Windows, clicando na opção de cor Área de traba-lho. Também poderíamos completar tal atividade com a ajuda de código, e com a propriedade BackColor, que obedece à seguinte sintaxe:

objeto.BackColor [= Longo]

Em que objeto deve ser substituído pelo nome do elemento atualmente manipu-lado, como, por exemplo, um frame. Longo deve ser substituído pelo valor-código da cor escolhida, com qualquer inteiro que represente uma cor válida. Também podemos especificar uma cor utilizando a função RGB com componentes em cores vermelha, verde e azul. O valor de cada componente de cor é um inteiro que varia de zero a 255. Como exemplo, podemos especificar azul turquesa com o valor inteiro 4966415 ou os componentes vermelho, verde e azul como 15, 200 e 75, respectivamente. O código da cor de fundo do objeto ficaria mais ou menos assim:

TextBox6.BackColor = RGB(0, 255, 0) ‘Esta combinação de RGB equivale à cor verde.

TextBox3.BackColor = RGB(0, 255, 255) ‘Esta combinação equivale ao ciano

TextBox3.BorderColor = RGB(0, 0, 0) ‘Aqui criamos um fundo preto

TextBox4.BackColor = RGB(0, 0, 100) ‘Aqui temos azul marinho

TextBox5.BackColor = RGB(128, 128, 128) ‘Um cinzento bem pronunciado

7. Na linha Caption, podemos dar ao objeto um nome que será mostrado para o usuário. Se nenhum nome for atribuído, o nome padrão do objeto será exibido na tela. Para nosso frame, atribuiremos a frase: Escolha seu lanche. Também é possível fazê-lo com a linha de comando: a propriedade Caption será sempre a primeira na declaração de propriedades de um objeto.

Private Sub Frame1() Frame1.Caption = “Escolha seu lanche”

cap04.indd 70 1/11/2006 15:47:33

Page 63: Universidade VBA

Recursos de programação VBA 71

4capítulo

8. Clique, agora, com o botão direito do mouse no primeiro Botão de opção, no interior da moldura, e selecione novamente a opção Propriedades. A janela que antes existia para o objeto Frame será sobreposta à do objeto OptionButton1. A primeira coisa a ser alterada é a cor de fundo do objeto, para que ele acompanhe a cor de fundo do frame. O resultado final é mostrado na figura a seguir:

Figura 4.13.

9. Para testar o comportamento do aplicativo, clique no botão Salvar e, em seguida, execute o aplicativo apertando o botão Executar Sub/UserForm (Figura 4.14). No resultado final, você verá a tela de seleções surgir (Figura 4.15):

Figura 4.14.

Figura 4.15.

cap04.indd 71 1/11/2006 15:47:33

Page 64: Universidade VBA

72 universidade VBA

Você deve ter percebido que o objetivo desse exercício era manipular objetos visuais do VBA, alterando algumas de suas configurações, e não criar um aplicativo acabado. Basta notar que as ações definidas não foram atreladas aos botões e que não foi criado um botão de OK ou outra forma de sair do aplicativo.

UserForms e objetos

Este projeto será mais elaborado que o anterior, pois vamos atrelar ações es-pecíficas à ListBox e aos demais componentes presentes em nosso frame. Além disso, teremos de criar diversas estruturas menores para povoar nossa moldura, o que começaremos a fazer no tópico Exercício 9, antes de partirmos para montagem da ListBox propriamente dita.

Exercício 9

1. Abra o editor de VBA e, em seguida, clique com o botão direito do mouse no diretório Formulários, localizado na árvore à esquerda da tela. Escolha a opção Inserir > UserForm.

2. Aumente o tamanho da área da UserForm com o cursor. Logo após, clique com o botão direito do mouse, selecione a opção Propriedades. Aparecerá a tela de propriedades da UserForm, em que podemos alterar todos os valores relacionados ao objeto, como já fizemos no exercício anterior.

3. Anteriormente, apresentamos algumas propriedades como Caption. Agora, nos deteremos um pouco mais em algumas delas e no modo de editá-las.

• Name: é o nome com o qual vamos identificar a UserForm. Tem de ser um nome único, sem espaços ou símbolos como separadores. Um bom truque é iniciar o nome do objeto com UF. Assim, sempre que o código fizer referência a este objeto, saberemos que se trata de uma UserForm;

• Caption: como já vimos, Caption se refere ao título que o usuário verá no quadro de diálogo. Podemos inserir qualquer tipo de texto, incluindo espaços;

• BackColor: é a cor de fundo da caixa de diálogo. Já vimos como realizar a alteração da propriedade BackColor no Exercício 8;

• ForeColor: é a cor do primeiro plano, ou seja, a cor do texto que aparece na caixa de diálogo;

• Font : é a fonte utilizada como padrão para a caixa de diálogo, incluindo os botões de controle presentes na caixa de diálogo;

cap04.indd 72 1/11/2006 15:47:33

Page 65: Universidade VBA

Recursos de programação VBA 73

4capítulo

• StartupPosition: é a posição em que aparecerá a caixa de diálogo. Ao utilizar-mos, por exemplo, o valor ”CenterScreen”, o objeto será exibido no centro da tela;

• SpecialEffect: são efeitos especiais para a borda da caixa de diálogo; • Picture, PictureAlignment, PictureSizeMode e PictureTiling:

são propriedades utilizadas para inserir e formatar as características de figuras no interior da UserForm.

4. Agora, vamos inserir uma caixa de texto em nossa UserForm. Para tanto, na janela Caixa de ferramentas, clique no botão Caixa de texto e arraste o objeto para a UserForm. É possível utilizar o mouse para alterar a localização e o tamanho desse controle.

5. Clique com o botão direito do mouse na caixa de texto e selecione a opção Propriedades. Aparecerá a janela Propriedades do lado direito da tela. Vejamos as principais propriedades com que trabalharemos:

• Name: é o nome do objeto. Como já apontamos anteriormente em relação a UserForm, aqui também não é permitida a utilização de espaços ou símbolos. Nomeie o objeto como TB (iniciais de TextBox) para identificá-lo no decorrer do código;

• Text: corresponde ao texto no interior da caixa de texto. Podemos inserir um texto do tipo: Preencha com seus dados, ou Digite um número. Essa caixa pode ser editada pelo usuário com a inserção de novos dados;

• TextAlign: alinhamento do texto dentro da UserForm. Normalmente, se quisermos que o usuário introduza uma seqüência de texto, é preciso alinhar o tex-to à esquerda (mTextAlignLeft). Se for preciso introduzir números, costuma-se alinhar o texto à direita (fmTextAlignRight). Para alinhar um texto de forma centralizada, escolha fmTextAlignLeft;

• MultiLine: estabelece se os valores possíveis são True ou False. Tais va-lores indicam se será possível que o usuário escreva ou não mais de uma linha na caixa de texto.

Na propriedade TextAlign, vamos escolher fmTextAlignRight, já que usaremos essa caixa para inserir um número.

6. Agora, vamos inserir um texto descritivo do lado do quadro de edição. Para

tanto, vamos novamente para a janela Caixa de ferramentas, em que selecionamos a opção Rótulo (Figura 4.16), posicionando-a acima da caixa de texto. Todos os elementos de texto de uma UserForm que não correspondam a objetos editáveis mas somente a textos indicativos ou explicativos devem ser montados com a ajuda da opção Rótulo:

cap04.indd 73 1/11/2006 15:47:34

Page 66: Universidade VBA

74 universidade VBA

Figura 4.16.

7. Clique com o botão direito do mouse sobre o Rótulo e selecione a opção Pro-priedades. A propriedade utilizada para fazer com que o rótulo mostre um texto é Caption. Preencha-a com o texto Digite um número.

Terminamos nosso exercício com uma bela estrutura: alinhamento, nomes, tudo estabelecido. Porém, um aplicativo em VBA ou em qualquer outra linguagem de programação deve possuir uma maneira de ser reiniciado ou finalizado.

Em aplicativos gráficos, isso é feito por botões de controle. No exercício seguinte, vamos construir um botão de controle dentro da UserForm anteriormente criada, além de lhe atribuir uma função.

Exercício 10

1. Na UserForm em que trabalhamos no exercício anterior, montaremos um botão OK e um botão Cancelar. Começamos pelo Cancelar, de execução um pouco mais simples. Começamos novamente pela Caixa de ferramentas, selecionando o comando Botão de comando (Figura 4.17):

Figura 4.17.

2. Posicione o botão na parte inferior da UserForm. Em seguida, clique com o botão direito do mouse e selecione Propriedades. Vamos editar algumas das pro-priedades do objeto:

• Name: no nome do controle, vamos escrever cbCancel, para documentar o código (cb é a sigla para CommandButton);

• Caption: no texto mostrado no botão, vamos escrever Cancelar;• Cancel: essa propriedade pode ter o valor True ou False. Só pode existir

um controle em uma determinada caixa de diálogo ou UserForm, com a propriedade Cancel estabelecida como verdadeira. Se dermos à Cancel o valor True, basta que o usuário utilize a tecla Esc para que o botão editado seja ativado, como se houvesse sido clicado com o mouse. Selecione a opção True;

• Default: com valor True ou False, indica se o botão pertence à caixa de diálogo. Se optarmos por definir a propriedade como True, o botão será ativado, assim como seria ativado com a tecla do mouse se o usuário apertasse a tecla En-ter. Como o botão em questão é o Cancelar, e, além disso, pretendemos reservar

cap04.indd 74 1/11/2006 15:47:34

Page 67: Universidade VBA

Recursos de programação VBA 75

4capítulo

a propriedade Default para o botão OK, que montaremos mais tarde, optamos por False.

Se executarmos o projeto agora, veremos que temos um botão acionado com a tecla Esc, mas que não faz nada além disso. Para que o botão faça alguma coisa, é preciso operar com um conceito muito importante da programação de objetos: os eventos.

4. Um evento é uma ação concreta que ocorre sempre que um objeto ou proprie-dade é ativado por um agente, que pode ser uma tecla, um clique do mouse ou outro objeto. O comum para um botão Cancelar é que o usuário clique com o mouse ou selecione com o teclado. Esse tipo de evento é chamado de Click.

Criaremos um evento Click, chamando-o de cbCancelar _ Click(). Para tanto, clicamos duas vezes no botão Cancelar, exibindo a janela de código corres-pondente ao projeto.

5. Vejamos o seguinte código:

Private Sub cbCancelar _ Click()

End Sub

O Excel encarregou-se de criar a estrutura do evento. Agora, temos de preen-chê-lo. A instrução que utilizamos para fechar uma UserForm é Unload, que serve para limpar um objeto da memória ativa do sistema. A instrução Unload requer um parâmetro, utilizado para indicar qual objeto deve ser retirado da memória.

Em nosso caso, utilizaremos a palavra-chave Me, que aponta o objeto em que estamos executando o código, ou seja, nossa UserForm.

6. Nosso código, então, ficará assim:

Private Sub cbCancelar _ Click() Unload MeEnd Sub

Faça o teste. Rode o aplicativo e clique no botão Cancelar (ou aperte a tecla Esc). Se a janela for fechada, o botão está funcionando.

Com a técnica de criação de botões, vamos passar para o próximo exercício. Nele, criaremos mais um botão, tão necessário quanto o botão Cancelar: o botão OK.

cap04.indd 75 1/11/2006 15:47:34

Page 68: Universidade VBA

76 universidade VBA

Exercício 11

1. Abra a Caixa de ferramentas e clique em Botão de comando. Coloque esse novo botão na UserForm em que criamos o botão Cancelar. O ideal é posicioná-lo do lado esquerdo do botão Cancelar.

2. Clique, com o botão direito do mouse, sobre o comando e selecione a opção Propriedades. Em Name, digite cbOK, ou o nome que você quer dar ao botão. Em Caption, definimos que a mensagem inscrita no botão será OK.

3. Na propriedade Default, definimos o valor como True. Dessa forma, sempre que o usuário apertar a tecla Enter, o botão OK será ativado, da mesma forma que ocorreria se o mouse tivesse sido utilizado.

4. Clique duas vezes no botão para que surja a janela de código. Dentro da es-trutura do botão:

Private Sub cbOK _ Click()

End Sub

idêntica à do botão Cancelar, insira o seguinte código:

Private Sub cbOK _ Click() ActiveCell.Value = TextBox1.Value Unload MeEnd Sub

Essa função é praticamente igual à que inserimos no botão Cancelar, com exceção de que antes de fechar a caixa de diálogo, temos de escrever uma outra linha, que se encarrega de copiar a célula ativa da planilha a qual pertence o aplicativo com o conteúdo da caixa de texto.

Observe que ativamos a caixa de texto por meio do nome do controle (TextBox1) e sua propriedade Value:

ActiveCell.Value = TextBox1.Value

Estabelecemos que a célula da planilha é igual ao valor da caixa de texto presente na UserForm. Se não existir nenhum caractere numérico na caixa de texto, o valor capturado para a célula será 0.

cap04.indd 76 1/11/2006 15:47:34

Page 69: Universidade VBA

Recursos de programação VBA 77

4capítulo

UserForms mais elaboradas

Nesse tópico, vamos construir uma UserForm mais elaborada, aproveitando para mostrar mais alguns recursos da Caixa de ferramentas. Suponhamos que temos uma folha de cálculo em que há uma célula com o nome de uma pessoa e outra célula com o sobrenome. Criaremos uma UserForm que permita ao usuário editar o nome e o sobrenome localizados na planilha, e que, além de tudo, logo que apertar o botão OK na caixa de diálogo, transfira os valores inseridos pelos usuários para a planilha.

Exercício 11

1. Antes de tudo, vamos criar nossa planilha. À primeira coluna, que terá os no-mes, daremos o título de rgNome, e à segunda coluna, responsável pelos sobrenomes, chamaremos de rgSobrenome.

2. Agora, acessamos o editor de VBA e criamos uma UserForm. Mediante o botão direito do mouse, abra o menu Inserir > UserForm. Vamos dar a essa UserForm o nome de ufDadosPessoais, editando a linha Name da janela Propriedades.

3. Clique na Caixa de ferramentas e insira duas caixas de texto, uma para o nome e outra para o sobrenome, às quais daremos os nomes tbNome e tbSobrenome.

4. Inserimos, agora, dois rótulos, que colocaremos à esquerda de cada uma das caixas de texto. No primeiro rótulo, escreveremos Nome e, no segundo, Sobrenome. Para tanto, edite as linhas Caption das janelas de propriedades de cada objeto.

Figura 4.18.

cap04.indd 77 1/11/2006 15:47:34

Page 70: Universidade VBA

78 universidade VBA

5. Clique, agora, no comando Botão de comando, da Caixa de ferramentas e arraste um botão para a UserForm. Na janela Propriedades, mude o nome do botão para a cbCancelar, digite Cancelar na linha Caption e, na propriedade Cancel, selecione o valor True.

6. Inserimos, então, um botão OK, nomeando-o como cbOK. Na linha Caption, setaremos OK e daremos à propriedade Default o valor True.

7. Vamos aos eventos: para o botão Cancelar, a função que devemos escrever é exatamente igual à mostrada no exercício anterior:

Private Sub cbCancelar _ Click() Unload MeEnd Sub

A única coisa que esse botão faz é fechar a caixa de diálogo assim que o botão Cancelar for pressionado pelo mouse ou acionado pela tecla Esc.

8. A função para o botão OK também é bem parecida com a anterior:

Private Sub cbOK _ Click() Range(“rngNome”).Value = tbNome.Text Range(“RngSobrenome”).Value = tbSobrenome.Text Unload MeEnd Sub

Essa função é executada quando produzimos o evento Click do botão chamado cbOK. Porém, antes de fechar a caixa de diálogo, a função guarda nas células de nossa planilha os valores presentes nas caixas de texto. Para tanto, utilizamos um objeto Range e estabelecemos que sua propriedade Value é igual ao valor da propriedade Text do objeto TextBox.

9. Execute o aplicativo e observe que ele funciona perfeitamente: se alterarmos os nomes na UserForm e clicarmos em OK, veremos que as células da planilha também terão o conteúdo alterado e agora armazenam novos nomes. No entanto, algo escapou.

Se acessarmos diretamente a planilha, podemos alterar os nomes contidos nas células e depois, ao executar a UserForm, veremos que os controles de edição não têm os nomes atualizados, pois não são capazes de recolher as alterações feitas di-retamente na folha de cálculo.

cap04.indd 78 1/11/2006 15:47:35

Page 71: Universidade VBA

Recursos de programação VBA 79

4capítulo

10. Para resolver esse problema, vamos utilizar um evento específico para a UserForm. Esse evento chama-se Initialize, e é executado antes da UserForm surgir na tela.

Para criar esse evento, clique com o botão direito do mouse sobre a UserForm de nosso aplicativo e, depois, em Exibir código.

11. No menu suspenso, localizado no canto superior direito da tela, substitua Click por Initialize. O Excel criará uma estrutura para essa nova função:

Private Sub UserForm _ Initialize()

End Sub

12. É no miolo dessa função que temos de escrever o código a ser executado antes que a UserForm seja exibida. O que vamos fazer é inserir, nas duas caixas de texto, o conteúdo das células com esses dados. Para tanto, utilizaremos o seguinte código:

Private Sub UserForm _ Initialize() tbNome.Text = Range(“rngNome”).Value tbSobrenome.Text = Range(“rngSobrenome”).ValueEnd Sub

cap04.indd 79 1/11/2006 15:47:35

Page 72: Universidade VBA

cap04.indd 80 1/11/2006 15:47:35

Page 73: Universidade VBA

Propriedades 81

5capítulo

Capítulo 5 Propriedades

cap05.indd 81 1/11/2006 15:48:32

Page 74: Universidade VBA

82 universidade VBA

Eventos seletivos

No capítulo anterior, criamos uma UserForm com botões utilizáveis, ou seja, capaz de por em prática uma instrução simples. No entanto, falta um toque de inteligência ao nosso aplicativo. Se, no lugar de números, o pretenso usuário decidisse preencher as células com palavras ou caracteres aleatórios, não haveria obstáculo nenhum.

Para impedir o preenchimento aleatório de uma caixa de texto, seria preciso utilizar o evento KeyPress. Esse evento ocorre quando o usuário pressiona uma tecla que produz um caractere (uma tecla ANSI) em um formulário executado. O evento pode ocorrer tanto antes como depois de a tecla ser solta.

Um evento KeyPress pode ser genérico, abrangendo toda a tabela de caracteres ANSI, ou seletivo – objeto de nosso interesse. Se uma determinada tecla é confi-gurada para receber apenas um tipo de caractere ANSI, outros tipos de caracteres serão “barrados” como elementos não-aceitáveis. As teclas e combinações aceitas por KeyPress são:

• Qualquer caractere do teclado alfabético, além de símbolos de pontuação presentes no teclado;

• Qualquer caractere de teclado numérico;• CTRL combinada com um caractere do alfabeto padrão;• CTRL combinada com qualquer caractere especial;• Backspace (barra de espaço) e Esc.

As teclas Tab, Enter e todas as teclas funcionais (Insert, Home e Delete, por exemplo) não são aceitas, além das teclas direcionais (as “setas”).

Em nosso próximo exercício, criaremos um formulário, ligado a uma planilha, que terá por objetivo marcar as horas extras de profissionais liberais que recebem por hora. Nesse aplicativo será possível escrever apenas números nas caixas de texto, para impedir que os usuários preencham os campos com dados em forma-to texto.

Exercício 1

1. Abra uma planilha do Excel e, na primeira coluna (A), digite hEntrada, para representar a hora de entrada no trabalho. Na segunda coluna (B), digite hSaída, para representar a hora de saída. Por último, na terceira coluna (C), digite hTrab para representar as horas trabalhadas. Na quarta coluna (D), que chamaremos de nProf̧ serão colocados os nomes dos profissionais donos das horas.

cap05.indd 82 1/11/2006 15:48:32

Page 75: Universidade VBA

Propriedades 83

5capítulo

2. Em seguida, acione o editor de VBA (Alt + F11). Clique com o botão direito do mouse em Formulários > Inserir > UserForm. Clique na Caixa de ferramentas. Em seguida, selecione o controle Caixa de texto. Inclua três caixas de texto em sua UserForm. Você também pode arrastar uma única caixa de texto para o interior da UserForm e, logo após, dar-lhe um clique com o botão direito, selecionando, então, a opção Copiar. Escolha uma área da UserForm com o botão direito do mouse e selecione a opção Colar.

3. De volta à Caixa de ferramentas, selecione o controle Botão de comando e arraste-o para a UserForm, posicionando-o abaixo das caixas de texto. Você pode criar mais um botão de comando na UserForm; basta clicar no comando criado com o botão direito do mouse, copiando-o e colando-o em seguida. Posicione os dois botões lado a lado.

4. Clique duas vezes no botão à esquerda, que será utilizado como botão Cancelar, ou, com o botão direito do mouse, selecione a opção Exibir código. Após a linha:

Private Sub CommandButton2 _ Click()

Insira o código que habilita as funções de um botão Cancelar:

Unload Me

5. Edite, agora, o botão OK, repetindo o processo: pressione duas vezes o botão e, em seguida, escreva na área correspondente à área do botão o código abaixo, utilizado para dar funcionalidade ao botão OK:

Private Sub cbOK _ Click() Range(“hEntrada “).Value = hEntrada Range(“hSaída “).Value = hSaída Range(“hTrab “).Value = hTrab Range(“nProf “).Value = nProf Unload MeEnd Sub

Note que criamos saídas para as quatro colunas presentes em nossa planilha. Ela tem seus correspondentes nas quatro caixas de texto da UserForm. Assim, as informações na planilha serão atualizadas de acordo com o conteúdo das caixas de texto, assim que o aplicativo VBA for fechado.

cap05.indd 83 1/11/2006 15:48:32

Page 76: Universidade VBA

84 universidade VBA

6. Aqui, “travaremos” o acesso de outros valores diferentes de números nas caixas de texto. Clique em cada uma das caixas de texto presentes na UserForm e, entre as linhas:

Private Sub TextBox1 _ Change()

End Sub

Insira o seguinte código:

Private Sub TextBox1 _ KeyPress()(BeVal KeeAscii As _ MSForms.ReturnInteger)If KeeAscii < Asc(“0”) Or KeeAscii > Asc(“9”) ThenKeeAscii = 0End IfEnd Sub

Estabelecemos aqui que se (If) o valor da propriedade KeeAscii for menor que zero e maior que nove, então (Then) KeeAscii deve ser tratada como se o seu valor fosse igual a zero, o que equivale a bloquear a edição da propriedade, pois zero é igual a valor nulo ou fechado.

7. Clique nas demais caixas de texto (salvo a quarta, em que deve constar nomes) e insira o mesmo código. Salve o projeto.

Caixa de listagem (ListBox)

Uma forma mais sofisticada de produzir um objeto VBA seria criar caixas de listagem, também conhecidas como ListBox.

Uma ListBox é um objeto que exibe um ou mais valores, permitindo a seleção de um deles. Deste objeto são feitas as caixas de verificação ou menus suspensos da maioria das aplicações Windows. De uma maneira simplória, uma caixa de listagem pode ser feita dentro do editor do VBA se selecionarmos, na Caixa de ferramentas, o objeto Caixa de listagem (Figura 5.1) para, em seguida, empurrá-lo para a área da UserForm.

Figura 5.1.

cap05.indd 84 1/11/2006 15:48:33

Page 77: Universidade VBA

Propriedades 85

5capítulo

Um objeto construído dessa forma, no entanto, é uma caixa vazia, pois não foram adicionados parâmetros (opções) à listagem e nem foram definidas propriedades de ação ao seu manuseio.

Uma ListBox exibe uma lista de valores e nos permite selecioná-los. O List-Box pode aparecer como uma lista (opção padrão) ou como um grupo de controles OptionButton ou CheckBox. A propriedade-padrão de um ListBox é a Value. O evento-padrão do controle ListBox é o Click.

Existem dois estilos possíveis para a montagem de uma ListBox. Se optarmos pelo estilo Plain, temos cada item de uma lista em uma linha separada. O usuário selecionará um item realçando uma ou mais linhas.

Se o estilo for Option, um botão de opção ou uma caixa de verificação aparecerá no início de cada linha. Com esse estilo, o usuário pode selecionar um item clicando no botão de opção ou na caixa de verificação.

É por isso que, no próximo exercício, estudaremos a forma de montar uma List-Box com o auxílio do editor de código. Preste atenção nos comentários para entender o processo de desenvolvimento.

Exercício 2

1. Crie uma nova planilha do Excel e, na coluna A, insira os dados pertinentes a uma determinada lista. Essa lista pode conter nomes de pessoas, objetos, equipamen-tos de informática, livros etc. Em nosso exemplo, utilizaremos uma lista de países.

2. Utilize o atalho Alt + F11 para abrir o editor do VBA. Crie, depois, uma UserForm e nela insira o código seguinte (os comentários são nossos):

Private Sub UserForm _ Initialize()′ Initialize é o comando utilizado para iniciar um aplicativo

VBA antes que o Excel seja iniciado. Você pode substituir o nome UserForm por outro nome qualquer, Países, por exemplo.

Dim MinhaLista As Variant, i As Long With Me.ListBox1′ Dim é a instrução utilizada no VBA para declarar variá-

veis e o local de armazenamento dessas variáveis. O nome da variável, declarado obrigatoriamente após a instrução, é aqui definido como MinhaLista.

.Clhear ‘ Limpa o conteúdo da listbox MinhaLista = UniqueItemList(Range(“A1:A100”), True)

cap05.indd 85 1/11/2006 15:48:33

Page 78: Universidade VBA

86 universidade VBA

‘ Utilizamos a linha acima para capturar todos os elemen-tos presentes na coluna A. Estabelecemos que MinhaLista será igual uma lista de item único, que abrange um range válido (True) de opções da célula A1 até a célula A100

For i = 1 To UBound(MinhaLista) .AddItem MinhaLista(i) Next i .ListIndex = 0 ‘ Selecione sempre o primeiro item da listagem End WithEnd Sub‘ A função que captura os nomes dos países listados na

planilha termina aqui.

Private Function UniqueItemList(InputRange As Range, _ HorizontalList As Boolhean) As Variant‘ A função aqui iniciada tem por objetivo ordenar os ele-

mentos capturados a partir das coordenadas (range) propostas no início do código. HorizontalList estabelece que os dados devem ser organizados no formato de uma lista horizontal, que emprega dados booleanos (Verdadeiro ou Falso) para operar.

Dim cl As Range, cUnique As New Collhection, i As Long, uList() As Variant

Application.Volatilhe On Error Réume Next For Each cl In InputRange If cl.Formula <> “” Then cUnique.Add cl.Value, CStr(cl.Value) End If‘ Se (If) a fórmula de inserção de dados se deparar com

uma célula vazia (“”) esse lapso não será computado como valor para a listagem, que prosseguirá computando os dados normalmente

Next cl UniqueItemList = “” If cUnique.Count > 0 Then ReDim uList(1 To cUnique.Count) For i = 1 To cUnique.Count uList(i) = cUnique(i)

cap05.indd 86 1/11/2006 15:48:33

Page 79: Universidade VBA

Propriedades 87

5capítulo

‘ Aqui estabelecemos que todos os elementos maiores que 0 (portanto, True ou Verdadeiros) serão considerados True ou Verdadeiro (representados aqui pelo valor booleano 1) e serão anexados à lista.

Next i UniqueItemList = uList If Not HorizontalList Then UniqueItemList = _ Application.WorksheetFunction.Transpose

(UniqueItemList) End If End If‘ Aqui estabelecemos que a lista montada deve ser trans-

posta, pela Propriedade Application.WorksheetFunction.Trans-pose, para a planilha por nós criada. Lembre-se de que, como utilizamos Initialize no começo do código, a aplicação será aberta juntamente com a planilha, como se fosse um adendo.

On Error GoTo 0‘ Essa linha estabelece que, em caso de erro (On Error) o

código deve retornar (GoTo) para o início, estabelecido pelos parênteses fechados (). Essa operação evita o travamento ou suspensão do aplicativo em caso de erro.

End Function

3. Terminado o aplicativo, rode-o e observe o resultado na figura seguinte:

Figura 5.2.

É claro que não demos nome à caixa de diálogo, nem inserimos botões como OK e Cancelar. Mas foi simplesmente para não sermos repetitivos: a essa altura, você

cap05.indd 87 1/11/2006 15:48:33

Page 80: Universidade VBA

88 universidade VBA

mesmo pode montar seus botões, se não de olhos fechados, ao menos seguindo os passos de exercícios anteriores.

Caixas de combinação (ComboBox)

Uma ComboBox combina os recursos de ListBox e TextBox. O usuário pode inserir um novo valor, como com um TextBox, ou pode selecionar um valor exis-tente, como em uma ListBox.

Para que seja possível listar dados ou valores, um ComboBox deve estar ligado a uma fonte de dados. Nesses casos, a ComboBox vai inserir o valor que o usuário digitar ou selecionar na fonte de dados.

A lista em um ComboBox consiste em linhas de dados. Cada linha pode ter uma ou mais colunas, que podem aparecer com ou sem cabeçalhos. Alguns aplicativos não suportam cabeçalhos de colunas, outros, como o Excel, fornecem apenas um suporte limitado.

A propriedade padrão de um ComboBox é a Value e o evento padrão de um ComboBox é Change.

Para exemplificar a construção de uma ComboBox, vamos construir, no próximo exercício, um formulário ou uma caixa de diálogo para a inserção de dados pessoais. Os primeiros passos serão semelhantes aos mostrados no Exercício 11 do Capítulo 4, Recursos de programação VBA, com a criação da UserForm e dos botões principais.

Exercício 3

1. Crie uma planilha para inserção de nome, sobrenome, estado civil e idade de uma série de pessoas. À primeira coluna, que guardará os nomes, daremos o título de rgNome, e à segunda coluna, responsável pelos sobrenomes, chamaremos de rgSobrenome, a terceira se chamará rgEstadoCivil e a quarta rgIdade.

2. Acesse o editor de VBA e crie uma UserForm com o botão direito do mouse e o menu Inserir > UserForm. Vamos dar a essa UserForm o nome de ufDadosPes-soais2, editando a linha Name da janela Propriedade.

3. Clique, agora, na Caixa de ferramentas e insira quatro caixas de texto, uma para cada coluna da planilha.

4. Inserimos então os rótulos correspondentes a cada uma das caixas:• Nome;• Sobrenome;

cap05.indd 88 1/11/2006 15:48:33

Page 81: Universidade VBA

Propriedades 89

5capítulo

• Estado Civil;• Idade.

5. Isso feito, com a ajuda do Botão de comando da Caixa de ferramentas, criamos dois botões. Acessamos as propriedades do primeiro botão e, na linha Name, muda-mos o nome do botão para a cbCancelar. Não se esqueça de escrever Cancelar na linha Caption e, na propriedade Cancel, de solucionar o valor True.

Fazemos o mesmo com o botão da direita, que será nosso botão OK, nomeando-o como cbOK, definindo a linha Caption como OK e dando à propriedade Default o valor True.

6. Definimos, assim, o nosso evento para o botão Cancelar:

Private Sub cbCancelar _ Click() Unload MeEnd Sub

Além do botão OK:

Private Sub cbOK _ Click() Range(“rngNome”).Value = tbNome.Text Range(“RngSobrenome”).Value = tbSobrenome.Text Unload MeEnd Sub

7. Logo após, inserimos Initialize no início do código, para que a aplicação seja aberta juntamente com a planilha. O comando é colocado na linha inicial do código:

Private Sub ufDadosPesoais2 _ Initialize()

8. Montada a estrutura básica, vamos para algo realmente novo: todos os controles possuem a propriedade ControlSource na lista de atributos. ControlSource é utilizado para indicar ao controle qual é a fonte da informação, quer seja uma célula, um intervalo ou mesmo uma planilha inteira. Como exemplo, na caixa de texto Nome, podemos assinalar como ControlSource a célula da planilha em que está inserido esse dado. Como sempre, no entanto, é bastante prudente não utilizar referências absolutas em células e intervalos (por exemplo, Plan1!A5), mas referências nominais.

Podemos, por exemplo, acessar o editor do VBA, selecionar a caixa de texto Nome e, na propriedade ControlSource, escrever o nome do intervalo que será a fonte. Utilizaremos o intervalo da primeira coluna de nossa planilha, rgNome.

cap05.indd 89 1/11/2006 15:48:34

Page 82: Universidade VBA

90 universidade VBA

9. Faça o mesmo com as demais caixas. Por exemplo, clicamos em Sobrenome, acionamos suas propriedades e, em seguida, escrevemos rgSobrenome em sua propriedade ControlSource.

10. Para que a propriedade ControlSource funcione, devemos desabilitar, ao menos temporariamente, o evento Initialize. Isso pode ser feito com um comentário (sinal de ‘) antes de Initialize. A linha deve mudar de cor (verde) para mostrar que está comentada. Logo após, clicamos duas vezes no botão OK e em seguida comentamos, da mesma maneira que fizemos com Initialize, a rotina btnOK_Click().

11. Se testarmos agora a caixa de diálogo, executando o projeto, veremos que a propriedade ControlSource funciona, e que antes de mostrar o diálogo ela lê o conteúdo da folha de cálculo, colocando-o na Userform. Quando apertamos o botão OK, a propriedade ControlSource copia o conteúdo dos controles da Userform na planilha ativa.

12. No entanto, se fizermos alguma alteração na Userform e apertarmos em segui-da o botão Cancelar, as alterações realizadas nos dados são atualizadas na planilha, quando não deveriam ser. Afinal, apertamos o botão Cancelar, portanto, não deseja-mos que a operação se concretize. Se, por sua vez, fizermos alguma alteração e depois apertamos a tecla Esc, as alterações não serão mostradas na planilha. Este parece um dos tantos bugs do VBA. Teremos de conviver com ele até que algum profissional, lista de discussão, ou a própria Microsoft traga resultados satisfatórios para o caso.

13. Agora vamos adicionar, finalmente, uma ComboBox, também chamada, na Caixa de ferramentas do VBA, de Caixa de combinação. Essa é a típica janela que estamos fartos de ver em aplicações do Windows, e que permite ao usuário escolher uma opção entre várias apresentadas. No nosso caso, vamos mostrar uma janela para o dado estado civil. As opções que vamos apresentar são: solteiro, casado, viúvo e divorciado.

14. As propriedades mais importantes de uma ComboBox são:• ListRows: um conjunto de cadeias de caracteres (strings) que representam

todos os elementos da lista. Para ter acesso a um elemento, utilizamos Minha- ComboBox.List( 3 ), que nos devolveria o quarto elemento da lista, pois o pri-meiro equivale ao número zero;

• ListCount: é o número de elementos que há na lista. Se utilizarmos Minha-ComboBox.List(3)(MiComboBox.ListCount-1), obteremos o último elemento da lista;

cap05.indd 90 1/11/2006 15:48:34

Page 83: Universidade VBA

Propriedades 91

5capítulo

• ListIndex: é o número do elemento atualmente selecionado pelo usuário. Para obter o texto do elemento selecionado, utilizaríamos MinhaComboBox.List(MinhaComboBox.ListIndex). Se definirmos o controle como multises-são, o usuário poderá escolher mais de um elemento. Essa propriedade não pode ser utilizada;

• RowSource: local a partir do qual desejamos que a ComboBox leia os elemen-tos. Podemos utilizar essa propriedade, ou introduzir mediante código os elementos (com o método AddItem);

• ControlSource: célula em que a ComboBox lê e escreve o elemento selecio-nado. Funciona de maneira similar a RowSource. Também podemos utilizar esta propriedade para que o ComboBox escreva em uma célula o elemento selecionado, ou podemos utilizar um código para obtermos o elemento selecionado (utilizando ListIndex);

• Stohe: identifica o tipo de ComboBox que desejamos. Apresenta dois valo-res possíveis:

• fmStoheDropDownCombo: o usuário pode escolher um dos valores da lista ou escrever um distinto;• fmStoheDropDownList: o usuário pode escolher apenas um dos valores da lista. • ControleTipText: essa propriedade aplica-se a todos os controles. Serve para mostrar ao usuário um pequeno texto de ajuda sobre o controle quando posicionamos o mouse, no já clássico quadradinho amarelo.

15. Uma vez vistas as propriedades, vamos manipular os métodos do objeto ComboBox:

• AddItem: serve para adicionar um elemento à lista. A sintaxe é:

MeuComboBox.AddItem( ‘Meu texto’, 3 )

O primeiro parâmetro é o texto do elemento, e o segundo (opcional) é a posição dentro da lista que queremos para o novo elemento. Se não utilizarmos o segundo parâmetro, nosso novo elemento será adicionado ao final da lista;

• RemoveItem: serve para apagar um elemento. A sintaxe é:

MinhaComboBox.RemoveItem( 3 )

cap05.indd 91 1/11/2006 15:48:34

Page 84: Universidade VBA

92 universidade VBA

Se quiséssemos, só como exemplo, apagar o elemento número três:• Clear: apaga todos os elementos da lista.

16. Estabeleça a propriedade Stohe como fmStoheDropDownList, para que o usuário possa escolher apenas um dos valores apresentados, ou seja, não vamos deixar que ele invente um novo estado civil.

17. Agora, vá à planilha e escreva em uma célula qualquer Solteiro, na célula de baixo, Casado, na seguinte, Divorciado, e, por último, Viúvo. Isso feito, nomeie esse intervalo, selecionando as quatro células e digitando rgEstadoCivil (na parte superior esquerda).

18. Já que estamos aqui, vamos solucionar outra célula para que a ComboBox armazene o elemento selecionado pelo usuário. Daremos a essa célula o nome rgValorEstadoCivil.

19. Volte ao editor de Visual Basic (VBE), selecionando, em seguida, uma Com-boBox. Na propriedade RowSource, escreva rgEstadoCivil. Na propriedade ControlSource escreva rgValorEstadoCivil.

20. Na propriedade ControleTipText, vamos colocar o texto: Selecione seu estado civil. Esse é o texto que o usuário verá no quadrado amarelo assim que posi-cionar o mouse sobre o ComboBox. Lembre-se de que essa propriedade existe em todos os controles.

21. Já temos nossa ComboBox. Se a testarmos, veremos que funciona perfeita-mente. Lembre-se de que a ComboBox colhe os valores do intervalo estabelecido em RowSource, e armazena o valor selecionado pelo usuário na célula estabelecida em ControlSource.

22. Note que, se apagamos as propriedades ControlSource e RowSource, faremos com que o controle funcione da mesma maneira, mas nós mesmos teremos de nos encarregar de adicionar os valores na lista e, logo depois, identificar a seleção do usuário, além de adicionar seu valor na célula desejada. Para isso, teremos que utilizar as propriedades List e ListIndex, e os métodos Clear e AddItem. Além disso, teremos de fazer retornar ao código os eventos Userform _ Initialize() e btnAceptar _ Click().

Agora que já dominamos o ComboBox, uma boa notícia: o controle ListBox funciona praticamente da mesma maneira. O ComboBox é o controle em que se vê

cap05.indd 92 1/11/2006 15:48:34

Page 85: Universidade VBA

Propriedades 93

5capítulo

apenas uma linha e, após o clique em um botão, surge uma janela com opções dis-tintas. Ao contrário, no controle ListBox temos sempre a lista de opções, não há janela ou menu suspenso. Fora essa diferença visual, os dois tipos de controles são praticamente iguais. Vamos ao exercício seguinte.

Exercício 4

1. Vamos adicionar outro controle, o SpinButton, ou barra de rolagem, (Fi-gura 5.3):

Figura 5.3.

Normalmente, esse botão é utilizado combinado a uma janela de edição. Se clicar-mos em SpinButton posicionando a seta para cima, aumentaremos o valor do quadro de edição, e vice-versa. As propriedades mais importantes do SpinButton são:

• Value: é o valor do SpinButton, que deve ser definido por um número; • Min: valor mínimo que pode ter o SpinButton; • Max: valor máximo que pode ter o comando;• SmallChange: é o incremento ou decréscimo que sofrerá a variável Value

cada vez que o usuário clicar no SpinButton. Normalmente, é definido como um, mas pode ser alterado.

2. Vamos utilizar o controle SpinButton combinado a um quadro de edição para armazenar as informações sobre a idade dos nossos funcionários. Primeiro, colocamos uma caixa de texto, que chamaremos de editIdade.

3. Em uma planilha do Excel, daremos o nome rgIdade a uma célula, e a utiliza-remos para a propriedade ControlSource de nosso controle editIdade.

4. Agora, adicionamos um controle SpinButton. Normalmente, costuma-se colocar o SpinButton à direita do quadro de edição ao qual será associado. No quadro de propriedades, vamos definir o valor Min como 15 (idade mínima) e a Max com o valor 70 (idade máxima). O nome do controle pode ser deixado em sua forma padrão (SpinButton1).

5. Assim, vamos operar um pouco com os eventos. Cada vez que o usuário cli-car no SpinButton, produz-se o evento Change. Toda vez que produzimos esse evento, alteramos o valor da caixa de texto ”editIdade”. Dê um clique duplo em SpinButton e, assim que aparecer a janela de código, escrevemos:

cap05.indd 93 1/11/2006 15:48:34

Page 86: Universidade VBA

94 universidade VBA

Private Sub SpinButton1 _ Change() editIdade.Text = SpinButton1.ValueEnd Sub

6. Se o usuário for diretamente à caixa de texto e inserir a idade, o valor do Spin-Button deve ser atualizado, pois tanto o quadro de edição como o SpinButton têm de ter o mesmo valor. Para tanto, usamos o evento Change do objeto editIdade. Dê um clique duplo sobre ele e, na janela de edição de código, escreva:

Private Sub editIdade _ Change() SpinButton1.Value = editIdade.ValueEnd Sub

7. Aqui, utilizamos a propriedade Value de editIdade no lugar da proprie-dade Text, pois queremos o valor numérico, e não a cadeia de caracteres. Se no controle de edição colocarmos alguma letra no lugar de um número, veremos que a UserForm trava, mostrando-nos uma mensagem de erro, já que não consegue calcular a propriedade Value de editIdade. Em uma aplicação mais comple-xa, poderíamos escrever algum código para evitar esses erros, tópico que ainda não estudamos.

8. Ainda falta esclarecer um pequeno detalhe sobre o SpinButton. Quando a UserForm é carregada pela primeira vez, o controle editIdade reconhece a idade na planilha (afinal, é a função que lhe atribuímos ao editar a propriedade Con-trolSource), porém o controle SpinButton não está atualizado. Temos, então, que dar à SpinButton o mesmo valor que tem o controle editIdade. Para tanto, utilizaremos o evento Initialize da UserForm, que já conhecemos de sobra:

Private Sub UserForm _ Initialize() SpinButton1.Value = editIdade.ValueEnd Sub

O código é o mesmo que foi utilizado no evento editIdade _ Change(). Se testarmos a caixa de diálogo, veremos que a combinação de editIdade com Spin-Button1 funciona perfeitamente (salvo a detecção de erros, que veremos adiante).

A seguir, vamos utilizar outros tipos de controle: as caixas de seleção (Check-Box), e os botões de opção (OptionButtons). Para adicioná-los, vamos supor que o usuário deve nos indicar se utiliza ou não uma planilha de cálculo e, em caso positivo, qual delas.

cap05.indd 94 1/11/2006 15:48:35

Page 87: Universidade VBA

Propriedades 95

5capítulo

Exercício 5

1. É preciso criar, antes de tudo, uma planilha com os nomes de programas de planilha eletrônica. Utilizaremos em nosso exemplo a coluna C. Selecionamos o in-tervalo em seguida (como já fizemos nos exercícios anteriores) e lhe damos o nome rngUtilizarPlanilha.

2. A primeira coisa a perguntar é se o usuário utiliza uma planilha. Para tanto, faremos uso de uma caixa de seleção, que pode ter valores verdadeiros ou falsos. Como sempre, colocamos o controle sobre a UserForm. Em seguida, damos-lhe o nome cboxUtilizaPlanilha.

3. Na propriedade ControlSource, escreva ”rngUtilizarPlanilha”, que é o nome que demos ao intervalo da planilha. Na propriedade Caption, escrevemos o texto do controle, algo como: Utiliza planilha. Também podemos escrever algo na propriedade ControleTipText.

4. Além de todas essas propriedades já conhecidas, as propriedades importantes de um CheckBox são:

• Value: é o valor do controle. Pode ser True ou False;• Triplestate: pode ser True ou False, sendo que este último é o valor default.

Se dermos o primeiro valor ao controle, este passará a ter três estados: verdadeiro (quando está selecionado), falso (quando não está selecionado) e nada (quando ficar cinzento). Em algumas ocasiões, pode ser útil, mas normalmente o deixaremos como False.

5. Agora, vamos ver qual é o programa de planilha eletrônica preferido pelo usuá-rio. Para tanto, utilize alguns botões de opção, para oferecer a chance de escolhermos entre Excel, Lotus 1-2-3, ou qualquer outro programa de planilhas.

A primeira coisa que temos de fazer é inserir um controle Quadro (Frame, em inglês). Esse controle só serve para agrupar controles e para melhorar a apre-sentação da UserForm. Também tem propriedades e eventos, mas quase nunca são utilizados.

6. Coloque um controle Frame na UserForm, e insira dentro deste os três botões de opção. Para inserir um controle dentro de um Frame temos de selecionar o quadro e, sem retirar a seleção, inserir um novo controle.

7. Para guardar os valores dos botões de opção, vamos nomear as três células de nossa planilha (podemos, por exemplo, utilizar as células E16, E17 e E18), que nomearemos como rngExcel, rngLotus e rngOutros.

cap05.indd 95 1/11/2006 15:48:35

Page 88: Universidade VBA

96 universidade VBA

8. Isso feito, voltamos aos três botões de opção inseridos na UserForm e, na propriedade ControlSource de cada um deles, escrevemos um dos nomes que acabamos de criar. Também convém alterar a propriedade Caption de cada um dos botões para mostrar o texto adequado.

As propriedades Value e Triplestate de um botão de opção funcionam de maneira semelhante às do controle de seleção.

9. Se testarmos a UserForm, esta funcionará perfeitamente, exceto por um detalhe. Se o usuário informa que não utiliza nenhuma folha de cálculo, os botões de opção continuam perguntando qual é o programa de planilha preferido, o que, evidentemente, não tem nenhum sentido. O que temos de fazer é desativar os botões de opção.

10. Para desativar qualquer controle (não só os botões de opção), utilizamos a propriedade Enabled. Se essa propriedade for True, significa que o controle está ativado, se for False, que está desativado (aparece na cor cinzenta), e o usuário não pode utilizá-lo.

11. O que nos resta agora é saber quando foi alterado o estado (verdadeiro, falso) da caixa de seleção cboxUtilizaPlanilha. Como sempre, podemos fazê-lo com a ajuda de um evento, o evento Change do controle de verificação, executado toda vez que alteramos o estado do controle. Portanto, no evento Change temos que mudar o estado (ativado, desativado) dos botões de opção. O código é:

Private Sub cboxUtilizaPlanilha _ Change() Frame2.Enabled = cboxUtilizaPlanilha.Value OptionButton1.Enablhed = cboxUtilizaPlanilha.Value OptionButton2.Enablhed = cboxUtilizaPlanilha.Value OptionButton3.Enablhed = cboxUtilizaPlanilha.ValueEnd Sub

Observe que damos à propriedade Enabled dos botões de opção e ao Frame o valor da propriedade Value do controle de verificação. Também podemos utilizar o código:

If cboxUtilizaPlanilha.Value = True Then OptionButton1.Enablhed = True ..... Ose

cap05.indd 96 1/11/2006 15:48:35

Page 89: Universidade VBA

Propriedades 97

5capítulo

OptionButton1.Enablhed = False ..... End If

Pois o resultado é o mesmo.

É importante salientar um detalhe importante: quando a UserForm é iniciada, também deveríamos ativar/desativar os botões de acordo com o valor da caixa de seleção. Uma solução rápida para o problema seria escrever dentro do evento Userform _ Initialize o mesmo código que há em cboxUtilizaPlani-lha _ Change. Esse artifício, porém, não é adequado, já que escreveríamos o mesmo código em dois lugares distintos, coisa que temos de evitar pois, se tivermos de efetuar alguma alteração no código, teremos de fazê-lo em mais de um lugar.

O melhor é utilizar a cboxUtilizaPlanilha_Change() a partir do evento Userform_Initialize(). A rotina cboxUtilizaPlanilha_Change é chama-da sempre que se produz o evento Change, mas nada nos impede de habilitá-la por nossa conta a qualquer momento, como, por exemplo, quando iniciamos a UserForm. O evento Userform_Initialize, em uma configuração como essa, ficaria assim:

Private Sub UserForm _ Initialize() cboxUtilizaHoja _ Change SpinButton1.Value = editIdade.ValueEnd Sub

Enfim, aprendemos a utilizar todos os comandos. Como novo exercício, vamos fazer outra UserForm, na qual não vamos utilizar nenhum novo comando, mas sim um evento novo: KeeUp.

Para tanto, faremos um aplicativo em que o usuário poderá inserir uma cifra em dólares para, automaticamente, obter a conversão em euro. Assim como, ao contrário, se inserirmos um valor em euro, teremos o valor em dólares:

Exercício 6

1. Primeiro, criamos uma UserForm e, nela, colocamos duas caixas de texto, que chamaremos de editDoares e editEuros, duas etiquetas ao lado de cada caixa de texto, e um botão para fechar o aplicativo.

2. Vamos primeiro ao mais fácil. No botão de fechamento do aplicativo (que chamaremos de btnFechar) temos que inserir o código para fechar a UserForm:

cap05.indd 97 1/11/2006 15:48:35

Page 90: Universidade VBA

98 universidade VBA

Private Sub btnFechar _ Click() Unload MeEnd Sub

3. Enfim, vamos às caixas de texto. Sempre que o usuário escrever R$ 2.500,00, a caixa de texto correspondente aos euros será atualizada automaticamente, sem esperar que a entrada dos dados termine. Para tanto, vamos utilizar o evento KeeUp, realizado toda vez que o usuário apertar uma tecla.

4. Para escrever o código desse evento, vamos à janela de código de nossa User-Form para selecionar o controle editDolares e, na parte direita, o evento KeeUp. Colocamos no meio do “esqueleto” do código a declaração do objeto:

Private Sub editDolares _ KeeUp(BeVal KeeCode As MSForms.ReturnInteger, BeVal Shift As Integer)

If editDolares.Text <> “” Then′ Se a célula apresenta conteúdo em dólares, a função “não

está vazio” é representada por <> “” então (Then) editEuros.Text = Format(editDólares.Value / 3, “0.00”)′ O conteúdo da caixa de texto Euros deve apresentar o

valor correspondente à caixa de texto Dólares dividido por três. “0,00” mostra que o resultado da operação deve ser feito no formato decimal

Ose editEuros.Text = “” End IfEnd Sub

O If foi utilizado como uma forma de detecção de erros, pois se a caixa de texto estiver vazia, podem ocorrer muitos erros, sobretudo se o usuário digitar uma letra no lugar de um número. O resto é bastante simples. Trata-se de colocar a caixa edi-tEuros ou o resultado de editDolares divididos por três (o valor em dólares de um euro), e utilizar a função Format para que apresentem apenas os decimais.

Podemos testar o aplicativo e veremos que cada vez que introduzirmos um carac-tere na caixa de texto editDolares será atualizada a caixa de texto editEuros.

5. Agora temos que fazer o contrário: toda a vez em que escrevemos algo em editEuros o programa deve atualizar a caixa editDolares. O procedimento é exa-tamente o mesmo:

cap05.indd 98 1/11/2006 15:48:35

Page 91: Universidade VBA

Propriedades 99

5capítulo

Private Sub editEuros _ KeeUp(BeVal KeeCode As MSForms.Re-turnInteger, BeVal Shift As Integer)

If editEuros.Text <> “” Then′ Se a célula apresentar um valor em euros (portanto, não

está vazia), a função “não está vazio” é representada por <> “” então

editDolares.Text = Format(editEuros.Value * 3, “0.00”)′ O conteúdo da caixa de texto Dólares deve apresentar

o valor correspondente à caixa de texto Euros multiplicado por três. “0,00” mostra que o resultado da operação deve ser feito no formato decimal.

Ose editDolares.Text = “” End IfEnd Sub

Até o momento, todos os botões utilizados em nossas UserForms servem apenas para fechar o recurso, com a diferença de que um foi chamado de Cancelar e outro de OK. No próximo exercício, aproveitando nosso recém-construído conversor de euros, vamos criar dois botões, cada um ao lado de uma caixa de edição, capazes de capturar da célula ativa da planilha o conteúdo da caixa de texto a ele associada.

Exercício 7

1. Colocamos os dois botões, um ao lado de cada caixa de texto, e nomeamos como btnCapturarReal e btnCapturarEuros. Nos valores Caption, inserimos algo como Pegar. Vamos ao código:

Private Sub btnCapturarReal _ Click() ActiveCol.Value = editDólares.ValueEnd Sub

Private Sub btnCapturarEuros _ Click() ActiveCol.Value = editEuros.ValueEnd Sub

O evento utilizado é o Click, que já conhecemos de sobra. O código também não é difícil: simplesmente colocamos em ActiveCol o valor das caixas de texto editDolares e editEuros.

cap05.indd 99 1/11/2006 15:48:35

Page 92: Universidade VBA

100 universidade VBA

2. Observe que, ao apertar esses botões, capturamos o conteúdo da planilha, mas não fechamos a UserForm. Se quiséssemos que a UserForm fosse fechada depois de fazer a captura, teríamos de acrescentar o clássico Unload Me em cada uma das rotinas anteriores.

É possível melhorar muito essa aplicação, fazendo com que, por exemplo, seja possível modificar o range de busca da opção, ou que sejamos capazes não só de dividir, mas também de somar, subtrair ou multiplicar mediante um botão de opção. E é exatamente isso o que faremos no próximo exercício.

Exercício 8

1. Nesse aplicativo, vamos utilizar um controle novo, o RefEdit. Esse controle serve para que o usuário possa introduzir uma referência (um range ou intervalo). Ele poderá fazê-lo caso escreva uma referência absoluta ou um nome de intervalo (como uma caixa de texto), o que aparece à direita, que fará com que a UserForm desapareça e o usuário possa selecionar o intervalo desejado com o mouse ou o teclado.

Os controles que vamos utilizar nessa UserForm são exibidos na tabela seguinte. Não mostraremos com detalhes como montar cada um deles, pois tais comandos já foram apresentados à exaustão nos decorrer deste livro. Basta seguir os dados da tabela para conseguir alterar as propriedades Name e Caption:

Tipo de controle

RefEdittextosFrameOptionButtonOptionButtonOptionButtonOptionButtonCommandButtonCommandButton

Name

RefEdit1tbValorFrame1obSomarobSubtrairobMultiplicarobDividirbtnOKbtnCancelar

Caption

N/AN/AOperaçãoSomar SubtrairMultiplicarDividir OKCancelar

Tabela 5.1.

3. O intervalo que o usuário introduziu em RefEdit deve ser guardado na propriedade Text. No entanto, Text é uma cadeia (string) de caracteres, razão pela qual, se quisermos fazer referência a um intervalo determinado, é preciso usar Range(RefEdit1.Text). Observe o código:

Private Sub UserForm _ Initialize() obSumar.Value = True

cap05.indd 100 1/11/2006 15:48:36

Page 93: Universidade VBA

Propriedades 101

5capítulo

RefEdit1.Text = Sohection.AddrésEnd Sub

Primeiro, fazemos com que a operação selecionada por default seja soma, de-finindo-a como True. Na verdade, podemos definir qualquer valor como padrão. Depois, fazemos com que em RefEdit apareça como intervalo a seleção feita pelo usuário antes de habilitar a caixa de diálogo.

4. Enfim, os botões, que podem ser inseridos na tela de edição do código:

Private Sub btnOK _ Click() RealizarOperação Unload MeEnd Sub

e

Private Sub btnCancelar _ Click() Unload MeEnd Sub

A única diferença entre os dois botões é que um deles ativa a rotina Realizar-Operação antes de fechar a UserForm.

5. Vamos montar a rotina RealizarOperação. Obedeça ao código seguinte:

Sub RealizarOperação () Dim r As Range Dim c As Object Dim i As Doublhe Set r = Range(RefEdit1.Text) i = tbValor.Value For Each c In r.Cols If obSomar.Value = True Then c.Value = c.Value + i OseIf obSubtrair.Value = True Then c.Value = c.Value - i OseIf obMultiplicar.Value = True Then c.Value = c.Value * i

cap05.indd 101 1/11/2006 15:48:36

Page 94: Universidade VBA

102 universidade VBA

OseIf obDividir.Value = True Then c.Value = c.Value / i End If Next cEnd Sub

6. Vamos explicar a construção do código. Primeiro, obtemos o intervalo selecio-nado e o armazenamos em r, com o auxílio de Dim.

Set r = Range(RefEdit1.Text) Logo depois, obtemos o valor a ser utilizado, e que o usuário inseriu em tbValor,

e o armazenamos em i.

i = tbValor.Value

Assim, utilizamos For Each - Next, que já conhecemos, para repetir o mesmo código em todo o intervalo. O If extenso que utilizamos é bem mais simples do que parece: simplesmente comprova qual é o botão de opção ativado (Value = True), efetuando a operação associada a esse botão.

cap05.indd 102 1/11/2006 15:48:36

Page 95: Universidade VBA

Capítulo 6 Mais recursos de desenvolvimento

cap06.indd 103 1/11/2006 15:49:17

Page 96: Universidade VBA

104 universidade VBA

Mais recursos de desenvolvimento

O VBA é uma grande caixa de ferramentas: tudo que se possa imaginar para incrementar uma planilha, banco de dados ou documento baseado nos padrões do Microsoft Office pode ser obtido procurando nas diversas funções e propriedades escondidas nas bibliotecas do Visual Basic for Applications. Existe alguma coisa para ser vista além disso?

Existe, sim. Na verdade, os recursos do VBA podem ser esticados quase que indefinidamente, já que ele é uma linguagem aberta, baseada em objetos gráficos (UserForms), muito semelhantes aos objetos que formam o próprio Windows, além de pequenos scripts escritos em código de sintaxe (estrutura) muito simples.

Essa sintaxe, formada por uma infinidade de estruturas, métodos e propriedades, é que dá corpo às soluções e programas criados com o auxílio do VBA: as UserForms são apenas um “esqueleto” para elas.

Pois bem: existe muita coisa escondida no VBA, desde o advento do Office 2000. Isso ocorre por causa das opções de segurança do Microsoft Office, como vimos no Capítulo 2 deste livro: Macros e VBA. O uso dessa configuração abre muitos horizontes e permite que as macros possam ser executadas “de verdade” dentro de uma planilha, sem restrição de acesso – a macro terá acesso total ao conteúdo da planilha, deixando de ter acesso apenas à visualização do conteúdo (opção Somente leitura ou Read Only). Uma macro que fosse um vírus poderia, nesses casos, apagar todos os dados de uma planilha – uma macro bem-intencionada e utilizada para fins profissionais, no entanto, seria capaz de reformular a aparência ou, melhor ainda, a disposição dos dados de uma folha de dados ou de um formulário de banco de dados, com um simples clique de botão.

Outra restrição que deixa de existir é a de usuário: não será necessário ser administrador do sistema para acessar o sistema. A partir daqui qualquer usuário do sistema (ou mesmo de uma rede) será capaz de rodar uma macro ou mesmo de alterá-la com o editor de textos do VBA. É claro que a presença de um bom antivírus na rede ou no computador é recomendável, desde que se deseje dar tal liberdade ao usuário sem passar por maiores problemas.

Além de desabilitar a segurança das macros, também é necessário abrir o acesso interno aos projetos do VBA. Assim como a abertura da segurança permite o acesso dos usuários ao sistema, a realização dessas configurações permite o acesso total aos módulos VBA e aos códigos neles transcritos, como se você desse um upgrade na linguagem original.

Para fazer isso basta clicar no menu Ferramentas > Macro > Segurança e, em Fontes confiáveis, clicar em Confiar em todos os suplementos e modelos instalados, e em Confiar no acesso ao projeto do Visual Basic (Figura 6.1). No Excel 2000 clique

cap06.indd 104 1/11/2006 15:49:17

Page 97: Universidade VBA

Mais recursos de desenvolvimento 105

6capítulo

Figura 6.1.

Figura 6.2.

Feitas as alterações, abra o editor de macros (Alt + F11). Ao clicar com o botão direito do mouse sobre a coluna VBA Project (canto esquerdo da tela) você notará que, além dos objetos Módulo e Formulário, passaremos a visualizar também os objetos Módulo de classe.

Para inserir um módulo como variável, utilize o seguinte código dentro do Mó-dulo de classe:

Dim cm as CodeModuleSet cm = VBE.ActiveCodePane.CodeModule

ou

With VBE.ActiveCodePane.CodeModule ---End With

Lembrando que Dim deve ser utilizado sempre para definir variáveis. Para trazer referências ao módulo de classe recém-criado dentro de um outro módulo, utilize:

em Ferramentas > Macro > Segurança e selecione a opção Confiar em todos os suplementos e modelos instalados (Figura 6.2).

cap06.indd 105 1/11/2006 15:49:17

Page 98: Universidade VBA

106 universidade VBA

Dim VBCodeMod As CodeModuleSet VBCodeMod = ThisWorkbook.VBProject.VBComponents(“Module1”).

CodeModule

No caso anterior, pedimos que o módulo localizado na planilha atualmente ativa seja aberto.

Para inserir um módulo de classe diretamente em uma planilha assim que ela for criada, podemos utilizar a macro seguinte:

Sub AddModule()′Lembre-se de documentar suas macros. Esta macro será

utilizada para adicionar um módulo de classe a uma planilha recém-criada

′Note que, na linha abaixo, definimos um componente do Visual Basic como variável

Dim VBComp As VBComponent‘Definimos agora que o mesmo documento será adicionado a

uma planilha assim que ela for criadaSet VBComp = ThisWorkbook.VBProject.VBComponents.Add(vbext _

ct _ StdModule)VBComp.Name = “NewModule”‘Definimos a seguir que a operação deve ser executada de

forma visível, ou seja, que deve ser possível visualizar o Excel em operação no momento em que o módulo for inserido.

Application.Visible = TrueEnd Sub

Podemos apagar um módulo do sistema ou de uma determinada planilha utili-zando uma implementação semelhante:

Sub DeleteModule()‘Utilizaremos esta macro ou sub-função para apagar as ma-

cros de uma planilha ativa

Dim VBComp As VBComponentSet VBComp = ThisWorkbook.VBProject.VBComponents

(“NewModule”)ThisWorkbook.VBProject.VBComponents.Remove VBComp

End Sub

cap06.indd 106 1/11/2006 15:49:18

Page 99: Universidade VBA

Mais recursos de desenvolvimento 107

6capítulo

Para inserir um novo procedimento, poderíamos utilizar uma sub-função seme-lhante à mostrada a seguir:

Sub AddProcedure()‘ Utilizaremos a macro a seguir para inserir um procedi-

mento na planilha atual, sob a forma de um novo móduloDim VBCodeMod As CodeModuleDim LineNum As Long

Set VBCodeMod = ThisWorkbook.VBProject.VBComponents(“NovoMódulo”).CodeModule

With VBCodeMod LineNum = .CountOfLines + 1 .InsertLines LineNum, _“Sub MeuNovoProcedimento()” & Chr(13) & _“ Msgbox “”Este é um novo elemento para a planilha”” “ &

Chr(13) & _“End Sub”End With

Application.Run “MeuNovoProcedimento”

End Sub

Em uma implementação mais ousada poderíamos, também, apagar todo o código de uma macro utilizando:

Sub DeleteAllCodeInModule()Dim VBCodeMod As CodeModuleDim StartLine As LongDim HowManyLines As Long

Set VBCodeMod = ThisWorkbook.VBProject.VBComponents(“NewModule”).CodeModule

With VBCodeMod StartLine = 1 HowManyLines = .CountOfLines .DeleteLines StartLine, HowManyLinesEnd WithEnd Sub

cap06.indd 107 1/11/2006 15:49:18

Page 100: Universidade VBA

108 universidade VBA

Aplicação dos módulos

A aplicação de métodos de classe abre muito o leque de nossas opções: podemos fazer, por exemplo, com que uma caixa de mensagem exiba data e hora atuais quando surgir. Isso, na prática, equivale a criar uma macro dentro da outra:

Call cm.InsertLines (5, “Sub ShowTime()” & vbCrLf & “MsgBox Now” & vbCrLf & “End Sub”)

Poderíamos também, de agora em diante, criar eventos a partir de um objeto, como no caso seguinte. Aqui, criamos um evento que aproxima o cursor do mouse do botão OK.

Private Sub cmdOK _ MouseMove(ByVal Button As Integer, ByVal Shift As Integer, _

ByVal X As Single, ByVal Y As Single)

End Sub

Para apagar um procedimento de um módulo fazendo o reverso do mostrado a seguir, poderíamos utilizar as macros:

Sub DeleteProcedure()‘Utilizaremos essa sub-função para apagar um procedimento

de uma planilha

Dim VBCodeMod As CodeModuleDim StartLine As LongDim HowManyLines As Long

Set VBCodeMod = ThisWorkbook.VBProject.VBComponents(“NewModule”).CodeModule

With VBCodeMod StartLine = .ProcStartLine(“MyNewProcedure”, vbext _

pk _ Proc) HowManyLines = .ProcCountLines(“MyNewProcedure”, vbext _

pk _ Proc) .DeleteLines StartLine, HowManyLinesEnd With

cap06.indd 108 1/11/2006 15:49:18

Page 101: Universidade VBA

Mais recursos de desenvolvimento 109

6capítulo

Listagem de elementos via linha de código

Muito mais útil para um administrador de sistemas ou programador é ser capaz de listar todos os elementos que estão sendo utilizados em seu projeto, não importa o tipo. Em tempos em que a administração de projetos e o desenho de organogramas de software estão em alta, nada melhor do que fazer com que esses recursos fiquem ao alcance dos dedos.

O VBA permite isso a partir do momento em que as permissões de acesso direto ao código são apagadas, como fizemos no início. Na macro seguinte, por exemplo, fazemos com que seja possível listar todos os módulos existentes no projeto, pouco importando quantas planilhas e formulários os constituam:

Sub ListModules()‘Esta macro lista módulos de todo o projetoDim VBComp As VBComponentDim Msg As String

For Each VBComp In ThisWorkbook.VBProject.VBComponents Msg = Msg & VBComp.Name & “ Type: “ & CompTypeToName(VBComp)

& Chr(13)Next VBCompMsgBox Msg

End Sub

Function CompTypeToName(VBComp As VBComponent) As String‘A função a seguir acessa o objeto DirectX, que permite

a publicação da listagemSelect Case VBComp.Type Case vbext _ ct _ ActiveXDesigner CompTypeToName = “ActiveX Designer” Case vbext _ ct _ ClassModule CompTypeToName = “Class Module” Case vbext _ ct _ Document CompTypeToName = “Document” Case vbext _ ct _ MSForm CompTypeToName = “MS Form” Case vbext _ ct _ StdModule

cap06.indd 109 1/11/2006 15:49:18

Page 102: Universidade VBA

110 universidade VBA

CompTypeToName = “Standard Module” Case ElseEnd Select

End Function

Podemos utilizar uma variável do projeto anterior para listar apenas procedi-mentos:

Sub ListProcedures()‘Lista os procedimentos do projetoDim VBCodeMod As CodeModuleDim StartLine As LongDim Msg As StringDim ProcName As String

Set VBCodeMod = ThisWorkbook.VBProject.VBComponents(“SaveModule”).CodeModule

With VBCodeMod StartLine = .CountOfDeclarationLines + 1 Do Until StartLine >= .CountOfLines Msg = Msg & .ProcOfLine(StartLine, vbext _ pk _ Proc)

& Chr(13) StartLine = StartLine + _ .ProcCountLines(.ProcOfLine(StartLine, _ vbext _ pk _ Proc), vbext _ pk _ Proc) LoopEnd WithMsgBox Msg

End Sub

Manipulação avançada de módulos

A listagem auxilia no momento de descobrir módulos redundantes ou que pareçam deslocados do projeto. Uma planilha repleta de módulos redundantes pode tornar-se demasiado pesada, sobretudo quando é utilizada como base de dados para os usuários de uma rede interna. A macro seguinte ajuda a testar a existência de um módulo ou procedimento listado por meio das implementações da seção anterior:

cap06.indd 110 1/11/2006 15:49:18

Page 103: Universidade VBA

Mais recursos de desenvolvimento 111

6capítulo

Function ModuleExists(ModuleName As String) As BooleanOn Error Resume NextModuleExists = Len( _ThisWorkbook.VBProject.VBComponents(ModuleName).Name) <> 0End Function Function ProcedureExists(ProcedureName As String, _ ModuleName As String) As BooleanOn Error Resume NextIf ModuleExists(ModuleName) = True Then ProcedureExists = ThisWorkbook.VBProject.

VBComponents(ModuleName) _ .CodeModule.ProcStartLine(ProcedureName, vbext _

pk _ Proc) <> 0End IfEnd Function

Intervenção extrema

A partir do sucesso da função é possível realizar a alteração dos módulos, a começar pelos nomes:

ThisWorkbook.VBProject.VBComponents(“Module1”).Name = “New-Module”

ou

ThisWorkbook.VBProject.VBComponents(“ThisWorkbook”).Name = “MyWorkbook”

Em uma intervenção mais extrema podemos utilizar as listagens para referenciar módulos de dois projetos diferentes, comparando-os entre si. Uma comparação desse tipo é útil para descobrir de que maneira os elementos de dois ou mais projetos pos-suem correspondência entre si, e que módulos podemos importar ou exportar de um módulo para outro para incrementar referências, como é feito na função a seguir:

Sub ExportAllVBA()‘Esta função exporta todos os módulos de um projeto VBA

para outros projetos existentes

cap06.indd 111 1/11/2006 15:49:18

Page 104: Universidade VBA

112 universidade VBA

Dim VBComp As VBIDE.VBComponentDim Sfx As String

For Each VBComp In ActiveWorkbook.VBProject.VBComponents‘Se a planilha atualmente ativa possuir um projeto do VBA

e componentes VBA Select Case VBComp.Type Case vbext _ ct _ ClassModule, vbext _ ct _ Document Sfx = “.cls” Case vbext _ ct _ MSForm Sfx = “.frm” Case vbext _ ct _ StdModule Sfx = “.bas” Case Else Sfx = “”‘ então cada um dos elementos anteriores – módulos de classe

(cls), forms (frm), módulos padrão (bas) serão copiados End Select

If Sfx <> “” Then‘e enviados para a planilha ativa no momento, além da pla-

nilha original VBComp.Export _ Filename:=ActiveWorkbook.Path & “\” & VBComp.

Name & Sfx End IfNext VBCompEnd Sub

A exportação pode ser feita de maneira mais fácil – uma simples cópia – utilizando a macro a seguir:

Sub CopyOneModule()

Dim FName As StringWith Workbooks(“Book2”)‘ Note que, utilizando essa forma de cópia, podemos co-

piar os módulos para um arquivo de texto e outros tipos de blocos de informação, e não somente para planilhas, como no caso anterior

cap06.indd 112 1/11/2006 15:49:19

Page 105: Universidade VBA

Mais recursos de desenvolvimento 113

6capítulo

FName = .Path & “\code.txt” .VBProject.VBComponents(“Module1”).Export FNameEnd With‘O envio da informação para blocos de texto não impede que

os mesmos componentes sejam enviados para uma planilha, como no exemplo seguinte, em que reenviamos os elementos copiados para a planilha book1

Workbooks(“book1”).VBProject.VBComponents.Import FNameEnd Sub

Alertas

O VBA (Visual Basic for Applications), a linguagem de criação de macros e scripts padrão do Microsoft Office, foi criado para adicionar funcionalidades e automatizar tarefas dentro de documentos do Office. Com o VBA é possível, por exemplo, formatar automaticamente um documento do Word, criar células perso-nalizadas em uma planilha do Excel, ou incrementar formulários de um banco de dados do Access.

Uma das ferramentas mais interessantes em relação ao Excel é a que permite a criação de planilhas e células que emitem determinados tipos de alertas ou mensa-gens de notificação. Esse tipo de recurso permite que uma planilha, por exemplo, avise ao usuário quando o horário de trabalho está terminando, ou que o usuário seja alertado quando o conteúdo de uma célula ultrapassar uma determinada soma ou montante.

Como fazer

A primeira coisa a fazer para montar o alarme é criar um timer para sua aplicação. Timer é uma função do VBA que permite a realização de uma tarefa com base em uma determinada contagem de tempo.

No exemplo seguinte demonstramos como usar a função de timer para fazer a chamada de um procedimento depois da passagem de um determinado intervalo de tempo. Para realizar o exemplo utilize o Editor do VBA via Excel.

1. Abra o Microsoft Excel e selecione a planilha em que deseja aplicar a macro. Em seguida clique no menu Ferramentas > Macro > Editor do Visual Basic. Você também pode utilizar a combinação de teclas Alt + F11 – opção muito mais rápida – para abrir o Editor.

cap06.indd 113 1/11/2006 15:49:19

Page 106: Universidade VBA

114 universidade VBA

Figura 6.3.

2. Será aberta uma janela do Microsoft Visual Basic. Existem, acopladas a ela, duas janelas à esquerda. À janela superior chamamos de Projeto – VBAProject, e à janela inferior damos o nome de Propriedades. Na primeira janela estão os elementos que fazem parte do projeto – projeto, aqui e a partir de agora, será entendido como o grupo de macros e planilhas do Excel utilizado para uma determinada funciona-lidade. Na segunda janela são listadas as propriedades dos objetos que porventura podem ser incorporados às nossas macros.

3. Clique no menu Inserir > Módulo. Observe que na janela superior à esquerda (Projeto – VBA Project) surge um novo diretório, chamado Módulo1. É dentro desse módulo que serão armazenadas as macros que vamor criar, a partir de agora, para esse projeto.

4. Note que também será aberta, na janela central, uma janela em branco, de-nominada Pasta1 – Módulo (ou o nome da planilha que está sendo utilizada para criar ou módulo). Essa janela é a interface de inserção dos comandos, onde vamos inscrever os códigos que farão parte da nossa macro.

5. Digite o código a seguir na tela. Os comentários (‘) servem para orientar você.

cap06.indd 114 1/11/2006 15:49:19

Page 107: Universidade VBA

Mais recursos de desenvolvimento 115

6capítulo

‘ Neste exemplo utilizaremos um timer de cinco segundos para chamar a função. A função que utilizaremos será Application.OnTime alertTime. O método OnTime é utilizado para fazer com que o procedimento possa ser executado em um momento espe-cificado no futuro (seja em uma determinada hora do dia ou após uma quantidade específica de tempo decorrido).

‘ Inicie um sub-procedimento sempre com Sub, acompanhado do nome que se quer dar ao procedimento.

Sub timerMsg()‘ Dim é utilizado para declarar variáveis e espaços de

armazenamento. No nosso caso, alertTime – o nosso alerta que surgirá na tela – é uma variável porque ele pode ou não aparecer dentro de um programa maior. É bom se acostumar a formatar alertas e mensagens de texto como variáveis.

Dim alertTime

‘ MsgBox é a função utilizada para exibir uma mensagem em uma caixa de diálogo – ou seja, ela cria um objeto predefini-do (caixa de mensagem) que pode ser visto na tela. Uma caixa de mensagem, normalmente, aguarda que o usuário clique em um botão e retorna um Integer que indica qual botão o usuário clicou. No nosso caso, todavia, a caixa permanecerá apenas com o botão de OK, já que ela será utilizada apenas como veículo do alert. A etiqueta (conteúdo) da caixa deve ser declarada entre parênteses (“”).

MsgBox “O alarme será tocado em cinco segundos!”

‘ Agora definimos que a variável alertTime é formada pelo momento atual (Now) mais o valor de cinco segundos. TimeValue costuma ser utilizado para imprimir um determinado horário na tela. Acompanhado do sinal positivo (+), no entanto, pode-mos utilizá-lo para setar um intervalo para uma determinada tarefa – no caso a sub-tarefa msg, que ensinaremos a montar logo adiante. Note que o formato utilizado corresponde ao de um relógio padrão (Horas:minutos:segundos). Se quisermos, portanto, setar a mensagem de alerta para uma hora e meia, utilizaremos o valor (01:30:00).

alertTime = Now + TimeValue(“00:00:05”)

cap06.indd 115 1/11/2006 15:49:19

Page 108: Universidade VBA

116 universidade VBA

Application.OnTime alertTime, “msg”‘ Utilize sempre End Sub para terminar uma sub-função.End Sub

‘ Agora criaremos a sub-função msg, que corresponde ao ob-jeto (Caixa de mensagens) que deve surgir na tela

Sub msg()MsgBox “Cinco segundos já se passaram! Feche a planilha.”End Sub.

Um segredo a mais

Se você realizou o teste da macro, deve ter notado que o alerta só foi realizado depois que colocamos a função para rodar, utilizando o botão Executar Sub/User Form. E é claro que não adianta nada ter uma macro de alerta de cinco minutos para o fim do expediente e salvamento da planilha se você tem de lembrar de acionar a contagem regressiva.

Esse problema pode ser resolvido com o próprio Application.OnTime, que já vimos anteriormente, criando um timer para início do alerta:

Private Sub Alert _ Open() Application.OnTime TimeValue(“17:55:00”), “timerMsg”End Sub

Sub inventoryDAPs()Dim myAObject As AccessObjectDim dap1 As DataAccessPageDim rst1 As ADODB.RecordsetDim cmd1 As ADODB.Command

‘Open recordset for data access page inventorySet rst1 = New ADODB.Recordsetrst1.Open “dapInventory”, CurrentProject.Connection, _ adOpenKeyset, adLockOptimistic, adCmdTable

‘Empty old inventory before repopulating tableSet cmd1 = New ADODB.CommandWith cmd1

cap06.indd 116 1/11/2006 15:49:19

Page 109: Universidade VBA

Mais recursos de desenvolvimento 117

6capítulo

.ActiveConnection = CurrentProject.Connection .CommandText = “DELETE dapInventory.* From dapInventory” .CommandType = adCmdText .ExecuteEnd With

‘Start loop through pagesFor Each myAObject In _ Application.CurrentProject.AllDataAccessPagesWith rst1‘Start to add a record to the inventory .AddNew rst1.Fields(“dapLinkName”) = myAObject.Name rst1.Fields(“dapFileName”) = myAObject.FullName‘Collect connect string info‘Open (and re-close) any pages that are closed If myAObject.IsLoaded = True Then Set dap1 = _ Application.DataAccessPages(myAObject.Name) rst1.Fields(“dapConnectionString”) = _ dap1.ConnectionString Else DoCmd.Echo False DoCmd.OpenDataAccessPage myAObject.Name Set dap1 = _ Application.DataAccessPages(myAObject.Name) rst1.Fields(“dapConnectionString”) = _ dap1.ConnectionString DoCmd.Close acDataAccessPage, _ myAObject.Name, acSaveNo DoCmd.Echo True End If .Update .MoveNextEnd WithNext myAObject

End Sub

cap06.indd 117 1/11/2006 15:49:20

Page 110: Universidade VBA

118 universidade VBA

Funções matemáticas

Com o código interno do programa à disposição, também podemos trabalhar com ferramentas relacionadas a funções matemáticas chamadas normalmente de manipulações matemáticas “puras”. Algumas dessas manipulações são possíveis em um código de VBA “normal”, mas com uma série de limitações que não ocorrerão nos exemplos aqui mostrados.

Exemplo 1 – Gerador de números aleatórios

Sub rndNo()‘ Nosso objetivo nessa macro é gerar uma fileira de cinco

conjuntos de números aleatórios. Você pode utilizar essa ma-cro para gerar jogos de loteria ou da Mega Sena, ou para a geração aleatória de senhas ou seqüências numéricas.

Dim str As String For i = 1 To 5 str = str & CStr(Rnd) & vbCrLf Next i MsgBox str ‘ As seqüências de números serão retornadas em uma caixa

de mensagem End Sub

Exemplo 2 – Implementação alternativa do gerador de números aleatórios

Sub rndNo() Dim str As String Randomize For i = 1 To 5 str = str & CStr(Rnd) & vbCrLf Next i MsgBox str End Sub

cap06.indd 118 1/11/2006 15:49:20

Page 111: Universidade VBA

Mais recursos de desenvolvimento 119

6capítulo

Exemplo 3 – Desvio de curva

Function Mean(Arr() As Single)‘ Essa macro cria uma Estatística de Desvio de Curva, base-

ada nos valores presentes na planilha atualmente ativa. Esse tipo de estatística é utilizado para definir as probabilida-des reais de um valor frente a um outro valor que lhe serve como comparação

Dim Sum As Single Dim i As Integer

Sum = 0‘ 1 é igual a 100% de probabilidade ou Verdadeiro em Es-

tatística For i = 1 To UBound(Arr) Sum = Sum + Arr(i) Next i Mean = Sum / UBound(Arr)End Function

Function StdDev(Arr() As Single) Dim i As Integer Dim avg As Single, SumSq As Single avg = Mean(Arr) For i = 1 To UBound(Arr) SumSq = SumSq + (Arr(i) - avg) ^ 2 Next i StdDev = Sqr(SumSq / (UBound(Arr) - 1))End Function

Exemplo 4 – Assimetria de distribuição

Sub compute()‘ Essa macro pode ser utilizada para desenvolver códigos

de simetria de distribuição em uma planilha. Isso permite que se automatize a contagem de valores prováveis na divisão

cap06.indd 119 1/11/2006 15:49:20

Page 112: Universidade VBA

120 universidade VBA

de números inteiros, uma função que é aplicada na prática no mercado financeiro, na distribuição de títulos financeiros a um grupo de investidores etc.

Dim Arr(10) As Single Dim Average As Single Dim Std _ Dev As Single

For i = 1 To UBound(Arr) Arr(i) = Sheets(“Sheet1”).Cells(i, 1) Next i

Average = Mean(Arr) Std _ Dev = StdDev(Arr) MsgBox “Total:” & vbTab & Average & vbCrLf & “StdDev

:” & vbTab & Std _ Dev End Sub

Sub compute() Dim arr(10) As Single For i = 1 To 10 arr(i) = Cells(i, 1) Next i MsgBox “Mean:” & vbTab & Format(Mean(arr), “0.0000”) &

vbCrLf & _ “SD:” & vbTab & Format(Var(arr) ^ 0.5, “0.0000”) & vb-

CrLf & _ “Skew:” & vbTab & Format(Skew(arr), “0.0000”) & vbCrLf

& _ “Kurt:” & vbTab & Format(Kurtosis(arr), “0.0000”) End Sub

Function Skew(arr() As Single) Dim i As Long, n As Long Dim avg As Single, sd As Single, SumTo3 As Single n = UBound(arr) avg = Mean(arr)

cap06.indd 120 1/11/2006 15:49:20

Page 113: Universidade VBA

Mais recursos de desenvolvimento 121

6capítulo

sd = (Var(arr)) ^ 0.5 SumTo3 = 0 For i = 1 To n SumTo3 = SumTo3 + ((arr(i) - avg) / sd) ^ 3 Next i Skew = SumTo3 * (n / ((n - 1) * (n - 2))) End Function

Function Kurtosis(arr() As Single) Dim i As Long, n As Long Dim avg As Single, sd As Single, SumTo3 As Single n = UBound(arr) avg = Mean(arr) sd = (Var(arr)) ^ 0.5 SumTo4 = 0 For i = 1 To n SumTo4 = SumTo4 + ((arr(i) - avg) / sd) ^ 4 Next i Kurtosis = SumTo4 * (n * (n + 1) / ((n - 1) * (n - 2)

* (n - 3))) - (3 * (n - 1) ^ 2 / ((n - 2) * (n - 3)))End Function

Function Mean(arr() As Single) Dim Sum As Single Dim i As Long, k As Long k = UBound(arr) Sum = 0 For i = 1 To k Sum = Sum + arr(i) Next i Mean = Sum / k End Function

cap06.indd 121 1/11/2006 15:49:20

Page 114: Universidade VBA

122 universidade VBA

Function Var(arr() As Single) Dim i As Long Dim avg As Single, SumSq As Single k = UBound(arr) avg = Mean(arr) For i = 1 To k SumSq = SumSq + (arr(i) - avg) ^ 2 Next i Var = SumSq / (k - 1) End Function

Exemplo 5 – Percentual e Intervalo Percentual

Sub GetPercentile()‘Percentagem é um modo de expressar uma proporção ou uma

relação a partir de uma fração cujo denominador é 100. Em determinados casos, o valor máximo de uma percentagem é obri-gatoriamente 100%, tal qual ocorre na umidade relativa do ar. Em outros, contudo, o valor pode ultrapassar essa marca, como quando se refere à majoração de um preço. Nesse caso, utili-zamos intervalos percentuais para “arredondar” valores.

Dim arr(10) As Single For i = 1 To 10 arr(i) = Int(Rnd * 50) + 1 Cells(i, 1) = arr(i) Next i

Cells(10, 2) = u _ percentile(arr, 0.4)End Sub

Function u _ percentile(arr() As Single, k As Single) Dim i As Integer, n As Integer n = UBound(arr) Call Sort(arr) x = Application.Max(Application.Min(Int(k * n), n), 1) u _ percentile = arr(x)

cap06.indd 122 1/11/2006 15:49:20

Page 115: Universidade VBA

Mais recursos de desenvolvimento 123

6capítulo

End Function

Sub Sort(ByRef arr() As Single) Dim Temp As Single Dim i As Long Dim j As Long For j = 2 To UBound(arr) Temp = arr(j) For i = j - 1 To 1 Step -1 If (arr(i) <= Temp) Then GoTo 10 arr(i + 1) = arr(i) Next i i = 010 arr(i + 1) = Temp

If j Mod 100 = 0 Then Cells(26, 5) = j End If Next jEnd Sub

Exemplo 6 – Geração de probabilidades com base numérica

Sub GetProb()‘ Assim como ocorre na montagem de curvas, a probabilidade

numérica de um evento geralmente é representada como um nú-mero real entre 0 e 1. Um evento impossível tem uma probabi-lidade de exatamente 0, e um evento dado como certo tem uma probabilidade de 1, mas a recíproca não é sempre verdadeira: eventos de probabilidade 0 não são sempre impossíveis, nem os de probabilidade 1 são sempre certos.

‘ Essa função representa numericamente as probabilidades de ocorrência de um número ou grupo de números dentro de um determinado intervalo.

Dim high As Single, low As Single, profit As Single Dim counter As Integer Dim str As String

cap06.indd 123 1/11/2006 15:49:21

Page 116: Universidade VBA

124 universidade VBA

high = 500000 low = -100000 profit = 300000 srt = “” For j = 1 To 5 counter = 0 For i = 1 To 1000 If profit <= Rnd * (high - low + 1) + low Then counter = counter + 1 End If Next i str = str & counter / 1000 & vbCrLf Next j ‘ A caixa de mensagem retornará uma string com os valores

MsgBox strEnd Sub

Exemplo 7 – Histograma

Sub Hist(M As Long, arr() As Single)‘ Essa função implementa um histograma. O histograma é um

gráfico composto por retângulos justapostos, em que a base de cada um deles corresponde ao intervalo de classe, e a al-tura, à respectiva freqüência. Quando o número de dados au-menta indefinidamente e o intervalo de classe tende a zero, a distribuição de freqüência passa para uma distribuição de densidade de probabilidades.

Dim i As Long, j As Long Dim Length As Single‘ Cada quebra (break) corresponde a uma alteração na fre-

qüência de probabilidades ReDim breaks(M) As Single ReDim freq(M) As Single For i = 1 To M freq(i) = 0

cap06.indd 124 1/11/2006 15:49:21

Page 117: Universidade VBA

Mais recursos de desenvolvimento 125

6capítulo

Next i

Length = (arr(UBound(arr)) - arr(1)) / M For i = 1 To M breaks(i) = arr(1) + Length * i Next i For i = 1 To UBound(arr) If (arr(i) <= breaks(1)) Then freq(1) = freq(1) +

1 If (arr(i) >= breaks(M - 1)) Then freq(M) = freq(M)

+ 1 For j = 2 To M - 1 If (arr(i) > breaks(j - 1) And arr(i) <= breaks(j))

Then freq(j) = freq(j) + 1 Next j Next i ‘ A partir de agora transformaremos os dados capturados

(freqüências e quebras de probabilidade) em valores aritmé-ticos, que serão impressos nas células indicadas

For i = 1 To M Cells(i, 1) = breaks(i) Cells(i, 2) = freq(i) Next iEnd Sub

cap06.indd 125 1/11/2006 15:49:21

Page 118: Universidade VBA

cap06.indd 126 1/11/2006 15:49:21

Page 119: Universidade VBA

Capítulo 7 Projetos e implementações

cap07.indd 127 1/11/2006 15:49:41

Page 120: Universidade VBA

128 universidade VBA

Macros de procura e referência

Neste capítulo, vamos montar tipos mais avançados de macros, com especial atenção às macros de procura e referência. Essas macros nos permitirão movimentar células, colunas e planilhas, ou realizar de ações. É recomendável trabalhar com pastas e planilhas que contenham dados, para que possamos conferir os efeitos da execução da macro.

A primeira macro que criaremos tem por objetivo buscar o último elemento de uma lista de objetos, materiais ou outros elementos quaisquer. Interpretaremos que o final da lista ocorre quando encontramos uma célula vazia. A macro que será a seguinte:

Sub Final()

While ActiveCell.Value <> “”

ActiveCell.Offset(1, 0).Range(“A1”).Select

Wend

End Sub

Observe que, com essa macro, sempre temos a a primeira célula ativad, em bran-co, (While ActiveCell.Value <> “”) depois do final da lista (ActiveCell.Offset(1, 0).Range(“A1”).Select).

Buscando o final de uma lista e inserindo uma última entrada

Esta macro é igual à anterior, com a diferença de que a célula ativada é a última com uma entrada válida da lista (objeto, número etc.):

Sub FinalLista()

While ActiveCell.Value <> “”

ActiveCell.Offset(1, 0).Range(“A1”).Select

Wend

cap07.indd 128 1/11/2006 15:49:41

Page 121: Universidade VBA

Projetos e implementações 129

7capítulo

ActiveCell.Offset(-1, 0).Range(“A1”).Select

End Sub

Note que, nessa macro, efetua-se uma varredura até encontrarmos a célula vazia após o final da lista (ActiveCell.Offset(1, 0).Range(“A1”).Select), mas, logo em seguida, ordenamos à macro que suba uma linha (ActiveCell.Offset(-1, 0).Range(“A1”).Select), encontrando, portanto e por aproximação, a última linha com conteúdo.

Buscar uma entrada na lista e apagar toda a linha da entrada

Imagine que temos uma planilha de dados na qual nos interessa procurar um ele-mento determinado e apagar todos os dados que apareçam na mesma linha. Suponha que a tabela tenha nome, telefone e endereço do conjunto de clientes de uma casa de materiais de construção. A busca será realizada a partir de parâmetros guardados na linha em que estão as informações sobre o endereço de cada cliente.

Para criar uma macro com essas características, abra o editor do Visual Basic e digite:

Sub ApagarLinhas()

While ActiveCell.Value <> “”

If ActiveCell.Value <> “São Paulo” Then

ActiveCell.Offset(1, 0).Range(“A1”).Select

Else

Selection.EntireRow.Delete

End If

Wend

End Sub

cap07.indd 129 1/11/2006 15:49:41

Page 122: Universidade VBA

130 universidade VBA

É importante notar que, ao executar a macro, não é possível recuperar a linha apagada, como acontece se apagarmos uma linha manualmente, a partir do atalho Ctrl + Z.

Buscando o final de uma lista com espaços em branco

Imagine que temos uma lista de dados dentro da qual existem espaços em branco (células e linhas inteiras). Se utilizássemos a primeira macro criada neste capítulo, ela interpretaria tais espaços em branco como o final da lista, e não leria o restante do conteúdo. Então, criaremos uma macro que interpretará como final da lista apenas dois espaços em branco consecutivos. Observe:

Sub FinalListaEspecial()

Sair = “Não”

While Sair = “Não”

While ActiveCell.Value <> “”

ActiveCell.Offset(1, 0).Range(“A1”).Select

Wend

ActiveCell.Offset(1, 0).Range(“A1”).Select

If ActiveCell.Value <> “” Then

Sair = “Não”

Else

Sair = “Sim”

End If

Wend

End Sub

cap07.indd 130 1/11/2006 15:49:41

Page 123: Universidade VBA

Projetos e implementações 131

7capítulo

Elementos repetidos

Nas macros criadas anteriormente, vimos que é possível automatizar funções de busca e movimentação por células e linhas, sendo possível também eliminar registros que não nos interessarem mais.

Agora, criaremos uma macro que, além de procurar e retirar elementos em branco, seja capaz, também, de retirar os elementos repetidos de uma lista. Se o elemento da célula for igual a outro ou se a célula for vazia, obedecendo aos padrões de for-matação, vamos excluí-la e subir uma posição na lista para, assim, eliminar todas as áreas em branco da lista.

Algumas macros, como as funções, devem obedecer a alguns pré-requisitos. No caso dessa macro específica a lista deve estar ordenada para que a macro funcione corretamente. O código para criação da macro é o seguinte:

Sub EliminarRepetidos()

contador = 0

valor = ActiveCell.Value

ActiveCell.Offset(1, 0).Range(“A1”).Select

While ActiveCell.Value <> “”

If ActiveCell.Value = valor Then

Selection.Delete Shift:=xlUp

contador = contador + 1

Else

valor = ActiveCell.Value

ActiveCell.Offset(1, 0).Range(“A1”).Select

End If

Wend

cap07.indd 131 1/11/2006 15:49:42

Page 124: Universidade VBA

132 universidade VBA

Resposta = MsgBox(“Foram encontrados “ & contador & “ elementos repetidos”, 1, “Número de repetidos”)

End Sub

Nessa macro, empregamos uma variável chamada contador, que nos será útil para contabilizar o número de elementos repetidos encontrados na lista. O valor do contador é inicialmente zero, e aumenta em uma unidade sempre que células duplicadas são encontradas.

Eliminando elementos repetidos

Eliminar elementos repetidos em uma lista e fazer um registro. Na macro anterior, eliminamos todos os elementos repetidos de uma lista, para que restasse apenas um dos elementos.

No entanto, poderíamos criar elementos que nos permitissem contabilizar quantas vezes um determinado elemento repetido é encontrado, controlando o que foi digitado inicialmente na tabela, bem como do que foi apagado pela macro anterior.

O script da macro será o seguinte:

Sub EliminarRepetidoseRegistro()

contador = 1

valor = ActiveCell.Value

ActiveCell.Offset(1, 0).Range(“A1”).Select

While ActiveCell.Value <> “”

If ActiveCell.Value = valor Then

ActiveSheet.Next.Select

If ActiveCell.Value <> valor Then

ActiveCell.Offset(1, 0).Range(“a1”).Select

ActiveCell.Value = valor

cap07.indd 132 1/11/2006 15:49:42

Page 125: Universidade VBA

Projetos e implementações 133

7capítulo

End If

ActiveSheet.Previous.Select

Selection.Delete Shift:=xlUp

contador = contador + 1

Else

If contador <> 1 Then

ActiveSheet.Next.Select

ActiveCell.Offset(0, 1).Range(“a1”).Select

ActiveCell.Value = contador

ActiveCell.Offset(0, -1).Range(“a1”).Select

ActiveSheet.Previous.Select

End If

contador = 1

valor = ActiveCell.Value

ActiveCell.Offset(1, 0).Range(“A1”).Select

End If

Wend

If contador <> 1 Then

ActiveSheet.Next.Select

ActiveCell.Offset(0, 1).Range(“a1”).Select

cap07.indd 133 1/11/2006 15:49:42

Page 126: Universidade VBA

134 universidade VBA

ActiveCell.Value = contador

ActiveCell.Offset(0, -1).Range(“a1”).Select

ActiveSheet.Previous.Select

End If

End Sub

Comparação entre colunas

Depois de procurar e excluir dados em uma determinada lista utilizando as linhas em branco como coordenadas, criaremos uma macro que compare as diferentes colunas, eliminando, por exemplo, da primeira coluna elementos que porventura sejam encontrados também na segunda.

Assim, construiremos uma planilha com as seguintes características: na primeira linha será colocada a nossa lista, que pode ser a mesma utilizada nos demais exemplos deste capítulo. Na segunda coluna, vamos inserir os elementos que serão encontrados e excluídos da primeira.

Criada a tabela, escrevemos a macro, explicando mais tarde cada uma das linhas que a compõe.

ATENÇÃO

Os números presentes no código servem apenas de referência para a expli-cação posterior e não devem ser inseridos no código da macro.

1 Sub Repetidos()

2 Range(“B1”).Select

3 Position = 1

4 While ActiveCell.Value <> “”

5 valorcomparação = ActiveCell.Value

6 Range(“a1”).Select

cap07.indd 134 1/11/2006 15:49:42

Page 127: Universidade VBA

Projetos e implementações 135

7capítulo

7 Sair = “não”

8 While ActiveCell.Value <> “” And Sair = “não”

9 If ActiveCell.Value = valorcomparacão Then

10 resposta = MsgBox(“¿Deseja apagar essa entrada?”, 4, “Encontrado!”)

11 If resposta = vbYes Then

12 Selection.Delete Shift:=xlUp

13 End If

14 Sair = “sim”

15 Else

16 ActiveCell.Offset(1, 0).Range(“A1”).Select

17 End If

18 Wend

19 Position = Position + 1

20 Range(“b1”).Select

21 ActiveCell.Offset(Posição - 1, 0).Range(“a1”).Select

22 Wend

23 End Sub

Escrita a macro, salve-a e confira o funcionamento, linha a linha:• Linha 2: com essa instrução, nos situamos na primeira célula da coluna B para

iniciar a busca dos dados que desejamos apagar;• Linha 3: criamos uma variável chamada Position para controlar a fila em

que nos encontramos na segunda coluna;

cap07.indd 135 1/11/2006 15:49:42

Page 128: Universidade VBA

136 universidade VBA

• Linha 4: aqui, criamos um looping que se repetirá até que não existam mais elementos a a serem buscados;

• Linha 5: criamos uma variável chamada valorcomparação, com a qual trabalharemos para comparar os elementos da primeira coluna com os da segunda. O valor da célula em que nos encontramos na coluna B passa a estar na variável valorcomparação;

• Linha 6: passamos para a coluna A para iniciar o processo de comparação;• Linha 7: criamos uma nova variável chamada Sair, com a qual controlamos

a saída (interrupção) ou não do looping criado na linha 4. Sairemos apenas no momento em que encontrarmos um elemento que esteja na segunda e na primei- ra colunas;

• Linha 8: aqui, começamos um looping que se repetirá até chegarmos ao final da primeira coluna, caso não existam elementos comuns, ou até que se encontre um elemento comum que será indicado na variável Sair;

• Linha 9: nesta linha, perguntaremos se a célula em que nos encontramos (pri-meira coluna) é igual ao valor que temos dentro da variável valorcomparação;

• Linha 10: se encontrarmos coincidência de elementos, faremos a pergunta sobre se realmente é preciso excluir os resultados;

• Linha 11: observamos se a resposta do usuário foi afirmativa;• Linha 12: se o usuário responde afirmativamente, eliminamos a célula com

a coincidência e encurtamos a lista até a linha acima. Dessa forma, não teremos espaços em branco no meio da lista;

• Linha 13: terminamos a estrutura Sim, iniciada na Linha 11;• Linha 14: como foi localizado um elemento coincidente, à variável Sair será

atribuído o valor ”sim”:• Linha 15: aqui, iniciamos o caso em que o valor selecionado na primeira coluna

não é coincidente com o valor inscrito na variável valorcomparação;• Linha 16: se não coincidirem os dados de ambas as colunas, avançaremos uma

posição dentro da primeira;• Linha 17: aqui, terminamos a estrutura If iniciada na Linha 9;• Linha 18: terminamos o looping iniciado na Linha 8;• Linha 19: incrementamos em (+ 1) o valor da variável Position, já que avan-

çamos uma posição dentro da segunda coluna;• Linha 20: passamos à segunda coluna para continuarmos comparandoos ele-

mentos;• Linha 21: avançamos na segunda coluna o número de vezes que nos é indicado

na variável Position, para iniciar novamente a comparação entre os elementos de ambas as colunas;

• Linha 22: terminamos o script principal dessa macro;• Linha 23: terminamos a macro.

cap07.indd 136 1/11/2006 15:49:42

Page 129: Universidade VBA

Projetos e implementações 137

7capítulo

Essa macro é bastante completa, e recomendamos que repita seu estudo quantas vezes forem necessárias, até absorver todos os seus conceitos. Para testar a macro, lembre-se de que basta criar uma lista na primeira coluna de uma planilha e inserir os elementos que deseja apagar na segunda coluna.

Lista de planilhas abertas e com células ativas

Com a macro seguinte, pretendemos capturar informações das planilhas atual-mente ativas, bem como das células ativas em cada planilha. Essa é uma implementa-ção simples e com fins puramente didáticos. Uma aplicação real e capaz de cumprir a função de abertura de índice de documentos abertos e ativos pode ser encontrada no final deste capítulo:

‘ Aplicação para captura de planilhas e células ativasSub SheetNamesDownRows() Dim iSheet As Long‘ A variável Dim é utilizada para alocar informações sobre

a planilha em memória For iSheet = 1 To ActiveWorkbook.WorkSheets.Count‘ Estabelecemos que iSheet será considerado verdadeiro

(expressão lógico-booleana 1) sempre que existir uma plani-lha ativa

ActiveCell.offset(iSheet - 1,0) = “’” & WorkSheets(iSheet).Name

Next iSheetEnd Sub

Em uma aplicação um pouco diferente na mesma planilha, podemos fazer com que os nomes das planilhas ativas em um sistema sejam atribuídos às colunas de uma planilha utilizada como índice. As colunas utilizadas vão de B1 a IV1. O limite é de 255 planilhas listadas (uma planilha Excel tem por padrão 256 colunas), mas descartamos a coluna A:

Sub SheetNamesAcrossTop() Dim iSheet As Long For iSheet = 1 To ActiveWorkbook.WorkSheets.Count Range(“B1”).offset(0,iSheet - 1) = “’” & WorkSheets(iSheet).

Name

cap07.indd 137 1/11/2006 15:49:42

Page 130: Universidade VBA

138 universidade VBA

Next iSheetEnd Sub

Em uma implementação mais útil, podemos montar uma macro capaz de listar (comando Sort) todas as planilhas ativas, seguindo uma determinada ordem. Para tanto, basta abrir uma planilha em branco e inserir o seguinte código:

‘ Esta planilha lista todas as planilhas ativas no sistema e as organiza em ordem crescente, utilizando como critério os nomes e dividindo o resultado por linhas (rows)

Sub SheetNamesSortedDownRows() Application.ScreenUpdating = False Application.Calculation = xlCalculationManual Dim Rng As Range Dim WS As Worksheet Set Rng = Range(“A1”) For Each WS In ActiveWorkbook.Worksheets Rng.Value = “’” & WS.Name Set Rng = Rng(2, 1) Next WS Cells.Sort Key1:=Range(“A1”), Order1:=xlAscending, _ Header:=xlNo, OrderCustom:=1, MatchCase:=False, _ Orientation:=xlTopToBottom Range(“A1”).Select Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True End Sub

Em uma implementação mais simples, podemos criar, a partir de uma planilha vazia, uma macro que funcione como um contador das células preenchidas em todas as planilhas de uma pasta. Além de mais simples – são utilizados apenas objetos da planilha e elementos de formatação – o resultado visual também é mais simples e vistoso.

Sub ContagemTodasasPlanilhasd umaPasta() Dim wkBook As Workbook, wkSheet As Worksheet ‘ 2006-02-01Dim iRow As Long, iSheet As Long: iRow = 1 Worksheets.Add After:=Sheets(Sheets.Count) Set wkSheet = ActiveSheet

cap07.indd 138 1/11/2006 15:49:42

Page 131: Universidade VBA

Projetos e implementações 139

7capítulo

‘Criamos automaticamente uma nova planilha após as pla-nilhas ativas, para nela inserir os dados de contagem das demais planilhas

Columns(“A:B”).NumberFormat = “@” Columns(“C”).NumberFormat = “#,###””S”””‘Aqui formatamos as colunas, atribuindo a cada uma delas

um formato de número Range(“a1:g1”) = Array(“Pasta”, “Planilha”, _ “pos”, “linhas”, “colunas”, “Células”, “Valor em

A1”)‘ Aqui atribuímos rótulos a cada uma das colunas. Defini-

mos primeiro o intervalo utilizado (Range) e estabelecemos que ele corresponde (=) a um Array (rótulo) para cada célula do intervalo.

Rows(“1:1”).Font.Bold = TrueFor Each wkBook In Workbooks iSheet = 0 For Each wkSheet In wkBook.Worksheets iRow = iRow + 1: iSheet = iSheet + 1 Cells(iRow, 1) = wkBook.Name Cells(iRow, 2) = wkSheet.Name Cells(iRow, 3) = iSheet ‘placement ‘Estabelecemos que não se deve contar células espe-

ciais caso elas estejam protegidas. Cells(iRow, 4).Value = wkSheet.UsedRange.Rows.Count Cells(iRow, 5).Value = wkSheet.UsedRange.Columns.Count Cells(iRow, 6) = Cells(iRow, 4) * Cells(iRow, 5) Cells(iRow, 7) = wkSheet.Cells(1, 1).Text On Error GoTo 0 Next wkSheetNext wkBook Cells.EntireColumn.AutoFit If Columns(“G”).ColumnWidth > 45 Then _ Columns(“G”).ColumnWidth = 43‘ Com o objeto, Sort definimos a maneira pela qual os re-

sultados serão listados Cells.Sort Key1:=Range(“A2”), Order1:=xlAscending, _ Key2:=Range(“B2”), Order2:=xlAscending, _ Header:=xlYes, OrderCustom:=1, MatchCase:=False,

_

cap07.indd 139 1/11/2006 15:49:43

Page 132: Universidade VBA

140 universidade VBA

Orientation:=xlTopToBottom Range(“A1”).SelectEnd Sub

O resultado final da aplicação da macro pode ser visto na tabela seguinte:

Pasta

Pasta1

Pasta1

Pasta1

Pasta1

PESSOAL.XLS

Programação planilhas em VBAl.xls

Programação planilhas em VBAl.xls

Programação planilhas em VBAl.xls

Programação planilhas em VBAl.xls

Programação planilhas em VBAl.xls

Programação planilhas em VBAl.xls

Planilha

Plan1

Plan2

Plan3

Plan4

Plan1

Plan1

Plan2

Plan3

Plan4

Plan5

Plan6

Posição

1S

2S

3S

4S

1S

1S

2S

3S

4S

5S

6S

Linhas

9

1

1

12

1

44

1

1

1

1

1

Colunas

7

1

1

7

1

256

1

1

1

3

3

Células

63

1

1

84

1

11264

1

1

1

3

3

Valor em A1

workbook

Pasta

Redes de Computadores

Tabela 7.1.

Vale notar que Sort, sem nenhum parâmetro extra, organiza as informações da primeira coluna em ordem crescente.

Poderíamos tornar esse aplicativo ainda mais interessante, pois, como não utili-zamos uma UserForm para montá-lo, ele também não terá botões. Porém, podemos incluir uma macro no aplicativo, fazendo com que todas as planilhas, salvo a planilha ativa, sejam fechadas após a contabilização de suas propriedades:

Sub FecharPlanilhas () Dim wkbk As Workbook For Each wkbk In Application.Workbooks If wkbk.Name <> ActiveWorkbook.Name Then

cap07.indd 140 1/11/2006 15:49:43

Page 133: Universidade VBA

Projetos e implementações 141

7capítulo

If Windows(wkbk.Name).Visible = True Then ‘MsgBox wkbk.Name & “ “ & Windows(wkbk.Name).Visible wkbk.Close SaveChanges:=False ‘or make it true End If End If NextEnd Sub

Colecionando planilhas

O código seguinte lista planilhas ou folhas de dados ativas, organizando-as em uma única janela. Mais simples do que a implementação anterior, esse código pode ser empregado para criar visualizadores ou gerenciadores de arquivos. Note que Dim continua sendo utilizado para alocar informações na memória e transformá-las em variáveis:

Dim wkBook As WorkbookDim wkSheet As WorksheetDim x As Long, cSht As LongFor Each wkBook In Workbooks x = x + 1: cSht = 0 Cells(1, x) = wkBook.Name For Each wkSheet In wkBook.Worksheets cSht = cSht + 1 Cells(cSht + 1, x) = “’” & wkSheet.Name Next wkSheetNext wkBook

Em uma implementação semelhante, podemos ver os nomes, e também a quanti-dade de planilhas abertas. Para tanto, utilize o objeto wkBook.Worksheets.Count (um contador) no lugar do visualizador de nomes da versão anterior, representado por wkBook.Worksheets:

Dim wkBook As WorkbookDim wkSheet As WorksheetDim x As Long, cSht As LongFor Each wkBook In Workbooks x = x + 1 Cells(1, x) = wkBook.Name

cap07.indd 141 1/11/2006 15:49:43

Page 134: Universidade VBA

142 universidade VBA

For cSht = 1 To wkBook.Worksheets.Count Cells(cSht + 1, x) = “’” & wkBook.Worksheets(cSht).Name Next cShtNext wkBook

Em outra implementação interessante, aproveitando de modo mais prático os dois exemplos apresentados, podemos criar um aplicativo capaz de colecionar os nomes das planilhas abertas, dispondo os nomes capturados verticalmente, a partir da célula abaixo da célula ativa, se esta possuir conteúdo, ou a partir (inclusive) da célula ativa, se ela não tiver conteúdo:

Sub ListarNomesPlanilhas2() Dim iSheet As Long For iSheet = 1 To ActiveWorkbook.WorkSheets.Count ActiveCell.offset(iSheet - 1,0) = “’” & WorkSheets(iSheet).

Name Next iSheetEnd Sub

Macros de formatação

Formatar uma planilha nunca é muito agradável, principalmente quando o tempo é curto: é um trabalho braçal, repetitivo e que traz poucos resultados concretos a um projeto, apesar do aspecto visual ajudar muito.

A primeira macro de formatação que vamos explorar é uma macro de busca que, ao mesmo tempo, consegue alterar aspectos de formatação. Ela fará com que a cor de uma célula com fórmula passe a ser azul, ao mesmo tempo em que apagará todas as formatações de cor nas células que não têm fórmula:

Sub ColorFormulas() Cells.FONT.ColorIndex = xlAutomatic Selection.SpecialCells(xlcelltypeformulas).FONT.Colo-

rIndex = 5 End Sub

Em algumas versões do Excel, as células com fórmulas são um pouco instáveis. Para sermos específicos, as versões posteriores ao Excel 97, utilizadas na maioria dos computadores. A macro anterior pode não funcionar nessas versões, razão pela qual apresentamos uma implementação alternativa:

cap07.indd 142 1/11/2006 15:49:43

Page 135: Universidade VBA

Projetos e implementações 143

7capítulo

Sub ColorFormulas() ‘ Utilize para versões posteriores ao Microsoft Excel 97 Cells.FONT.ColorIndex = xlAutomatic Selection.SpecialCells(xlFormulas).FONT.ColorIndex = 5 End Sub

De maneira semelhante, podemos colorir de azul as células desprotegidas contra edição de usuários:

Sub FormatDesprotegido() For Each Item In Intersect(ActiveSheet.UsedRange, Se-

lection.Cells) If Item.Locked = False Then‘ Se o item selecionado não estiver protegido (locked),

segundo a expressão booleana False, então (Then) Item.Font.colorindex = 32‘ Quando utilizamos o Item.Font.colorindex, pedimos que o

objeto Item.Font procure referências à sua configuração na tabela colorindex

End If NextEnd Sub

Mudanças automáticas de formatação

As duas pequenas macros apresentadas ajudam na formatação geral de uma planilha, mas não fazem nada muito extraordinário no sentido genérico.

Ao contrário do que fizemos até agora, a macro seguinte é capaz de fazer com que sejam executadas mudanças na formatação, utilizando como critério cores internas da fonte e das colunas. No exemplo, faremos com que todas as células com conteúdo em azul claro (41 na tabela de cores do Excel) sejam transformadas em conteúdo com fonte branca e colunas amarelas:

Sub brancoParaazul() Application.ScreenUpdating = False Application.Calculation = xlCalculationManual Dim cell As Range ‘---Range(“A3:N100”).Select

cap07.indd 143 1/11/2006 15:49:44

Page 136: Universidade VBA

144 universidade VBA

For Each cell In Selection If cell.Interior.colorindex = 41 And cell.Column = 4 Then cell.Font.colorindex = 2 ‘2=white, 6=yellow End If Next cell Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = FalseEnd Sub

Podemos fazer mais truques com cores, inserindo, por exemplo, uma formatação condicional em nossas planilhas por meio de macros VBA. A formatação condicional faz alterações na aparência do Excel com base em determinados parâmetros preesta-belecidos. É mais ou mais o que fizemos até agora, com a ressalva de que utilizamos Dim para reservar as variáveis equivalentes a cada caso presente na planilha. Os casos a que nos referimos são os diferentes tipos de formatação que podem ser aplicadas a uma planilha, utilizando como parâmetro os valores apresentados em cada linha, que serão transformados em uma cor:

Sub CordaLinhanaCélula() Application.ScreenUpdating = False Application.Calculation = xlCalculationManual Dim cell As Range For Each cell In Intersect(Selection, ActiveCell.Entire-

Column, _ ActiveSheet.UsedRange) Select Case cell.Value Case Is >= 50 cell.EntireRow.Interior.colorindex = 20‘ Se o valor na linha for maior que 50, seu conteúdo será

pintado de azul claro

Case Is >= 40 cell.EntireRow.Interior.colorindex = 37‘ Se o valor encontrado for menor que 40, a linha será co-

lorida com outra tonalidade de azul Case Is >= 20 cell.EntireRow.Interior.colorindex = 38‘ Se o valor for maior que 20, a linha será pintada com a

cor salmão Case Is >= 0

cap07.indd 144 1/11/2006 15:49:44

Page 137: Universidade VBA

Projetos e implementações 145

7capítulo

cell.EntireRow.Interior.colorindex = 36‘ Se o valor for maior que 0, a cor da linha será amarelo Case Else cell.EntireRow.Interior.colorindex = 44‘ Em outras situações, a cor da linha será amarelo ouro End Select Next cell Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = FalseEnd Sub

Em outro exemplo de macro que utiliza formatação condicional, podemos fazer com que elementos como células, linhas e colunas sejam excluídos com base em uma cor ou outro tipo de formatação. Montaremos, a seguir, uma macro que fará com que todas as linhas em vermelho de uma planilha sejam apagadas:

Sub DeleteLinhasemVermelho() ‘A macro só funcionará com a cor preestabelecida. Para

outros tipos de cores, faça a alteração da identificação da cor no código.

Application.ScreenUpdating = False Application.Calculation = xlCalculationManual Dim rng As Range, ix As Long Set rng = Intersect(Range(“A:A”), ActiveSheet.UsedRange) For ix = rng.Count To 1 Step -1 If rng.Item(ix).Interior.ColorIndex = 3 Then rng.Item(ix).EntireRow.Delete End If Next Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = TrueEnd Sub

Ligação com outros elementos

Os códigos de VBA também podem ser utilizados para interligar planilhas do Excel com dispositivos de hardware, como impressoras, HDs portáteis e escâneres. No exemplo seguinte, vamos montar um sistema de impressão direta. Esse sistema é ideal para a impressão de notas fiscais, sendo que a impressora deve ser iniciada por

cap07.indd 145 1/11/2006 15:49:44

Page 138: Universidade VBA

146 universidade VBA

meio do comando Open, e os dados serão enviados por meio do comando Print. Observe:

Open “Lpt1” For Output As #1

Em que:• Open é um método que pede a abertura de um objeto;• “Lpt1” é o objeto que deve ser aberto. Lpt equivale a uma porta paralela ins-

talada no computador, e 1 nos diz que a impressora está na primeira porta paralela (o default da configuração);

• For Output indica que o objeto aberto por Open deve ser retornado para uma determinada saída.

Com a utilização desse comando, podemos personalizar a forma como as consultas a partir de uma planilha serão impressas. Vejamos:

‘ Muda o passo para 8 LPP, imprimindo caracteres especiais.Open “Lpt1” For Output As #1Print #1, Chr(27) & “0”

‘ Imprime o texto de forma condensada.Open “Lpt1” For Output As #1Print #1, Chr(15)

‘ Salta uma linha para cada linha impressa.Open “Lpt1” For Output As #1Print #1, “”

Comentários

Existem muitas coisas para imprimir em uma planilha do Excel, além dos con-teúdos das células. Podemos, por exemplo, imprimir os comentários presentes nas células de uma planilha. Esses comentários são inseridos por meio da ferramenta Comentário, localizada no menu Inserir do Excel.

Crie ou abra uma planilha que já tenha comentários e, em seguida, utilize o editor do VBA para inserir o código:

‘ Aqui, selecionamos todas as células que têm comentáriosSub SelectComentários()

cap07.indd 146 1/11/2006 15:49:44

Page 139: Universidade VBA

Projetos e implementações 147

7capítulo

Selection.SpecialCells(xlCellTypeComments).Select End Sub

‘Agora, habilitamos a impressão das célulasDim mycomment As Comment, filename As StringDim mySht As WorksheetDim IEpath As String, Netscapepath As Stringfilename = “C:\temp\ccomment.txt”‘ Enviamos os textos de todos os comentários para o arquivo

temporário comment.txtOpen filename For Output As #1Print #1, FormatDateTime(Date, vbLongDate)For Each mySht In Worksheets For Each mycomment In Worksheets(mySht.Name).Comments Print #1, “ “ Print #1, mycomment.Parent.Parent.Name & “!” _ & mycomment.Parent.Address(0, 0) _ & “ comment: “ & Trim(mycomment.Text) If mycomment.Parent.Column > 1 Then _ Print #1, “ cell “ & mycomment.Parent.offset(0, -1). _ Address(0, 0) & “ on left has value: “ _ & mycomment.Parent.offset(0, -1).Value Print #1, “ cell “ & mycomment.Parent.Address(0, 0) & _ “ has value: “ & mycomment.Parent.Value Next mycommentNext myShtClose #1Netscapepath = _ “H:\program files\netscape\Communicator\program\nets-

cape.exe”IEpath = “C:\program files\internet explorer\iexplore.exe”Shell IEpath & “ “ & filename, vbNormalFocus‘Shell Netscapepath & “ “ & filename, vbNormalFocus‘Shell “Notepad “ & filename, vbNormalFocusEnd Sub

Em uma implementação mais ousada em relação à construção do código, mas voltada para objetivos menos práticos, podemos criar uma macro que imprima comentários não em uma impressora, mas sim em uma planilha, atribuindo a cada

cap07.indd 147 1/11/2006 15:49:44

Page 140: Universidade VBA

148 universidade VBA

uma das colunas presentes um comentário. Vale lembrar que, como uma planilha tem apenas 256 colunas, serão “impressos” até 256 comentários:

Sub PrintComentáriosporColuna() Dim cell As Range Dim myrange As Range, myrangeC As Range Dim col As Long Dim RowOS As Long Dim wsSource As Worksheet Dim wsNew As Worksheet If ActiveSheet.Comments.Count = 0 Then MsgBox “Não há comentários na planilha” Exit Sub‘ A sub-rotina anterior estabelece que se (If) o número de

comentários presentes em uma planilha é igual a zero, então (Then) deve ser exibido a caixa de mensagem (MsgBox) avisando que não existem comentários na planilha.

End If Application.ScreenUpdating = False Application.Calculation = xlCalculationManual ‘xl95 uses

xlManual Set wsSource = ActiveSheet Sheets.Add Set wsNew = ActiveSheet wsSource.Activate With wsNew.Columns(“A:C”) .VerticalAlignment = xlTop .WrapText = True End With wsNew.Columns(“B”).ColumnWidth = 15 wsNew.Columns(“C”).ColumnWidth = 60 wsNew.PageSetup.PrintGridlines = True RowOS = 2 wsNew.Cells(1, 3) = “’” & Application.ActiveWorkbook.Full-

Name & “ -- “ & _ Application.ActiveSheet.Name For col = 1 To ActiveSheet.UsedRange.Columns.Count Set myrangeC = Intersect(ActiveSheet.UsedRange,

Columns(col), _

cap07.indd 148 1/11/2006 15:49:44

Page 141: Universidade VBA

Projetos e implementações 149

7capítulo

Cells.SpecialCells(xlCellTypeComments)) If myrangeC Is Nothing Then GoTo nxtCol For Each cell In myrangeC If Trim(cell.Comment.Text) <> “” Then RowOS = RowOS + 1 wsNew.Cells(RowOS, 1) = “’” & cell.Address(0, 0)

& “:” wsNew.Cells(RowOS, 2) = “’” & cell.Text wsNew.Cells(RowOS, 3) = “’” & cell.Comment.Text End If Next cellnxtCol: Next col wsNew.Activate Application.Calculation = xlCalculationAutomatic Application.ScreenUpdating = True End Sub

Mais alguns comentários

Os comentários de células do Excel podem ser um laboratório interessante para macros que trabalham com formatação. Além de ser simples (como já mostramos) capturar o texto dos comentários de uma ou mais planilhas, esses textos podem ser facilmente manipulados ou alterados assim que são enviados para a memória ou para um arquivo de armazenamento.

Para alterar o tipo de fonte presente em um comentário. Podemos utilizar a seguinte macro:

Sub (AlteraçãoComentários) With ActiveCell .Comment.Shape.TextFrame. _ Characters.Font.Size = 14‘Selecionamos o objeto e pedimos na linha seguinte que a

fonte seja alterada para o tamanho (Font.Size) 14. .Comment.Shape.TextFrame. _ Characters.Font.Bold = False ‘or True‘ Estabelecemos que a fonte não está em negrito (False)

inserindo um comentário antes de or. Poderíamos adicionar negrito mantendo apenas True como valor da propriedade.

cap07.indd 149 1/11/2006 15:49:44

Page 142: Universidade VBA

150 universidade VBA

.Comment.Shape.TextFrame. _ Characters.Font.ColorIndex = 3 ‘Red‘Definimos a cor da fonte. End WithEnd Sub

No exemplo seguinte, uma variação da macro anterior, é possível definir o tipo da fonte:

Sub ChgAllCommentsF14() Dim Cell As Range For Each Cell In Cells.SpecialCells(xlCellTypeComments) With Cell.Comment.Shape.TextFrame .Characters.Font.Name = “Terminal”‘ Alteramos o tipo de fonte, seja ele qual for, manipulando

o objeto .Characters.Font.Name e setando-o como Terminal.

.Characters.Font.Size = 14 .AutoSize = True End With Cell.Comment.Shape.TextFrame.AutoSize = True NextEnd Sub

Fórmulas nos comentários

Os comentários podem ser utilizados para registrar mais do que as impressões do usuário ou operador da planilha. Em planilhas financeiras, é comum que o resul-tado de uma fórmula seja colocado na célula, mascarando a fórmula em si. Nesses casos, não seria útil “remover a máscara” da célula (os valores resultantes não seriam vistos), e muito menos ficar sem a informação, afinal, a coerência das fórmulas e a capacidade de visualizá-las é uma parte importante do trabalho com planilhas.

A solução seria fazer com que as fórmulas de uma planilha fossem anexadas como comentários nas células em que elas são utilizadas. Para tanto, desenvolvemos a macro seguinte:

Sub FórmulasnosComentários() Dim cell As Range Selection.ClearComments

cap07.indd 150 1/11/2006 15:49:45

Page 143: Universidade VBA

Projetos e implementações 151

7capítulo

For Each cell In Selection If cell.HasFormula Then‘Se a célula tem uma fórmula, então cell.AddComment cell.Formula‘É adicionado um comentário à célula, com a fórmula nela

inscrita. cell.Comment.Visible = False‘A expressão anterior, com o valor booleano False, nos diz

que o comentário não deve permanecer visível na planilha. cell.Comment.Shape.TextFrame.AutoSize = True‘O mecanismo apresentado é importante. Nele, definimos

que o comentário adequará seu tamanho ao conteúdo da célula, conforme permitido pela expressão booleana True.

End If Next cellEnd Sub

Segurança

Por uma questão de segurança, planilhas manipuladas com freqüência, ou em domínio público, podem ter de esconder informações sobre seus criadores ou man-tenedores. O Excel não tem opções que permitem a retirada de informações do usuário, mas é possível “camuflar” essas informações utilizando aplicações de VBA, como a que vemos a seguir:

Sub RemoveUserNameComentário() Dim cmt As Comment ‘DMcRitchie, misc, 2006-02-01 Dim LUSR As Long Dim USR As String USR = LCase(Application.UserName) & “:” & CHR(10) LUSR = Len(USR) For Each cmt In ActiveSheet.Comments‘Para cada vez que uma planilha contiver comentários If Left(LCase(cmt.Text), LUSR) = USR Then‘ Se (If) existir um nome de usuário no comentário, então

(Then) cmt.Text Mid(cmt.Text, LUSR + 1)‘ O nome do usuário será apagado do texto End If

cap07.indd 151 1/11/2006 15:49:45

Page 144: Universidade VBA

152 universidade VBA

NextEnd Sub

Macro para criação de índice de hiperlinks

A macro que vamos criar será utilizada para fazer um índice remissivo de hyper-links com o conteúdo de todas as planilhas ativas. Muito mais complexa do que todas as macros feitas até o momento, é possível utilizá-la para testar seus conhecimentos com VBA. Observe:

• A utilização de Dim para alocar memória e recursos;• A perfeita divisão das partes da célula, utilizando Sheet (folha de dados da

planilha), SheetName (nome da folha de dados), ActiveCell (célula ativa), Row (linha) e Range (intervalo).

Antes de escrever o código VBA propriamente dito, vamos criar as planilhas que serão utilizadas como referência.

1. Crie uma planilha como a que vemos a seguir:

1234567891011

A

Worksheet$$TOC~HELP~1999-01-311999-04-041999-06-151st 2nd 3rd4hdr rowsAbuseAddinsSheetAddress

B

TipoWorksheetWorksheetWorksheetWorksheetWorksheetWorksheetWorksheetWorksheetWorksheetWorksheet

C

CodeNameSheet94Sheet85Sheet6Sheet7Sheet1Sheet8Sheet9Sheet10Sheet11Sheet12

Tabela 7.2.

Em que:• Coluna A (Worksheet): exibe o nome dado à planilha pelo Windows; • Tipo: define o tipo do arquivo. Todos os arquivos listados são conjuntos de

planilhas (Worksheet);• CodeName: exibe o nome com o qual as planilhas serão conhecidas no códi-

go VBA.

cap07.indd 152 1/11/2006 15:49:45

Page 145: Universidade VBA

Projetos e implementações 153

7capítulo

2. Criada a planilha principal, é preciso gerar cada uma das planilhas listadas na coluna Worksheet da planilha de índice, atribuindo-lhes, obviamente, os nomes indicados. É possível alterar os nomes apresentados na planilha principal por nomes de seu interesse, ou que representem planilhas existentes, já que a referência válida está nos valores da coluna CodeName, e não nos nomes reais da planilha; algo que ajuda muito por não ser necessário reescrever o código no caso de movimentar ou apagar uma planilha.

3. De volta à planilha de índice, devemos criar hiperlinks para cada uma das planilhas listadas. Isso pode ser feito por meio de um clique com o botão direito do mouse em cada uma das células, para habilitar a opção Hiperlink.

Na janela Inserir hiperlink, vá para a coluna à esquerda, chamada de Vincular a, e selecione a opção Página da Web, ou arquivo existente. Na janela à direita, escolha o documento para o qual será criado o link e aperte OK. Repita o processo em todas as planilhas indexadas.

4. Terminado o trabalho com a planilha, podemos criar a nossa macro no editor de VBA. Observe:

Sub BuildTOC() ‘Esta macro tem por objetivo listar todas as planilhas

ativas no momento em nosso sistema, bem como as últimas cé-lulas preenchidas de cada planilha.

Dim iSheet As Integer, iBefore As Integer Dim sSheetName As String, sActiveCell As String Dim cRow As Long, cCol As Long, cSht As Integer Dim lastcell Dim qSht As String Dim mg As String Dim rg As Range Dim CRLF As String Dim Reply As Variant‘Dim é utilizado para alocar espaço em memória para as

variáveis. Nas quatro primeiras linhas do código, porém, o comando é utilizado para armazenar informações capturadas nas planilhas ativas e nas células.

Application.Calculation = xlCalculationManual Application.ScreenUpdating = False cRow = ActiveCell.Row

cap07.indd 153 1/11/2006 15:49:45

Page 146: Universidade VBA

154 universidade VBA

cCol = ActiveCell.Column sSheetName = UCase(ActiveSheet.Name) sActiveCell = UCase(ActiveCell.Value) mg = “” CRLF = Chr(10) ‘Actually just CR Set rg = Range(Cells(cRow, cCol), Cells(cRow - 1 + Acti-

veWorkbook.Sheets.Count, cCol + 7)) rg.Select If sSheetName <> “$$TOC” Then mg = mg & “Sheetname is

not $$TOC” & CRLF If sActiveCell <> “$$TOC” Then mg = mg & “Selected cell

value is not $$TOC” & CRLF‘ É definido que se (If) um link para uma planilha (sShee-

tName) não existir na tabela de índice, mesmo que ela esteja aberta no computador, a mensagem “Sheetname is not $$TOC” deve ser mostrada. A mesma observação é válida para as célu-las ativas nessas planilhas.

If mg <> “” Then mg = “Warning BuildTOC will destructively rewrite the

selected area” _ & CRLF & CRLF & mg & CRLF & “Press OK to proceed, “ _ & “the affected area will be rewritten, or” & CRLF & _‘ Aqui, criamos uma rotina de mensagens de interação com o

usuário. Essa rotina estabelece que se deve avisar o usuário que alterações na planilha de índice podem sobrescrever as próprias planilhas listadas, além de que é preciso apertar OK se desejarmos prosseguir com a operação.

“Press CANCEL to check area then reinvoke this macro (BuildTOC)”

‘ Uma outra mensagem estabelece que o usuário deve apertar o botão Cancel se desejar abortar a operação.

Application.ScreenUpdating = True ‘make range visible Reply = MsgBox(mg, vbOKCancel, “Create TOC for “ &

ActiveWorkbook.Sheets.Count _ & “ items in workbook” & Chr(10) & “revised will now

occupy up to 10 columns”) Application.ScreenUpdating = False If Reply <> 1 Then GoTo AbortCode End If

cap07.indd 154 1/11/2006 15:49:45

Page 147: Universidade VBA

Projetos e implementações 155

7capítulo

rg.Clear ‘Clear out any previous hyperlinks, fonts, etc in the area

For cSht = 1 To ActiveWorkbook.Sheets.Count Cells(cRow - 1 + cSht, cCol) = “’” & Sheets(cSht).Name If TypeName(Sheets(cSht)) = “Worksheet” Then ‘hypName = “’” & Sheets(csht).Name ‘ Os nomes das planilhas serão substituídos pelos

nomes de referência. qSht = Application.Substitute(Sheets(cSht).Name,

“”””, “”””””) If CDbl(Application.Version) < 8.0 Then

ActiveSheet.Cells(cRow - 1 + cSht, cCol).Formula = _ “=hyperlink(“”[“ & ActiveWorkbook.Name _ & “]’” & qSht & “’!A1””,””” & qSht & “””)” End If Else Cells(cRow - 1 + cSht, cCol + 2) = “’” & Sheets(cSht).

Name End If Cells(cRow - 1 + cSht, cCol + 1) = TypeName(Sheets(cSht)) Cells(cRow - 1 + cSht, cCol + 6) = Sheets(cSht).ScrollA-

rea ‘.Address(0, 0) Cells(cRow - 1 + cSht, cCol + 7) = Sheets(cSht).Page-

Setup.PrintArea If TypeName(Sheets(cSht)) <> “Worksheet” Then GoTo

byp7 Set lastcell = Sheets(cSht).Cells.

SpecialCells(xlLastCell) Cells(cRow - 1 + cSht, cCol + 4) = lastcell.Address(0,

0) Cells(cRow - 1 + cSht, cCol + 5) = lastcell.Column *

lastcell.Rowbyp7: ‘xxx On Error GoTo 0 Next cSht

‘A partir daqui, utilizamos a função Sort Key para orga-nizar os resultados obtidos a partir das capturas efetuadas pela tabela de índice.

cap07.indd 155 1/11/2006 15:49:45

Page 148: Universidade VBA

156 universidade VBA

rg.Sort Key1:=rg.Cells(1, 2), Order1:=xlDescending, Key2:=rg.Cells(1, 1) _

‘ Order2:=xlAscending, Header:=xlNo, OrderCustom:=1, MatchCase:=False, _

Orientation:=xlTopToBottom rg.Columns.AutoFit rg.Select ‘optional If cRow > 1 Then If “” = Trim(Cells(cRow - 1, cCol) & Cells(cRow - 1,

cCol + 1) & Cells(cRow - 1, cCol + 2)) Then Cells(cRow - 1, cCol) = “Worksheet” Cells(cRow - 1, cCol + 1) = “Type” Cells(cRow - 1, cCol + 2) = “CodeName” Cells(cRow - 1, cCol + 3) = “[opt.]” Cells(cRow - 1, cCol + 4) = “Lastcell” Cells(cRow - 1, cCol + 5) = “cells” Cells(cRow - 1, cCol + 6) = “ScrollArea” Cells(cRow - 1, cCol + 7) = “PrintArea” End If End If Application.ScreenUpdating = True Reply = MsgBox(“Table of Contents created.” & CRLF & CRLF

& _ “Would you like the tabs in workbook also sorted”, _ vbOKCancel, “Option to Sort “ & ActiveWorkbook.Sheets.

Count _ & “ tabs in workbook”) Application.ScreenUpdating = False If Reply = 1 Then SortALLSheets ‘Invoke macro to Sort

Sheet Tabs Sheets(sSheetName).ActivateAbortCode: Application.ScreenUpdating = True Application.Calculation = xlCalculationAutomaticEnd SubSub BuildTOC _ A3() Cells(3, 1).Select BuildTOCEnd Sub‘ Aqui termina o código.

cap07.indd 156 1/11/2006 15:49:45

Page 149: Universidade VBA

Capítulo 8 Conexão remota e banco de dados

cap08.indd 157 1/11/2006 15:59:04

Page 150: Universidade VBA

158 universidade VBA

Conexão remota e banco de dados

Utilizamos conexão remota para acessar um banco de dados, desktop de um computador ou qualquer outra aplicação que não esteja localizada diante de nós. No VBA e nas aplicações de dados são utilizados os drivers ODBC para interligar os programas a bancos de dados. Os drivers ODBC são fornecidos pela Microsoft e instalados quando você instala o Microsoft Excel e o Microsoft Access.

O ODBC (ou Open Data Base Connectivity) é uma tecnologia padrão de programação para o acesso a banco de dados por meio de uma biblioteca de funções predefinida, criada pelo SQL Access Group. Basicamente, o ODBC oferece uma interface padronizada de funções, uma API, ao programador, suportada por meio de um driver apropriado.

Exemplificaremos a utilização de drivers ODBC mostrando como realizar a insta-lação de drivers compatíveis com o padrão do banco de dados MySQL (www.mysql.com) no Windows. Instalar esse driver serve para que desde um sistema Microsoft Windows possamos ter acesso a uma base de dados MySQL – o mesmo se aplica a bancos de dados Oracle, dBase ou Access.

A instalação dos drivers permite que uma outra aplicação – um programa VBA, no nosso caso, tenha acesso, utilizando um front-end gráfico (Access, por exemplo) à base de dados MySQL, sendo capaz, inclusive, de exportar ou importar dados (migrar os dados de Access para MySQL ou vice-versa).

1. A primeira coisa que temos de fazer é abrir o Access da máquina do Windows que servirá como cliente e atualizar a versão 6 de Microsoft jet: http://support.mi-crosoft.com/default.aspx?scid=KB;EN-US;Q239114&.

2. A seguir, temos de fazer download da última versão de Myodbc da página de MySQL: http://www.mysql.com/downloads/api-myodbc-2.50.html.

3. Com tudo isso feito, instalamos a atualização de Microsoft Jet e instalamos os drivers OBDC de MySQL. Na janela Data Sources clicamos Close para terminar.

4. Com o driver ODBC instalado, vamos até o painel de controle OBDC de 32 bits (Início > Configurações > Painel de Controle > Fontes de dados ODBC 32 bits). Neste momento, teremos de escolher se queremos utilizar o driver para um usuário (DSN de usuário) ou para qualquer usuário do computador (DSN de Sistema). Uma vez escolhida uma opção, clique no botão Add para acrescentar uma nova fonte de dados e, a seguir, selecione o driver de MySQL.

5. Teremos agora de preencher os seguintes campos:

cap08.indd 158 1/11/2006 15:59:05

Page 151: Universidade VBA

Conexão remota e banco de dados 159

8capítulo

• Windows DSN name: nome da fonte de dados que estará disponível desde o Windows;

• Mysql host (name or IP): nome ou endereço IP do computador onde se encontra instalado o servidor MySQL;

• Mysql Database Name: nome da base de dados com a que se trabalhará desde a fonte de dados;

• User: nome de usuário com o qual se acessará o servidor de bases de dados; • Password: palavra-chave do usuário;• Port: serve para especificar a porta na qual se encontra o servidor MySQL.

Devemos colocar um valor diferente do predefinido, que é o 3306.

6. Uma vez que essas opções estejam configuradas, clicamos em OK para fechar as janelas e finalizar o processo.

Trabalho com o VBA e com o Registro

Feito o trabalho de instalação do driver, está na hora de trabalhar com a “outra ponta” do processo: o código do VBA. Qualquer planilha do Excel ou formulário do Access é capaz de se conectar corretamente a um banco de dados, considerando como remota qualquer base de dados que não se encontre na mesma máquina em que o front-end é rodado. Convencionou-se, no entanto, chamar de banco de dados remoto apenas as bases localizadas fora da rede local da empresa ou do usuário, e que possam ser acessadas quer via Internet, quer via acesso dedicado.

Uma implementação de VBA que utilize os drivers ODBC costuma utilizar o Registro do Windows para acesso direto aos drivers. O registro é a espinha dorsal do Windows, o controle do sistema. Do ponto de vista físico, está espalhado por diversos arquivos dos diretórios System e System 32 do Windows XP. Para a visualização e administração de sua estrutura – que é o que nos interessa – o Windows XP utiliza, todavia, uma estrutura de árvore de dados bem parecida, ao menos visualmente, com a apresentada no Windows Explorer.

Como funciona o registro

Ao mesmo tempo em que mostramos a estrutura do registro, é conveniente que você faça um reconhecimento visual. Para isso, vá até o menu Iniciar > Executar e digite o comando regedit. Esse reconhecimento é essencial para que você saiba programar corretamente em VBA utilizando os drivers ODBC.

cap08.indd 159 1/11/2006 15:59:05

Page 152: Universidade VBA

160 universidade VBA

O regedit é o utilitário padrão para manipulação do registro do Windows. Apesar da sua interface simples e voltada para o usuário, no entanto, o regedit não é um brinquedo: as alterações realizadas em sua estrutura, sobretudo em relação à alteração e apagamento de chaves, são capazes de desestabilizar ou fazer com que o sistema operacional simplesmente deixe de funcionar.

A árvore do registro é formada pro cinco “diretórios”, na verdade chamados de chaves, que podem ser vistos à esquerda do diretório do registro. Trata-se da estrutura básica do registro do Windows: cada uma das chaves coordena um dos elementos do sistema operacional. Um elemento de hardware instalado no computador, por exem-plo, deve procurar “seu lugar” no registro, alojando-se na chave correspondente. Essa chave passará a ser responsável por esse hardware, tendo sempre ciência da sua relação com o kernel, das DLLs adicionadas ao sistema, da versão de seus drivers entre outras coisas. O hardware, por sua vez, deverá se reportar sempre ao registro quando alguma alteração for feita em suas relações com o Windows – se isso não ocorrer, o elemento é “barrado” de suas relações com o kernel e os demais arquivos do sistema. Ou seja, se seu nome não constar no registro ele não será nem mesmo reconhecido como um “cliente” do sistema, e não terá acesso nem mesmo aos “manobristas”, quanto mais ao staff do chef kernel.

Uma outra característica das chaves de registro, que perceberemos mais a seguir: as chaves só trocam informações sobre seu funcionamento inteiro (o que elas contêm, que características do sistema controlam) entre si. Isso significa que uma chave de registro não repassa informações para programas externos ao registro quando não são solicitadas.

Vamos dar uma olhada agora em cada uma das chaves presentes no registro, enumerando suas utilidades dentro do sistema.

HKEY _ CLASSES _ ROOT

Essa chave, na verdade, é um atalho para a chave HKEY_LOCAL_MACHINE\SOFT-WARE\Classes, e sua finalidade é manter a compatibilidade com programas antigos, que rodam a 16 bits. Tanto essa chave quanto HKEY_CURRENT_USER são aliases de outras chaves do Registro, em uma tentativa tanto de criar atalhos que facilitem a edição do registro por usuários quanto facilitem a própria comunicação interna do registro. Assim, ao procurar por regras para permitir a abertura de um programa do antigo MS-DOS, por exemplo, o registro cai diretamente nessa chave em vez de ler a subchave contida em HKEY_LOCAL_MACHINE\SOFT-WARE\Classes.

cap08.indd 160 1/11/2006 15:59:05

Page 153: Universidade VBA

Conexão remota e banco de dados 161

8capítulo

HKEY _ CURRENT _ USER

Essa chave é um atalho para a chave HKEY _ USERS\<nome do usuário>, em que <nome do usuário> corresponde à identificação do usuário de sistema que está logado no momento e utilize o sistema. Essas informações dizem respeito ao usuário de uma conta local, e não a um usuário remoto, e incluem configurações relacionadas e informações do usuário atual do sistema, como configurações personalizadas.

Usuários locais são todos os usuários que possuem uma conta configurada no sistema Windows e a acessam localmente, ou seja, digitando seu login e senha em frente à tela do computador onde o sistema está instalado.

Os usuários remotos, por sua vez, são usuários que possuem uma conta local configurada em outra máquina, mas podem utilizar os recursos de uma determinada máquina Windows remotamente, ou seja, sem estar presentes diante do teclado. O Windows XP possui diversas opções que permitem a configuração de acesso remoto, inclusive via rede local (LAN) ou Internet. Vários usuários remotos podem acessar uma máquina ao mesmo tempo e um mesmo usuário remoto pode acessar várias máquinas que lhe permitam acesso ao mesmo tempo.

HKEY _ LOCAL _ MACHINE

Trata-se da chave mais importante do registro, é nela que estão contidas as in-formações sobre programas e hardware. Clicando no sinal positivo (+) ao lado desta chave (Figura 8.1) temos acesso às suas subchaves, que são montadas no formato de uma árvore de dados organizada segundo o tipo de cada dado. Daremos uma atenção especial à chave HARDWARE logo a seguir.

Figura 8.1.

cap08.indd 161 1/11/2006 15:59:05

Page 154: Universidade VBA

162 universidade VBA

Em HARDWARE estão informações relativas ao hardware do computador, como o chipset utilizado pela placa-mãe, endereçamento das portas seriais e paralelas, periféricos (teclado, mouse) anexos ao sistema entre outros. HARDWARE, assim como outras chaves do registro, possui vários níveis de subchaves, uma dentro da outra. Às subchaves dentro de HARDWARE chamaremos, para fins didáticos, de subchaves de segundo nível. As subchaves mais profundas serão tratadas citando seu caminho dentro do registro, ou teríamos de falar de subchaves terciárias, quaternárias e assim por diante.

Outra chave de importância vital para o sistema é a chave SOFTWARE. Nela você consegue encontrar informações sobre todos os programas instalados no Windows, inclusive algumas aplicações auxiliares aos drivers de hardware.

Nessa subchave cada uma das subchaves secundárias tem o nome de um desen-volvedor de software. Além da Microsoft – de longe a empresa com maior número de chaves representadas – temos a Macromedia, a Intel e até o Google.

No registro dos Windows 2000/XP/2003 existem outras subchaves que são intocá-veis. Uma delas é a chave SAM (Security Accounts Manager) que faz o gerenciamento dos logins de usuários remotos e locais do Windows. A subchave SAM é a responsável pela “montagem” do login dos usuários, contendo uma parte da chave de criptografia utilizada para a armazenagem da senha. Ao contrário do que ocorria com o Windows 98/ME, o Windows XP não guarda as senhas em um arquivo comum e legível, mas monta um arquivo temporário que mascara a senha de maneira diferente a cada login, e é representado no registro, justamente, pela chave SAM. Essa subchave é tão protegida que você não pode alterá-la e nem apagá-la.

Projeto de código para interligação ODBC

Veremos a seguir como proceder à ligação de código VBA com diversos tipos de bancos de dados remotos. Genericamente, o código a seguir (que você pode ler seguindo os comentários) pode ser utilizado para interligar qualquer aplicação VBA a qualquer base de dados.

Private Const REG _ SZ = 1‘ Note que a primeira constante, justamente, evoca o editor

de registro, utilizando o valor booleano True (Verdadeiro), numericamente equivalente a 1.

‘ A seguir passa-se a operar de forma direta com as chaves do Registro e seus valores auto-atribuídos.

Private Const HKEY _ LOCAL _ MACHINE = &H80000002

cap08.indd 162 1/11/2006 15:59:06

Page 155: Universidade VBA

Conexão remota e banco de dados 163

8capítulo

Private Const HKEY _ CURRENT _ USER = &H80000001‘ Definimos o local em que está a string que dá acesso às

configurações genéricas de drives ODBC do sistemaPrivate Const REG _ ODBCINI As String = “SOFTWARE\ODBC\ODBC.

INI\”Private Const REG _ ODBCINI _ DS As String = “SOFTWARE\ODBC\

ODBC.INI\ODBC Data Sources”‘ A partir de agora passamos a ter acesso às funções de

criação de chaves do registro e sua configuração.Private Declare Function RegCreateKey Lib “advapi32.dll”

Alias “RegCreateKeyA” (ByVal hKey As Long, ByVal lpSubKey As String, phkResult As Long) As Long

Private Declare Function RegOpenKey Lib “advapi32.dll” Alias “RegOpenKeyA” (ByVal hKey As Long, ByVal lpSubKey As String, phkResult As Long) As Long

Private Declare Function RegSetValueEx Lib “advapi32.dll” Alias “RegSetValueExA” (ByVal hKey As Long, ByVal lpValueNa-me As String, ByVal Reserved As Long, ByVal dwType As Long, lpData As Any, ByVal cbData As Long) As Long

Private Declare Function RegCloseKey Lib “advapi32.dll” (ByVal hKey As Long) As Long

Private Sub Set _ ODBC _ DSN(UserDSN As Boolean, _ DataSourceName As String, DatabaseName As String, _ Description As String, DriverPath As String, _ DriverName As String, Server As String) Dim lResult As Long Dim hKeyHandle As Long Dim HKEY _ XX As Long HKEY _ XX = IIf(UserDSN, HKEY _ CURRENT _ USER, HKEY _ LO-

CAL _ MACHINE) ‘ Criação de uma nova chave na árvore do registro lResult = RegCreateKey(HKEY _ XX, REG _ ODBCINI & Data-

SourceName, hKeyHandle) ‘ Definindo os valores da chave lResult = RegSetValueEx(hKeyHandle, “Database”, 0&,

REG _ SZ, ByVal DatabaseName, Len(DatabaseName)) lResult = RegSetValueEx(hKeyHandle, “Description”, 0&,

REG _ SZ, ByVal Description, Len(Description))

cap08.indd 163 1/11/2006 15:59:06

Page 156: Universidade VBA

164 universidade VBA

lResult = RegSetValueEx(hKeyHandle, “Driver”, 0&, REG _SZ, ByVal DriverPath, Len(DriverPath))

lResult = RegSetValueEx(hKeyHandle, “LastUser”, 0&, REG _ SZ, ByVal “user”, Len(“user”))

lResult = RegSetValueEx(hKeyHandle, “Server”, 0&, REG _SZ, ByVal Server, Len(Server))

‘ Fechando a chave. lResult = RegCloseKey(hKeyHandle) ‘ Ao abrir a chave “ODBC Data Sources” geramos entra-

das equivalentes dentro do diretório de administração dos drivers ODBC.

‘ Agora adicionamos um valor. ‘ E fechamos a chave de novo. lResult = RegCreateKey(HKEY _ XX, REG _ ODBCINI _ DS,

hKeyHandle) lResult = RegSetValueEx(hKeyHandle, DataSourceName, 0&,

REG _ SZ, ByVal DriverName, Len(DriverName)) lResult = RegCloseKey(hKeyHandle)End Sub

SQL Server

O SQL Server é um servidor de banco de dados de propriedade da Microsoft. O SQL trabalha com as tabelas em que são enviadas as listagens de dados, chamadas de consultas, e as tabelas geradas a partir de filtros, chamadas de seleções.

Em relação aos clientes, o SQL se utiliza de strings, como uma linguagem de pro-gramação baseada em scripts, para fazer a garimpagem e retirada de dados enviados pelos clientes. Esses scripts podem ser inseridos no corpo de páginas ASP, JAVA ou PHP sem afetar a utilização da página por parte do usuário.

Antes de começar a trabalhar a interação do VBA com as tabelas QL, vamos mostrar como criar essas mesmas tabelas. Supomos aqui que você já possui um ser-vidor SQL Server (ao menos na versão 2000) instalado em sua máquina.

Vamos, ao mesmo tempo, criar uma tabela que armazene todos os logins feitos em nossa página ASP. Basta acessar a página e abrir uma nova entrada do código no meio do código HTML, como:

<%@ LANGUAGE=”VBSCRIPT” dim StrSql ‘Variável que arquiva o comando de sql a exe-

cutar

cap08.indd 164 1/11/2006 15:59:06

Page 157: Universidade VBA

Conexão remota e banco de dados 165

8capítulo

StrSql =”CREATE TABLE dbo.logins (nome VARCHAR, senha INT NOT NULL)”

# o prefixo dbo mostra que a base de dados a ser utilizada é SQL Server

set conn=server.createobject(“adodb.connection”) #este comando cria um objeto – no caso a tabela que já foi

declarada acima – no servidorconn.open “DsnName”,”userName”,”Password” set rs = conn.execute(StrSql) response.write(“Query feito! “ & StrSql) %>

Para executar o código basta abrir o browser e introduzir a URL: www.meu site.com.br/New_Table.asp

Criação de usuários

Criada nossa base de dados SQL, provavelmente vamos querer inserir alguns usuários no sistema. Para isso digite:

CREATE USER nome _ do _ usuário [ [ WITH ] opção [ ... ] ]

onde opção pode ser:

PASSWORD (digite uma senha para o usuário)IN GROUP nome _ do _ grupo do usuário – se não houver nenhum,

digite o comando CREATE GROUPVALID UNTIL ‘data _ hora’

Para atribuir todos os privilégios de bancos de dados a um novo usuário, digite:

GRANT ALL PRIVILEGES ON meuBD.* TO usuario@localhost

IDENTIFIED BY ‘hello’ WITH GRANT OPTION;FLUSH PRIVILEGES;

Esse comando atribui todos os privilégios a todas as tabelas do banco de dadosmeuBD ao usuário , a partir da máquina localhost, cuja senha é hello. O comando FLUSH PRIVILEGES atualiza as novas alterações na tabela SQL em uso. Caso o usuário não exista, um novo usuário será criado.

cap08.indd 165 1/11/2006 15:59:06

Page 158: Universidade VBA

166 universidade VBA

Após criar uma base de dados e utilizar consultas, por exemplo, como as mos-tradas anteriormente, pode ser necessário filtrar os dados armazenados. Afinal de contas, bancos de dados servem para que os dados inscritos neles sejam utilizados. Podemos fazer uma seleção, a partir da interface do cliente do SQL, utilizando o seguinte comando:

SELECT * FROM table WHERE MONTH(data)=’05’;

Em que ‘05’ seleciona todos os registros da tabela onde o campo data possui uma data localizada no mês de maio.

Também podemos utilizar o seguinte comando:

SELECT DISTINCT DAYOFMONTH(data),MONTH(data),YEAR(data);

Esse comando seleciona dia, mês e ano localizados na tabela. Basta inserir os respectivos dados, na forma de números – 1 a 30 para dias; 1 a 12 para meses, números de quatro dígitos para anos – nas respectivas strings.

Importando e exportando arquivos

Mas nem só de consulta vive a administração de bancos de dados SQL. Alguns bancos e tabelas particulares costumam inchar tanto que se torna necessário migrar os dados para o formato texto e esvaziar a tabela original. Nesse caso, podemos utilizar o comando:

LOAD DATA INFILE ‘data.txt’ INTO TABLE tbl _ name

FIELDS TERMINATED BY ‘,’ ENCLOSED BY ‘”’

LINES TERMINATED BY ‘\n’;

Que carrega os registros em formato txt do arquivo data.txt para a tabela tbl_name, em que os campos estão separados por ”,” (vírgula), delimitados por ‘”’ (aspas) e as linhas delimitadas por ”\n” (quebra de linha). Para selecionar todas as ocorrências encontradas na tabela e migrá-las para o arquivo txt, podemos utilizar o comando:

SELECT * INTO OUTFILE ‘eu.txt’ FROM table;

cap08.indd 166 1/11/2006 15:59:06

Page 159: Universidade VBA

Conexão remota e banco de dados 167

8capítulo

Não precisamos, necessariamente, apelar para um arquivo txt – podemos fa-zer um backup da tabela original em uma nova tabela. Basta digitar no Cliente do SQL:

INSERT INTO table1 (nome) SELECT nome FROM table2

Não é necessário criar a tabela previamente – ela é criada no instante em que é solicitada uma cópia de tabela pré-existente tendo-a como arquivo de saída.

Outros comandos

Prosseguiremos mostrando mais alguns comandos de administração, que podem ser utilizados tanto localmente, a partir de um terminal SQL (acessando pelo ter-minal do MS-DOS o diretório onde está salvo o SQL Server e digitando o comando SQL) ou remotamente, pelo cliente SQL que acompanha o SQL Server, ou qualquer cliente de sua preferência. Lembrando que aqui passamos apenas conceitos gerais de SQL: aprofundar-se em criação e administração de bancos de dados SQL requer muito mais tempo do que o necessário para ler este livro, e provavelmente dez vezes o número de páginas que ele contêm.

O Comando JOIN

Às vezes, os dados que necessitamos estão dispostos em mais de uma tabela. Nesses casos usa-se o comando JOIN, que utiliza campos de dados em comum para unir mais de uma tabela.

Suponhamos, por exemplo, possuirmos uma tabela com a listagem de e-mails e outra de contra-senhas – essa segunda possui todas as senhas de compra que devem ser fornecidas a cada usuário todas as vezes que este inserir sua conta de e-mail em um formulário. Essa lista pode utilizar o seguinte código:

USE testesenha;SELECT e-mails.nome,contrasenha.resposta FROM e-

mails,contrasenhas WHERE e-mails.contrasenhas = e-mails.contrasenhas;

Pode-se também usar o JOIN de forma implícita, utilizando a cláusula de condição WHERE para mostrar tão somente campos em que os registros sejam correspondentes. O código é este:

cap08.indd 167 1/11/2006 15:59:06

Page 160: Universidade VBA

168 universidade VBA

USE testesenha;SELECT e-mails.nome,contrasenha.resposta FROM e-mails

INNER JOIN contrasenhas ON e-mails.contrasenha = e-mails.contrasenha;

Existem mais algumas variações de JOIN que podem ser utilizadas. Em LEFT JOIN, os registros da primeira tabela são exibidos – RIGHT JOIN faz o mesmo com a segunda tabela.

Aliases e contagem

Um recurso que torna a criação de um código SQL mais rápida são os aliases ou codinomes dados a uma determinada tabela ou função. Basta colocar o alias desejado em frente ao nome dos campos na cláusula SELECT e depois dos nomes das tabelas FROM. Veja o código:

USE testesenha;SELECT f.e-mail FROM contrasenhas f, contrasenhas d WHERE

d.contrasenhas = f.contrasenhas AND d.resposta = ‘Recebido’;

Note no código anterior que, após a implementação do alias, podemos, em vez de digitar contrasenhas. resposta, digitar simplesmente d.descrição.

Com o comando GROUP BY, por sua vez, podemos utilizar algumas das novas utilidades trazidas pelo comando alias. Utilizando GROUP BY ainda é possível fazer vários tipos de estatísticas e contagens – o que é muito útil para contabilizar os acessos e acertos de um website. Se você possuir um servidor de e-mails em uma rede interna e quiser conhecer as contas de e-mails dos funcionários de cada departamento, por exemplo, pode usar o seguinte código:

USE servidorl;SELECT d.conta departamento, CONT(f.e-mail) total FROM e-

mails f, departamentos d WHERE d.departamento = f.departamento GROUP BY f.departamento

Você também pode utilizar o comando SUM:

USE servidorl;SELECT d.conta departamento, CONT(f.e-mail) total FROM e-

mails f, departamentos d WHERE d.departamento = f.departamento SUM f.departamento

cap08.indd 168 1/11/2006 15:59:07

Page 161: Universidade VBA

Conexão remota e banco de dados 169

8capítulo

Este soma os resultados agrupados de todos os departamentos. Também podemos utilizar o comando SELECT, como neste caso, em que ele retorna todos os e-mails, localizados na tabela E-E-Mails que pertençam ao provedor Hotmail:

select e-mail, rgfrom E-MAILSwhere provedor = hotmail;

Trabalhando com o SQL

Depois de termos tabelas e ligações corretamente configuradas, fica muito fácil interligar um sistema de bancos SQL a um aplicativo VBA. Na implementação se-guinte ligamos uma planilha Excel a um servidor SQL, utilizando para isso as contas de usuário remotos (DNS) desse servidor:

Sub Revenue _ Report()‘ Monta um relatório baseado nas tabelas de um servidor

SQL Dim conn As New ADODB.Connection Dim rec As New ADODB.Recordset Dim sql As String, sql1 as string, sql2 as string conn.Open “DSN=ACCOUNTS”

sql = “SELECT INVOICE _ HEADER.Territory, INVOICE _ DETAIL.ProductGroup, INVOICE _ DETAIL.TaxableAmt “ & _

“FROM ((CUSTOMER _ MASTER INNER JOIN “ & _ “(INVOICE _ DETAIL INNER JOIN INVOICE _ HEADER ON

(INVOICE _ DETAIL.DocType = INVOICE _ HEADER.DocType) AND “ & _

“(INVOICE _ DETAIL.InternalDocNum = INVOICE _ HEADER.InternalDocNum)) ON CUSTOMER _ MASTER.Code = INVOICE _ HEADER.Code) “ & _

“INNER JOIN PRODUCT _ MASTER ON INVOICE _ DETAIL.Code = PRODUCT _ MASTER.Code) “ & _

“INNER JOIN PRODUCTGROUP _ NAME ON PRODUCT _ MAS-TER.ProductGroup = PRODUCTGROUP _ NAME.Code” & _

“WHERE (((INVOICE _ DETAIL.LineType) <> 9) And ((INVOICE _ DETAIL.DocType) <= 3)) “ & _

cap08.indd 169 1/11/2006 15:59:07

Page 162: Universidade VBA

170 universidade VBA

“ORDER BY INVOICE _ HEADER.Territory, INVOICE _ DE-TAIL.ProductGroup”

sql1 = “SELECT INVOICE _ HEADER.Territory, INVOICE _ DETAIL.

ProductGroup, INVOICE _ DETAIL.TaxableAmt “ & _ “FROM INVOICE _ DETAIL “ & _ “INNER JOIN INVOICE _ HEADER ON (INVOICE _ DETAIL.

DocType = INVOICE _ HEADER.DocType AND INVOICE _ DETAIL.Inter-nalDocNum = INVOICE _ HEADER.InternalDocNum) “ & _

“WHERE INVOICE _ DETAIL.DocType <> 9 And INVOI-CE _ DETAIL.LineType <= 3” & _

“ORDER BY INVOICE _ HEADER.Territory, INVOICE _ DE-TAIL.ProductGroup”

sql2 = “SELECT INVOICE _ DETAIL.ProductGroup, INVOICE _

DETAIL.TaxableAmt, INVOICE _ HEADER.Territory “ & _ “FROM INVOICE _ DETAIL INVOICE _ DETAIL, INVOI-

CE _ HEADER INVOICE _ HEADER “ & _ “WHERE INVOICE _ DETAIL.InternalDocNum = INVOI-

CE _ HEADER.InternalDocNum And INVOICE _ HEADER.DocType = IN-VOICE _ DETAIL.DocType “ & _

“And ((INVOICE _ DETAIL.DocType <> 9) And (INVOI-CE _ DETAIL.LineType <= 3)) “ & _

“ORDER BY INVOICE _ HEADER.Territory, INVOICE _ DE-TAIL.ProductGroup”

rec.Open SplitToArray(sql1, 255), conn ‘ Definimos que planilha e células do Excel receberão o

relatório dos dados Sheets(“Sheet2”).Cells(1, 1).CopyFromRecordset rec rec.Close conn.Close

End Sub

cap08.indd 170 1/11/2006 15:59:07

Page 163: Universidade VBA

Conexão remota e banco de dados 171

8capítulo

Oracle

Oracle é um SGBD (sistema gerenciador de banco de dados) que surgiu no final dos anos 1970, quando Larry Ellison vislumbrou uma oportunidade que outras companhias não haviam percebido ao encontrar a descrição de um protótipo fun-cional de um banco de dados relacional e descobrir que nenhuma empresa tinha se empenhado em comercializar essa tecnologia.

O Oracle também suporta a ligação via Access ou Excel, utilizando drivers ODBC, em uma implementação que pode ser mais simples do que a utilizada pelos demais tipos de bancos de dados, já que pode ser iniciada diretamente no editor de código do VBA.

1. Abra o editor do VBA e digite a macro seguinte. Ela será utilizada para criar uma chamada para o banco de dados Oracle a que se tenha acesso:

Function CallSProc() As Boolean

Dim db As Database Dim LSProc As QueryDef

On Error GoTo Err _ Execute

Set db = CurrentDb()

Set LSProc = db.CreateQueryDef(“”)

‘ Agora vamos utilizar o {Microsoft ODBC for Oracle} ODBC connection. Confira em Iniciar>Configurações>Painel de Controle>Configurações>Drivers ODBC.

LSProc.Connect = “ODBC;DSN=AAAA;UID=BBBB;PWD=DDDD;SERVER=CCCC”

LSProc.SQL = “BEGIN application _ program _ interface; END;”

LSProc.ReturnsRecords = False LSProc.ODBCTimeout = 0

cap08.indd 171 1/11/2006 15:59:07

Page 164: Universidade VBA

172 universidade VBA

LSProc.Execute

Set LSProc = Nothing

CallSProc = True

Exit Function

‘ Criaremos uma caixa de texto para nos avisar caso não seja possível nos conectarmos ao banco

Err _ Execute: MsgBox “A chamada ao banco de dados Oracle falhou.” CallSProc = False

End Function

2. A mesma coisa pode ser feita abrindo o Microsoft Access e, em seguida, o editor de VBA, criando um novo módulo e inserindo o seguinte código:

Function CallSProc() As Boolean‘ Cria um meio de acesso a um banco de dados Oracle uti-

lizando o Microsoft Access Dim db As Database Dim LSProc As QueryDef Dim LSQL As String

On Error GoTo Err _ Execute

Set db = CurrentDb()

Set LSProc = db.CreateQueryDef(“”)

‘ Faz a chamada utilizando padrões do Microsoft SQL LSQL = “BEGIN application _ program _ interface (“ &

member _ id & “, “ LSQL = LSQL & provider _ id & “, “ LSQL = LSQL & “to _ date(‘” & Format(service _ date, “mm/

dd/yyyy”) & “’,’mm/dd/yyyy’))” LSQL = LSQL & “; END;”

cap08.indd 172 1/11/2006 15:59:07

Page 165: Universidade VBA

Conexão remota e banco de dados 173

8capítulo

‘ Faz a chamada de forma direta, utilizando {Microsoft ODBC for Oracle} ODBC connection. É a melhor opção, por ser mais direta, mas pode apresentar problemas em redes em que servidores SQL e Oracle, com tabelas replicadas, coexistam.

LSProc.Connect = “ODBC;DSN=AAAA;UID=BBBB;PWD=DDDD;SERVER=CCCC”

LSProc.SQL = LSQL LSProc.ReturnsRecords = False LSProc.ODBCTimeout = 0

LSProc.Execute

Set LSProc = Nothing

CallSProc = True

Exit Function

Err _ Execute: MsgBox “A chamada ao banco de dados Oracle falhou.” CallSProc = False

End Function

3. Para customizar o bloco do código interligado ao SQL Server, proceda da seguinte forma:

LSProc.Connect = “ODBC;DSN=AAAA;UID=BBBB;PWD=DDDD;SERVER=CCCC”

em que:• AAAA é o nome do banco de dados (ODBC Data Source) que se deseja acessar;• BBBB é o nome do usuário que fará login no banco de dados;• CCCC é o nome do servidor de banco de dados;• DDDD é a senha que será utilizada para ter acesso ao servidor Oracle.

cap08.indd 173 1/11/2006 15:59:08

Page 166: Universidade VBA

cap08.indd 174 1/11/2006 15:59:08

Page 167: Universidade VBA

Access 175

9capítulo

Capítulo 9 Access

cap09.indd 175 1/11/2006 15:59:38

Page 168: Universidade VBA

176 universidade VBA

Access

Falamos o bastante sobre bancos de dados de alto desempenho mas não falamos muito do Acces, o front-end que o VBA normalmente utiliza para ter acesso às in-formações das tabelas desses bancos. Pretendemos corrigir essa lacuna agora.

O Microsoft Access, também conhecido por MSAccess, é um banco de dados relacional que permite o desenvolvimento rápido de aplicações que envolvem tanto a modelagem e estrutura de dados como também a interface a ser utilizada pelos usuários. Como o nome indica, foi desenvolvido pela Microsoft.

O desenvolvimento da estrutura de dados se dá de forma muito intuitiva, bastan-do que o desenvolvedor possua conhecimentos básicos em modelagem de dados e lógica de programação. Geralmente uma aplicação desenvolvida com o Access pela linguagem de programação VBA (Visual Basic for Applications) consiste em dois arquivos, um que se denomina BackEnd, onde ficam armazenadas todas as tabelas com seus respectivos relacionamentos, e outro denominado FrontEnd, onde ficam armazenados os códigos fontes, formulários, módulos, consultas e macros.

Para rodar os aplicativos desenvolvidos é necessário que o usuário possua em sua estação de trabalho o MSAccess instalado ou pelo menos o seu Runtime, que vem a ser uma versão enxuta do MSAccess que servirá apenas para rodar os aplicativos sem a possibilidade de desenvolvimento.

Depois do Excel, o Acces é, muito provavelmente, o programa que melhor se integra com recursos VBA. É essa integração a responsável pela alta taxa de quali-dade das aplicações Access produzidas a partir do Access, e pela grande variedade de recursos possíveis.

Para iniciar de onde paramos no capítulo anterior – ou ao menos a partir da mesma linha de desenvolvimento – vamos projetar o acesso de uma base de dados interna ao Access, utilizando VBA. Aqui utilizaremos ADODB em vez do padrão ODBC:

‘ Este primeiro exemplo conecta o Access a um banco de dados interno

‘ Iniciamos definindo o driver de ligação ADODB como a variável

Dim rs As ADODB.Recordset Set rs = New ADODB.Recordset rs.Open “Select * from Snippets”, CurrentProject.Connection,

adOpenKeyset, adLockOptimistic

‘ Em uma implementação levemente diferenciada, poderíamos acessar também bancos de dados externos

cap09.indd 176 1/11/2006 15:59:38

Page 169: Universidade VBA

Access 177

9capítulo

Dim gcnPrimary as New ADODB.Connection’ Setting up the ob-ject (optional)

Set gcnPrimary = New ADODB.Connection’ ADO Connection -- creating a new instance

gcnPrimary.Provider = “Microsoft.Jet.OLEDB.4.0” gcnPrimary.ConnectionString = gstrPrimaryDB gcnPrimary.Open

Dim grsPrimary as ADODB.Recordset’ Setting up the object (optional)

Set grsPrimary = New ADODB.Recordset’ ADO Recordset -- crea-ting a new object

grsPrimary.Source = “SELECT * FROM Snippets”’ Pulling from Snippets table

Set grsPrimary.ActiveConnection = gcnPrimary grsPrimary.Open If grsPrimary.EOF = True Then GoTo BYE’ We have a blank

database and need to skip some code Dim lngIndex As Long lngIndex = -1

Do Until grsPrimary.EOF’ Filling a zero-based array lngIndex = lngIndex + 1 ReDim Preserve aryCodeList(3, lngIndex) aryCodeList(0, lngIndex) = grsPrimary.Fields(“id”) aryCodeList(1, lngIndex) = grsPrimary.Fields(“Language _

Major”) ary CodeList(2, lngIndex) = grsPri m ary.

Fields(“Category”) ar y CodeList(3, lngIndex) = grsPri m ar y.

Fields(“Description”) grsPrimary.MoveNext Loop grsPrimary.Close’ When done we eliminate Recordset Set grsPrimary = Nothing’ Leaving connection open

‘ Ou, em uma implementação mais simples:

Public Sub CompleteDatabaseExample()

cap09.indd 177 1/11/2006 15:59:38

Page 170: Universidade VBA

178 universidade VBA

Dim dbMain as New ADODB.Connection’ Declaring the Con-nection

Dim rsCustomer as New ADODB.Recordset’ Declaring the Recordset

Dim SQL as String’ Declaring a simple variable dbMain.Open “Provider=Microsoft.Jet.OLEDB.4.0;” & _ ‘

Connecting to the Database “Persist Security Info=False;” & _ “Data Source=C:\WINDOWS\Desktop\training.mdb” SQL = “SELECT * FROM Customer”’ Setting up our SQL

Command statement rsCustomer.Open SQL, dbMain, adOpenDynamic, adLockOp-

timistic’ Opening the Recordset (see Recordset Options) Do While Not rsCustomer.EOF’ Loop until we reach the

End-Of-File marker MsgBox “The Customer’s Name is: “ &

rsCustomer(“Name”) MsgBox “The Customer’s City is: “ &

rsCustomer(“City”) rsCustomer(“Country”) = “United States” rsCustomer(“Name”) = rsCustomer(“Name”) & “ Jr.” rsCustomer.Update’ Updating the Records (see also

Recordset (Working With)) rsCustomer.MoveNext’ Moving to the next record

(necessary to reach the EOF) Loop rsCustomer.Close’ Closing the recordset dbMain.Close’ Closing the database connection End Sub

Acesso a SQL

Para o acesso do Access como front-end do SQL Server, por sua vez, podemos não necessitar nem de drivers ODBC nem ADODB, ao menos diretamente. Via de regra, o Access é capaz de trabalhar de forma transparente (sem configurações extras e sem visualização do drive de ligação). Para conferir como isso é possível, vamos a seguir interligar o Access a um servidor SQL e criar uma tabela sem apertar nenhum botão, apenas utilizando códigos VBA:

cap09.indd 178 1/11/2006 15:59:38

Page 171: Universidade VBA

Access 179

9capítulo

Sub PickRandom()“ Definição das variáveis Dim db As Database Dim tdf As TableDef Dim fld As Field Dim rst As Recordset Dim strSQL As String Dim strTableName As String

‘ 1: Criamos uma tabela SQL temporário que irá possuir os campos requeridos

strSQL = “SELECT tblStaff.Firstname, tblStaff.Lastname “ & _

“INTO tblTemp “ & _ “FROM tblStaff;” DoCmd.SetWarnings False DoCmd.RunSQL strSQL DoCmd.SetWarnings True ‘ 2: Adicionamos um campo a nova tabela Set db = CurrentDb() Set tdf = db.TableDefs(“tblTemp”) Set fld = tdf.CreateField(“RandomNumber”, dbSingle) tdf.Fields.Append fld

‘ 3: Atribuímos um valor aleatório a cada novo campo cria-do.

Set rst = db.OpenRecordset(“tblTemp”, dbOpenTable) rst.MoveFirst Do Randomize rst.Edit rst![RandomNumber] = Rnd() rst.Update rst.MoveNext Loop Until rst.EOF rst.Close Set rst = Nothing

cap09.indd 179 1/11/2006 15:59:39

Page 172: Universidade VBA

180 universidade VBA

‘ 4: Listamos os dados de acordo com os valores aleatórios anteriormente atribuidos, e repassamos os 25 primeiros valo-res para a nova tabela.

strTableName = “tblRandom _ ” & Format(Date, “ddmmmyyyy”)

strSQL = “SELECT TOP 25 tblTemp.Firstname, tblTemp.Last-name “ & _

“INTO “ & strTableName & “ “ & _ “FROM tblTemp “ & _ “ORDER BY tblTemp.RandomNumber;” DoCmd.SetWarnings False DoCmd.RunSQL strSQL DoCmd.SetWarnings True

‘ 5: Apagamos a tabela temporária db.TableDefs.Delete (“tblTemp”)End Sub

Criada uma tabela, seria possível adicionar novos dados a ela utilizando o VBA:

Dim rs As New ADODB.Recordset ‘ Com esta variável adicionamos novos elemnetos, via front-

end Access,a uma tabela SQLrs.Open “SELECT * FROM tblBarCode”, CurrentProject.Connec-

tion, adOpenKeyset, adLockOptimistic

‘ Adicionamos novas linhas à tabela-alvo do banco de da-dos

For i = LBound(aryBarCodes()) To UBound(aryBarCodes()) rs.AddNew rs![BarcodeNum] = aryBarCodes(i) rs![PDFFileName] = “empty” rs![NumTIFFsRenamed] = 0 rs![RenamedTIFFsDate] = 0 rs.Update lngCount = lngCount + 1 Next rs.Close

cap09.indd 180 1/11/2006 15:59:39

Page 173: Universidade VBA

Access 181

9capítulo

‘ Nota: evite usar a opção setrecord em bancos de dados multi-usuários ou em que múltiplos usuários têm acesso si-multâneo as tabelas.

Dim strSQL as String For i = LBound(aryBarCodes()) to UBound(aryBarCodes()) strSQL = “INSERT INTO tblBarCode (BarcodeNum, PDFFile-

Name, NumTIFFsRenamed, RenamedTIFFsDate)” strSQL = strSQL & “ VALUES (“ & aryBarCodes(i) & “,

‘empty’, 0, 0)” CurrentProject.Connection.Execute strSQL Next

‘ Outra maneira de adicionar dados pode ser vista a se-guir...

INSERT INTO tblName (FieldName1, FieldName2, FieldName3) VALUES (‘value1’, ‘value2’, True)

‘ Note: (a) Campos não devem ser delimitados por vírgu-las

‘ Agora vamos mostrar como fazer o update de um determi-nado campo via VBA

UPDATE tblName SET FieldName1= ‘value1’, FieldName2= num2, FieldName3= True WHERE field = value

‘ E também como apagar uma linha de dadosDELETE FROM tblName WHERE FieldName1= value

‘ Observe o exemplo abaixo para perceber como o commando DELETE opera

“ strSQL = “DELETE from tblCustomers WHERE Name = “Smith, John”

CurrentProject.Connection.Execute strSQL

Option Compare Database Option Explicit Public booCompactTime As Boolean Function Autoexec() ‘ ---------------------------------------------------------

cap09.indd 181 1/11/2006 15:59:39

Page 174: Universidade VBA

182 universidade VBA

‘ Purpose: ‘ 1. Compiles all code in the database if it is uncompiled ‘ 2. Writes usage info to custom database properties ‘ 3. Writes usage info to the Registry ‘ 4. Sets flag to indicate if db is due for compacting ‘ --------------------------------------------------------- On Error GoTo Autoexec _ Err

Dim strModule As String Dim strProperty As String Dim dtLastOpened As Date Dim db As Database Dim pty As Property Dim lngDBTimesOpened As Long Dim lngProfileTimesOpened As Long Dim intRetVal As Integer

Set db = CurrentDb

‘ If the db is not compiled then open a module and ‘ force recompilation If Not Application.IsCompiled Then ‘ Display a message indicating we are compiling DoCmd.OpenForm “frmCompile”, , , , acFormReadOnly ‘ Turn off screen updating Application.Echo False ‘ Get the name of any module strModule = db.Containers(“Modules”).Documents(0).

Name ‘ Open the module so we can use the Compile Modules menu

command DoCmd.OpenModule strModule ‘ Compile and save all modules Application.RunCommand acCmdCompileAndSaveAllModules ‘ Set a database property to indicate last compile time MarkCompileTime ‘ Give audible confirmation Beep ‘ Close the module we opened DoCmd.Close acModule, strModule

cap09.indd 182 1/11/2006 15:59:39

Page 175: Universidade VBA

Access 183

9capítulo

‘ Turn screen updating back on Application.Echo True ‘ Remove the warning form DoCmd.Close acForm, “frmCompile” End If ‘ Find out how many times this particular database has

been opened IncrementTimesOpened lngDBTimesOpened = db.Properties(“TimesOpened”) ‘ If this

is the first time for this database, then show the greeting form

If lngDBTimesOpened = 1 Then DoCmd.OpenForm “frmGreeting”, , , , , acDialog Else ‘ Else open the greeting form unless the user has deselected

the re-view check box If GetSetting(“MWSDB”, “Preferences”, “StartUpDialog”,

True) Then DoCmd.OpenForm “frmGreeting”, , , , , acDialog End If End If

‘ Write information to the Registry to indicate usage for this user

lngProfileTimesOpened = GetSetting(“MWSDB”, “Statistics”, “UsageCount”, 1)

SaveSetting “MWSDB”, “Statistics”, “UsageCount”, lngProfileTimesOpened + 1

SaveSetting “MWSDB”, “Statistics”, “LastUsed”, Format$(Now(), “yyyy.mm.dd hh:nn:ss”)

‘ And finally open the switchboard form DoCmd.OpenForm “frmSwitchboard” ‘ This form would contain

a cmdCompactDatabase control

Autoexec _ Exit: Exit Function

Autoexec _ Err: ‘ Turn screen updating back on

cap09.indd 183 1/11/2006 15:59:39

Page 176: Universidade VBA

184 universidade VBA

Application.Echo True

‘ Now handle the error Select Case Err.Number Case Else Call GlobalErr(“Autoexec”, Err.Number) Resume Autoexec _ Exit Resume End Select

End Function

Sub GlobalErr(strProcName As String, intErr As Integer) ‘ --------------------------------------------------------- ‘ Purpose: To display a message box providing details of

a given error ‘ Parameters: strProcName - the name of the procedure

calling GlobalErr intErr - an Error code ‘ Returns: Nothing ‘ --------------------------------------------------------- Dim strMsg As String

strMsg = “The following error occurred in the “ & strProc-Name & “ procedure”

strMsg = strMsg & Chr$(10) & Chr$(10) strMsg = strMsg & “Error Number: “ & Format$(intErr) &

Chr$(10) strMsg = strMsg & “Error Description: “ & Error$

MsgBox strMsg, 48, “Unexpected Error”

GlobalErr _ Exit: Exit Sub End Sub

Sub MarkCompileTime() ‘ --------------------------------------------------------- ‘ Purpose: To set a db property indicating when the data-

base was last programmatically compiled

cap09.indd 184 1/11/2006 15:59:39

Page 177: Universidade VBA

Access 185

9capítulo

‘ Parameters: None ‘ Returns: Nothing ‘ --------------------------------------------------------- On Error GoTo MarkCompileTime _ Err

Dim pty As Property

CurrentDb.Properties(“LastCompiled”) = Now

MarkCompileTime _ Exit: Exit Sub

MarkCompileTime _ Err: Select Case Err.Number Case 3270 ‘Error code for “Property not found” Set pty = CurrentDb.CreateProperty(“LastCompi

led”, dbDate, Now()) CurrentDb.Properties.Append pty Resume Case Else Call GlobalErr(“MarkCompileTime”, Err.Number) Resume MarkCompileTime _ Exit Resume End Select

End Sub

Sub IncrementTimesOpened() ‘ --------------------------------------------------------- ‘ Purpose: To set a db property indicating the number of

times the database has been opened ‘ Parameters: None ‘ Returns: Nothing ‘ --------------------------------------------------------- On Error GoTo IncrementTimesOpened _ Err

Dim pty As Property Dim lngDBTimesOpened As Long

cap09.indd 185 1/11/2006 15:59:39

Page 178: Universidade VBA

186 universidade VBA

lngDBTimesOpened = CurrentDb.Properties(“TimesOpened”) CurrentDb.Properties(“TimesOpened”) = lngDBTimesOpened + 1 ‘ Warn the user to re-compact every five opens If lngDBTimesOpened Mod 5 = 0 Then booCompactTime = True End If

IncrementTimesOpened _ Exit: Exit Sub

IncrementTimesOpened _ Err: Select Case Err.Number Case 3270’ Error code for “Property not found” Set pty = CurrentDb.CreateProperty(“TimesOpened”,

dbDate, 0) CurrentDb.Properties.Append pty Resume Case Else Call GlobalErr(“IncrementTimesOpened”, Err.

Number) Resume IncrementTimesOpened _ Exit Resume End Select End Sub

Access x Excel

Seguindo o padrão de integração dos programas, é perfeitamente possível fazer a interligação de dados de um banco de dados Access para planilhas do Excel ou vice-versa. O próprio Office permite esse tipo de transferência, conforme mostrado a seguir:

1. Na janela Banco de dados no Microsoft Access, clique na tabela, consulta, formulário ou relatório que você deseja usar no Excel.

2. No menu Ferramentas, aponte para Vínculos do Office, e clique em Analisar com o MS Excel.

O Access salva o conteúdo da tabela, consulta, formulário ou relatório como um arquivo (.xls) de pasta de trabalho do Excel e abre o arquivo no Excel. O arquivo é

cap09.indd 186 1/11/2006 15:59:40

Page 179: Universidade VBA

Access 187

9capítulo

salvo com o nome da tabela, consulta ou outro objeto de banco de dados na pasta de atual.

Observação: se você tiver um formulário principal com um ou mais sub-formu-lários, ou um relatório principal com um ou mais sub-relatórios, o Access salvará na pasta de trabalho apenas os dados contidos no formulário ou relatório principal.

3. Para copiar apenas os registros selecionados, vá até o Microsoft Access, abra a tabela, consulta ou formulário que contém os registros que você deseja copiar.

4. No menu Exibir, clique em Modo folha de dados. Selecione os registros que deseja copiar.

5. Se desejar selecionar colunas específicas, arraste pelos cabeçalhos de coluna adjacentes. Clique em Copiar.

6. Alterne para o Excel. Clique no canto superior esquerdo da área da planilha onde você deseja que o primeiro nome de campo seja exibido.

7. Para garantir que os registros copiados não substituam registros existentes, certifique-se de que a planilha não tem dados abaixo ou à direita da célula em que você clicar. Clique em Colar.

Apesar de não ser uma operação complexa, a ação anterior é um pouco traba-lhosa, sobretudo ao se operar com bases de dados ou planilhas de grande porte. Por isso, vamos mostrar como realizar as mesmas alterações, mas utilizando uma macro VBA:

Sub intro() ‘ Permite a transferência de dados em uma base de dados do

Access para uma planilha Excel Dim conn As New Connection Dim rec As New Recordset Dim ws As Worksheet Dim sql$, i& Set ws = ThisWorkbook.Worksheets(“intro”) conn.Open “Provider=microsoft.jet.oledb.4.0;” + _ “Data Source=” + ThisWorkbook.Path + “\nwind.

mdb;” sql = “SELECT LastName, FirstName “ & _

cap09.indd 187 1/11/2006 15:59:40

Page 180: Universidade VBA

188 universidade VBA

“FROM employees ORDER BY LastName, FirstName” rec.Open sql, conn While Not rec.EOF i = i + 1 ws.[a1].Cells(i) = rec!LastName + “, “ +

rec!FirstName rec.MoveNext Wend rec.Close: conn.Close End Sub

Sub rec _ fields() Dim conn As New Connection Dim rec As New Recordset Dim f As Field Dim ws As Worksheet Dim i& Set ws = ThisWorkbook.Worksheets(“fields”) conn.Open “Provider=microsoft.jet.oledb.4.0;” + _ “Data Source=” + ThisWorkbook.Path + “\nwind.

mdb;” rec.Open “employees”, conn For Each f In rec.Fields i = i + 1 ws.[a1].Cells(i) = f.Name ws.[b1].Cells(i) = f.Type ws.[c1].Cells(i) = TypeName(f.Value) Next rec.Close: conn.Close End Sub

Sub command _ parameters() Dim conn As New Connection Dim rec As New Recordset Dim comm As New Command Dim ws As Worksheet Dim i&, countryname$ Set ws = ThisWorkbook.Worksheets(“command”) conn.Open “Provider=microsoft.jet.oledb.4.0;” + _

cap09.indd 188 1/11/2006 15:59:40

Page 181: Universidade VBA

Access 189

9capítulo

“Data Source=” + ThisWorkbook.Path + “\nwind.mdb;” Set comm.ActiveConnection = conn comm.CommandText = “SELECT companyname FROM customers

WHERE country = ?” countryname = InputBox(“Please type in a country name

(i.e. ‘germany’).”) comm.Parameters(0) = countryname rec.Open comm ws.[a1].CopyFromRecordset rec rec.Close: conn.Close End Sub

Comparação entre bases de dados

Você pode utilizar qualquer operador SQL padrão como critério de pesquisa ou comparação entre duas bases de dados. Quando você utiliza operadores em um critério de pesquisa, as regras a seguir se aplicam:

• Os tipos de informações dos dados utilizados na comparação devem corres-ponder. Ou seja, apenas texto pode ser comparado a texto, números a números e assim por diante. Você pode utilizar uma função ou palavra-chave (como CAST), para converter temporariamente os dados para um outro tipo;

• Ao comparar os dados do tipo texto, o resultado depende do conjunto de ca-racteres em uso no momento. Por exemplo, se uma tabela tiver sido criada utilizando caracteres escandinavos, os resultados da pesquisa podem diferir, dependendo do conjunto de caracteres atual (página de código) ser escandinavo ou outro conjunto de caracteres;

• Se um valor de comparação for nulo, o resultado é desconhecido. Os nulos não são combinados a qualquer valor, incluindo outras ocorrências de nulo. Por exemplo, se você estiver procurando um nome que se inicia com a letra "M" ou acima (nome >= "M") e algumas das linhas não contêm valor, essas linhas não aparecem, não importa que operador de comparação você utiliza.

O VBA permite a criação de um aplicativo de comparação entre dois bancos de dados diferentes, utilizando comandos SQL. Observe a seguir a implementação desse aplicativo.

Option Compare Database “ Iniciamos a criação de nosso comparador de bancos de

dadosOption Explicit

cap09.indd 189 1/11/2006 15:59:40

Page 182: Universidade VBA

190 universidade VBA

Public booCompactTime As Boolean Function Autoexec()

On Error GoTo Autoexec _ Err

Dim strModule As String Dim strProperty As String Dim dtLastOpened As Date Dim db As Database Dim pty As Property Dim lngDBTimesOpened As Long Dim lngProfileTimesOpened As Long Dim intRetVal As Integer

Set db = CurrentDb

‘ Se o banco de dados não foi compilado, abre o módulo e força a compilação

If Not Application.IsCompiled Then ‘ Mostra mensagem indicando que o banco de dados foi com-

pilado DoCmd.OpenForm “frmCompile”, , , , acFormReadOnly ‘ Atualzia a tela do banco de dados Application.Echo False ‘ Dá um nome a um novo módulo strModule = db.Containers(“Modules”).Documents(0).Name ‘ Abre os módulos e os compila manualmente DoCmd.OpenModule strModule ‘ A seguir, compilamos e salvamos todos os módulos Application.RunCommand acCmdCompileAndSaveAllModules ‘ Registra a data e hora em que a base de dados foi com-

pilada MarkCompileTime ‘ Emite um sinal sonoro que confirma o envio Beep ‘ Fecha os módulos que proventura estejam abertos DoCmd.Close acModule, strModule ‘ Atualiza a tela do banco de dados novamente Application.Echo True

cap09.indd 190 1/11/2006 15:59:40

Page 183: Universidade VBA

Access 191

9capítulo

‘ Remove formers que não estejam sendo utilizados DoCmd.Close acForm, “frmCompile” End If ‘ Encontra as últimas alterações e mambas as bases de da-

dos comparadas IncrementTimesOpened lngDBTimesOpened = db.Properties(“TimesOpened”) ‘ If this

is the first time for this database, then show the greeting form

If lngDBTimesOpened = 1 Then DoCmd.OpenForm “frmGreeting”, , , , , acDialog Else

If GetSetting(“MWSDB”, “Preferences”, “StartUpDialog”, True) Then

DoCmd.OpenForm “frmGreeting”, , , , , acDialog End If End If

‘ Escreve as informações encontradas no Registro (Capítulo 3) da máquina que está sendo usada como cliente das compa-rações

lngProfileTimesOpened = GetSetting(“MWSDB”, “Statistics”, “UsageCount”, 1)

SaveSetting “MWSDB”, “Statistics”, “UsageCount”, lngProfi-leTimesOpened + 1

SaveSetting “MWSDB”, “Statistics”, “LastUsed”, Format$(Now(), “yyyy.mm.dd hh:nn:ss”)

DoCmd.OpenForm “frmSwitchboard” ‘ This form would contain a cmdCompactDatabase control

Autoexec _ Exit: Exit Function

Autoexec _ Err: Application.Echo True

Select Case Err.Number Case Else

cap09.indd 191 1/11/2006 15:59:41

Page 184: Universidade VBA

192 universidade VBA

Call GlobalErr(“Autoexec”, Err.Number) Resume Autoexec _ Exit Resume End Select

End Function

Sub GlobalErr(strProcName As String, intErr As Integer)

Dim strMsg As String

strMsg = “The following error occurred in the “ & strProc-Name & “ procedure”

strMsg = strMsg & Chr$(10) & Chr$(10) strMsg = strMsg & “Error Number: “ & Format$(intErr) &

Chr$(10) strMsg = strMsg & “Error Description: “ & Error$

MsgBox strMsg, 48, “Unexpected Error”

GlobalErr _ Exit: Exit Sub End Sub

Sub MarkCompileTime() On Error GoTo MarkCompileTime _ Err

Dim pty As Property

CurrentDb.Properties(“LastCompiled”) = Now

MarkCompileTime _ Exit: Exit Sub

MarkCompileTime _ Err: Select Case Err.Number Case 3270 ‘Error code for “Property not found” Set pty = CurrentDb.CreateProperty(“LastCompi

led”, dbDate, Now()) CurrentDb.Properties.Append pty

cap09.indd 192 1/11/2006 15:59:41

Page 185: Universidade VBA

Access 193

9capítulo

Resume Case Else Call GlobalErr(“MarkCompileTime”, Err.Number) Resume MarkCompileTime _ Exit Resume End Select

End Sub

Sub IncrementTimesOpened()

On Error GoTo IncrementTimesOpened _ Err

Dim pty As Property Dim lngDBTimesOpened As Long

lngDBTimesOpened = CurrentDb.Properties(“TimesOpened”) CurrentDb.Properties(“TimesOpened”) = lngDBTimesOpened + 1 ‘ Warn the user to re-compact every five opens If lngDBTimesOpened Mod 5 = 0 Then booCompactTime = True End If

IncrementTimesOpened _ Exit: Exit Sub

IncrementTimesOpened _ Err: Select Case Err.Number Case 3270’ Error code for “Property not found” Set pty = CurrentDb.CreateProperty(“TimesOpened”,

dbDate, 0) CurrentDb.Properties.Append pty Resume Case Else Call GlobalErr(“IncrementTimesOpened”, Err.

Number) Resume IncrementTimesOpened _ Exit Resume End Select End Sub

cap09.indd 193 1/11/2006 15:59:41

Page 186: Universidade VBA

194 universidade VBA

Compactação de bases de dados

Dependendo da configuração do computador e do ambiente de trabalho, há várias maneiras de melhorar o desempenho do Microsoft Access.

Se você excluir dados ou objetos de um banco de dados do Access, ou se excluir objetos de um projeto do Access, o arquivo pode ficar fragmentado e utilizar o es-paço em disco de forma ineficiente. A compactação do arquivo do Access copia o arquivo e reorganiza a forma como é armazenado em disco. A compactação de um banco de dados de uma versão anterior do Access não o converterá em formato do Access 2002 - 2003.

A compactação otimiza o desempenho dos bancos de dados e dos projetos do Access. Entretanto, em um projeto do Access, ela não afeta os objetos de banco de dados – como, por exemplo, tabelas ou modos de exibição – que residem no banco de dados do Microsoft SQL Server em vez de no próprio projeto do Access.

A compactação não tem efeito algum sobre a auto-numeração em um projeto do Access. Entretanto, em um banco de dados do Access, se você excluir registros do fim de uma tabela que possui um campo AutoNumeração, a compactação do banco de dados redefine o valor da AutoNumeração; o valor da AutoNumeração do próximo registro adicionado será um número maior que o valor da AutoNumeração do último registro não excluído da tabela.

O projeto a seguir implementa uma macro que compacta uma base de dados de maneira não excludente, ou seja, sem apagar linhas, colunas ou chaves em branco. Utilizamos drivers ADODB para fazer a interligação entre o front-end Access e a base de dados onde estão armazenadas as planilhas.

Public Sub CompactWithADO() On Error GoTo BYE Dim JRO As New JRO.JetEngine Dim cnnSrc As New ADODB.Connection Dim strSource As String Dim strDestDB As String Dim strPassword As String Dim iFileStart As Integer

With frmSnippetBrowser.CommDlg1 .DialogTitle = “Select Database to Compact” .Filter = “Access 97/2000 (*.mdb)|*.mdb” .CancelError = False .InitDir = gDbasePath

cap09.indd 194 1/11/2006 15:59:41

Page 187: Universidade VBA

Access 195

9capítulo

.ShowOpen End With

strSource = frmSnippetBrowser.CommDlg1.FileName If strSource = “” Then MsgBox “Cancel clicked” Exit Sub End If

‘ Fecha a base de dados Dim blnMeFlag As Boolean blnMeFlag = False If strSource = gstrPrimaryDB Then Btn = MsgBox(“You’ve selected the Active Database!”

& vbCrLf & vbCrLf & _ “Compactaçõa está sendo realizada! Reiniice o

aplicativo após a finalização do processo.” & vbCrLf & vbCrLf & _

“ Você realemnte quer realizar a compactação?”, vbOKCancel + vbQuestion, _

“ Compactação da base de dados ativa inicia-da”)

If Btn = vbNo Then Exit Sub gcnPrimary.Close Set gcnPrimary = Nothing blnMeFlag = True End If ‘ Determina o tamanho do arquivo Dim intReadChan As Integer Dim lngInitialFileSize As Long intReadChan = FreeFile Open strSource For Input As intReadChan ‘ Faz a referencia ao arquivo de destino lngInitialFileSize = LOF(intReadChan) ‘ Mostra o tamaho do arquivo Close intReadChan

cnnSrc.ConnectionString = “Provider=Microsoft.Jet.OLEDB.4.0;Data Source=” & strSource & _

cap09.indd 195 1/11/2006 15:59:41

Page 188: Universidade VBA

196 universidade VBA

“;Persist Security Info=False” cnnSrc.Open

‘ Fecha a conexão corrente entre o banco de dados e o front-end, se um deles utilizar conexão remota

cnnSrc.Close Set cnnSrc = Nothing

‘ define o caminho do diretório e do arquivo, e adiciona “Backup of “ ao nome do arquivo compactado

LastSlashPos = InStrRev(strSource, “\”) strPath = Left(strSource, LastSlashPos) strFilename = Right(strSource, Len(strSource) - Last

SlashPos) strDestDB = strPath & “Backup of “ & strFilename

‘ Encerra o Backup JRO.CompactDatabase “Provider=Microsoft.Jet.OLEDB.4.0;Data

Source=” & strSource & _ “;Jet OLEDB:Database Password=” & strPassword, _ “Provider=Microsoft.Jet.OLEDB.4.0;Data Source=” &

strDestDB & _ “;Jet OLEDB:Database Password=” & strPassword

‘ Deleta o arquivo original Kill strSource

DoEvents ‘ renomeia o arquivo original Name strDestDB As strSource

Dim lngFinalFileSize As Long intReadChan = FreeFile’ Get first open file number

(i.e., free channel) Open strSource For Input As intReadChan’ Can now refer

to input file by this lngFinalFileSize = LOF(intReadChan)’ Gives us our fi-

lesize Close intReadChan Dim lngResult As Long

cap09.indd 196 1/11/2006 15:59:41

Page 189: Universidade VBA

Access 197

9capítulo

lngResult = lngInitialFileSize - lngFinalFileSize

MsgBox strSource & vbCrLf & vbCrLf & “Compactado com sucesso!” & vbCrLf & vbCrLf & _

“Initial Filesize = “ & Str(lngInitialFileSize) & “ . . . . “ & _

“Final Filesize = “ & Str(lngFinalFileSize) & vb-CrLf & vbCrLf & _

Str(lngResult) & “ bytes were recovered!.”, vbOKOnly + vbInformation, _

“ Resultados do processo de compactação”

Set JRO = Nothing If blnMeFlag = True Then End End If BYE: End Sub

Se a base de dados parece apresentar problemas durante a compactação, experimente criar a macro a seguir e executá-la. Ela realiza a leitura da base por etapas:

Public Sub ChangeTitle() Dim strName As String, strMessage As String, strPrompt

As String Dim wspDefault As Workspace, dbsNorthwind As Database Dim rstEmployees As Recordset strPrompt = “Alterar o título da tabela atual?” Set wspDefault = DBEngine.Workspaces(0)’ Get default

Workspace. Set dbsNorthwind = wspDefault.Databases(0)’ Get current

database. ‘ Você pode substituir o nome das tabelas pelos que bem

desejar Set rstEmployees = dbsNorthwind.OpenRecordset(“Emprega-

dos”, dbOpenTable)’ Open table. wspDefault.BeginTrans’ Start of transaction. rstEmployees.MoveFirst Do Until rstEmployees.EOF

cap09.indd 197 1/11/2006 15:59:42

Page 190: Universidade VBA

198 universidade VBA

If rstEmployees![Title] = “Sales Representative” Then strName = rstEmployees![LastName] & _ “, “ & rstEmployees![FirstName] strMessage = “Employee: “ & strName & vbCrLf & vbCrLf If MsgBox(strMessage & strPrompt, vbQuestion + vbYesNo, _ “Altere o nome da função”) = vbYes Then rstEmployees.Edit’ Enable editing. rstEmployees![Title] = “Account Executive” rstEmployees.UPDATE’ Save changes. End If End If rstEmployees.MoveNext’ Move to next record. Loop If MsgBox(“Salvar todas as alterações?”, vbQuestion +

vbYesNo, _ “ Salvar as alterações”) = vbYes Then wspDefault.CommitTrans’ Commit changes. Else wspDefault.Rollback’ Undo changes. End If rstEmployees.Close ‘ Close table. dbsNorthwind.Close End Sub

Aplicativo de folha de pagamento

Vamos criar agora um aplicativo de folha de pagamento, utilizando o que apren-demos sobre o Access. Utilizaremos algumas das UserForms do Access, mas você não precisa se assustar: utilizaremos o próprio modo de formulário do Access para realizar nossa tarefa.

1. Inicie o Microsoft Access e crie um banco de dados em branco, nomeando-o como Payroll1.

2. Clique no menu Inserir > Forma. Na caixa de diálogo Nova Forma, selecione a opção Design View.

3. Salve a forma como Payroll. Em seguida, desenhe um formulário que contenha todas as linhas e botões citados na tabela a seguir. Você pode utilizar a disposição que desejar e/ou achar mais funcional, desde que a calculadora funcione.

cap09.indd 198 1/11/2006 15:59:42

Page 191: Universidade VBA

Access 199

9capítulo

Você deve utilizar a tabela da seguinte maneira:• Crie um objeto para cada respectivo controle;• Defina uma caption ou nome para cada objeto;• Defina a propriedade correspondente para cada objeto.

4. A tabela é a seguinte:

Control

Option GroupText BoxText BoxOption GroupLabelLabelLabelLabelLabelLabelLabelLabelText BoxText BoxText BoxText BoxText BoxText BoxText BoxText BoxText BoxText BoxText BoxText BoxText BoxText BoxOption GroupttonLabelLabelLabelText BoxText BoxText BoxLabelText BoxText BoxButton

Caption

Identificação do funcionárioNome do funcionárioSalário por horaFolha de horasSegundaTerçaQuartaQuintaSextaSábadoDomingoPrimeira semana:

Processo de pagamentoPague:Horas:Total:Horas regulares

PagueTotal trabalhado

Fechar

Name

txtEmployeeNametxtHourySalary

txtMonday1txtTuesday1txtWednesday1txtThursday1txtFriday1txtSaturday1txtSunday1txtMonday2txtTuesday2txtWednesday2txtThursday2txtfriday2txtSaturday2txtSunday2

cmdProcesslt

txtRegularHourstxtRegularAmounttxtNetPay

txtOvertimeHourstxtOvertime AmountcmdClose

Tabela 9.1.

5. Clique com o botão direito do mouse sobre o botão Processo de Pagamento e selecione a opção Construir Evento.

cap09.indd 199 1/11/2006 15:59:42

Page 192: Universidade VBA

200 universidade VBA

6. Na janela Escolher construtor, selecione a opção Construtor de código. Na janela do editor do VBA que será aberta, implemente o seguinte código:

Private Sub cmdProcessIt _ Click()

Dim monday1 As Double Dim tuesday1 As Double Dim wednesday1 As Double Dim thursday1 As Double Dim friday1 As Double Dim saturday1 As Double Dim sunday1 As Double Dim monday2 As Double Dim tuesday2 As Double Dim wednesday2 As Double Dim thursday2 As Double Dim friday2 As Double Dim saturday2 As Double Dim sunday2 As Double Dim totalHoursWeek1 As Double Dim totalHoursWeek2 As Double

Dim regHours1 As Double Dim regHours2 As Double Dim ovtHours1 As Double Dim ovtHours2 As Double Dim regAmount1 As Currency Dim regAmount2 As Currency Dim ovtAmount1 As Currency Dim ovtAmount2 As Currency Dim regularHours As Double Dim overtimeHours As Double Dim regularAmount As Currency Dim overtimeAmount As Currency Dim totalEarnings As Currency

Dim hourlySalary As Currency

cap09.indd 200 1/11/2006 15:59:42

Page 193: Universidade VBA

Access 201

9capítulo

‘ Descobre o salário por hora hourlySalary = CDbl(Me.txtHourlySalary) ‘ Descobre as horas trabalhadas em cada dia útil ‘ Primeira semana de trabalho monday1 = CDbl(Me.txtMonday1) tuesday1 = CDbl(Me.txtTuesday1) wednesday1 = CDbl(Me.txtWednesday1) thursday1 = CDbl(Me.txtThursday1) friday1 = CDbl(Me.txtFriday1) saturday1 = CDbl(Me.txtSaturday1) sunday1 = CDbl(Me.txtSunday1) ‘ Segunda semana. Pode-se implementar uma calculadora

que faça o calculo de quatro semanas – ou um mês completo – bastando configurar mais jogos de objetos como os mostra-dos na tabela e repetir mais duas vezes o código de contagem por semanas.

monday2 = CDbl(Me.txtMonday2) tuesday2 = CDbl(Me.txtTuesday2) wednesday2 = CDbl(Me.txtWednesday2) thursday2 = CDbl(Me.txtThursday2) friday2 = CDbl(Me.txtFriday2) saturday2 = CDbl(Me.txtSaturday2) sunday2 = CDbl(Me.txtSunday2) ‘ Calcula o número total de horas por semana. totalHoursWeek1 = monday1 + tuesday1 + wednesday1 +

thursday1 + _ friday1 + saturday1 + sunday1 totalHoursWeek2 = monday2 + tuesday2 + wednesday2 +

thursday2 + _

‘ Calcula o pagamento de expedientes de meio período Dim ovtSalary As Double ovtSalary = hourlySalary * 1.5

‘ Calcula o trabalho de funcionários que trabalharem mais de 40 horas em uma semana

cap09.indd 201 1/11/2006 15:59:42

Page 194: Universidade VBA

202 universidade VBA

If totalHoursWeek1 < 40 Then regHours1 = totalHoursWeek1 regAmount1 = hourlySalary * regHours1 ovtHours1 = 0 ovtAmount1 = 0 ‘ Se o empregado trabalhou mais de 40 horas, a função a

seguir calcula as horas excedentes que devem ser pagas ElseIf totalHoursWeek1 >= 40 Then regHours1 = 40 regAmount1 = hourlySalary * 40 ovtHours1 = totalHoursWeek1 - 40 ovtAmount1 = ovtHours1 * ovtSalary End If If totalHoursWeek2 < 40 Then regHours2 = totalHoursWeek2 regAmount2 = hourlySalary * regHours2 ovtHours2 = 0 ovtAmount2 = 0 ElseIf totalHoursWeek2 >= 40 Then regHours2 = 40 regAmount2 = hourlySalary * 40 ovtHours2 = totalHoursWeek2 - 40 ovtAmount2 = ovtHours2 * ovtSalary End If regularHours = regHours1 + regHours2 overtimeHours = ovtHours1 + ovtHours2 regularAmount = regAmount1 + regAmount2 overtimeAmount = ovtAmount1 + ovtAmount2 totalEarnings = regularAmount + overtimeAmount

Me.txtRegularHours = regularHours Me.txtOvertimeHours = overtimeHours Me.txtRegularAmount = CCur(regularAmount) Me.txtOvertimeAmount = CCur(overtimeAmount)

Me.txtNetPay = CCur(totalEarnings)End Sub

cap09.indd 202 1/11/2006 15:59:43

Page 195: Universidade VBA

Access 203

9capítulo

Undelete

Mas, e se você perder a base de dados das suas folhas de pagamento, ou qualquer um dos seus bancos de dados? Existem diversos programas de recuperação de dados a disposição – e o autor dessas páginas é até adepto de um ou dois deles – mas na maioria das vezes eles não são capazes de recuperar as informações da forma dese-jada. No caso de tabelas SQL, Access ou formulários, não é raro que apenas uma parte das informações consiga ser recuperada, o que, em se tratando de aplicações complexas, equivale a nada.

O projeto a seguir ajuda a criar uma ferramenta de recuperação de tabelas e filtros do Excel, semelhante ao antigo Undelete do MS-DOS. Para quem não lembra, o Undelete é um aplicativo que recupera arquivos apagados pela tecla Delete do teclado ou pelo comando Ren.

Para criar o aplicativo basta possuir qualquer versão do Access acima do 2000, abrindo o Editor do VBA (Alt + F11) embutido.

Option Compare DatabaseOption Explicit

‘ VBA MODULE: Undelete ‘‘ R EQ UIR E M E N TS: V B A DAO R efe r e nc e, Ac c e ss

97/2000/2002(XP)/2003Public Function FnUndeleteObjects() As Boolean

On Error GoTo ErrorHandler:

Dim strObjectName As String Dim rsTables As DAO.Recordset Dim dbsDatabase As DAO.Database

Dim tDef As DAO.TableDef Dim qDef As DAO.QueryDef

Dim intNumDeletedItemsFound As Integer

Set dbsDatabase = CurrentDb

For Each tDef In dbsDatabase.TableDefs

cap09.indd 203 1/11/2006 15:59:43

Page 196: Universidade VBA

204 universidade VBA

‘This is actually used as a ‘Deleted Flag’ If tDef.Attributes And dbHiddenObject Then

strObjectName = FnGetDeletedTableNameByProp(tDef.Name)

strObjectName = InputBox(“Uma tabela deletada foi descoberta.” & _

vbCrLf & vbCrLf & _ “Para recuperar o

objeto, digite seu nome:”, _ “Access Undelete Ta-

ble”, strObjectName)

If Len(strObjectName) > 0 Then

FnUndeleteTable CurrentDb, tDef.Name, strObjectName

End If

intNumDeletedItemsFound = intNumDeletedItems-Found + 1

End If

Next tDef

For Each qDef In dbsDatabase.QueryDefs

If InStr(1, qDef.Name, “~TMPCLP”) = 1 Then

‘ note que não é possível recuperar tabelas com seu nome original. O mesmo não se aplica aos filtros

strObjectName = “” strObjectName = InputBox(“Um filtro deletado

foi descoberto.” & _ vbCrLf & vbCrLf & _ “Para recuperar o

objeto, digite seu novo nome:”, _

cap09.indd 204 1/11/2006 15:59:43

Page 197: Universidade VBA

Access 205

9capítulo

“Access Undelete Query”, strObjectName)

If Len(strObjectName) > 0 Then

If FnUndeleteQuery(CurrentDb, qDef.Name, strObjectName) Then

‘ Renomeia o objeto recuperado qDef.Name = “~TMPCLQ” & Right$(qDef.

Name, Len(qDef.Name) - 7)

End If

End If

intNumDeletedItemsFound = intNumDeletedItems-Found + 1

End If

Next qDef

If intNumDeletedItemsFound = 0 Then

MsgBox “Terminado o processo de recuperação de tabelas e filtros perdidos!”

End If

Set dbsDatabase = Nothing FnUndeleteObjects = True

ExitFunction: Exit Function

ErrorHandler: MsgBox “Um erro ocorreu na recuperação dos objetos()

- “ & _

cap09.indd 205 1/11/2006 15:59:43

Page 198: Universidade VBA

206 universidade VBA

Err.Description & “ (“ & CStr(Err.Number) & “)”

GoTo ExitFunction

End Function

Private Function FnUndeleteTable(dbDatabase As DAO.Data-base, _

strDele-tedTableName As String, _

strNewTa-bleName As String)

Dim tDef As DAO.TableDef

Set tDef = dbDatabase.TableDefs(strDeletedTableName)

‘ Remove as flags dos objetos excluídos tDef.Attributes = tDef.Attributes And Not dbHiddenOb-

ject

‘ Renomeia a tabela recuperada tDef.Name = strNewTableName

dbDatabase.TableDefs.Refresh Application.RefreshDatabaseWindow

Set tDef = Nothing

End Function

Private Function FnUndeleteQuery(dbDatabase As DAO.Data-base, _

strDeletedQueryName As String, _ strNewQueryName As String)

If FnCopyQuery(dbDatabase, strDeletedQueryName, strNewQueryName) Then

cap09.indd 206 1/11/2006 15:59:43

Page 199: Universidade VBA

Access 207

9capítulo

FnUndeleteQuery = True Application.RefreshDatabaseWindow

End If

End Function

Private Function FnCopyQuery(dbDatabase As DAO.Database, _ strSourceName As String, _ strDestinationName As String)

On Error GoTo ErrorHandler:

Dim qDefOld As DAO.QueryDef Dim qDefNew As DAO.QueryDef Dim Field As DAO.Field

Set qDefOld = dbDatabase.QueryDefs(strSourceName) Set qDefNew = dbDatabase.CreateQueryDef(strDestinatio

nName, qDefOld.SQL)

‘ Copia as propriedades de um filtro que for a excluído e que foi considerado apto para recuperação

FnCopyLvProperties qDefNew, qDefOld.Properties, qDefNew.Properties

For Each Field In qDefOld.Fields

‘ Copia as propriedades de cada campo individual-mente

FnCopyLvProperties qDefNew.Fields(Field.Name), _ Field.Properties, _ qDefNew.Fields(Field.Name).Properties Next Field

dbDatabase.QueryDefs.Refresh

FnCopyQuery = True

cap09.indd 207 1/11/2006 15:59:43

Page 200: Universidade VBA

208 universidade VBA

ExitFunction: Set qDefNew = Nothing Set qDefOld = Nothing

Exit Function

ErrorHandler: MsgBox “Erro. Recriando o filtro ‘” & strDestination-

Name & “’:” & vbCrLf & _ Err.Description & “ (“ & CStr(Err.Number) & “)” GoTo ExitFunction

End Function

Private Function PropExists(Props As DAO.Properties, _ strPropName As String) As Boolean

‘O módulo a seguir ignora os errosOn Error Resume Next

Dim Prop As DAO.Property

For Each Prop In Props

If Prop.Name = strPropName Then

PropExists = True Exit Function ‘ Short circuit

End If

Next Prop

PropExists = False

End Function

Private Sub FnCopyLvProperties(objObject As Object, _ OldProps As DAO.Properties, _

cap09.indd 208 1/11/2006 15:59:44

Page 201: Universidade VBA

Access 209

9capítulo

NewProps As DAO.Properties)

On Error Resume Next

Dim Prop As DAO.Property Dim NewProp As DAO.Property

For Each Prop In OldProps

If Not PropExists(NewProps, Prop.Name) Then

If IsNumeric(Prop.Value) Then NewProps.Append objObject.CreateProperty(Prop.

Name, _

Prop.Type, _

CLng(Prop.Value)) Else NewProps.Append objObject.CreateProperty(Prop.

Name, _

Prop.Type, _

Prop.Value) End If

Else

With NewProps(Prop.Name)

.Type = Prop.Type .Value = Prop.Value

End With

End If

Next Prop

cap09.indd 209 1/11/2006 15:59:44

Page 202: Universidade VBA

210 universidade VBA

End Sub

Private Function FnGetDeletedTableNameByProp(strRealTableName As String) _

As String

On Error Resume Next

Dim i As Long Dim strNameMap As String

strNameMap = CurrentDb.TableDefs(strRealTableName).Properties(“NameMap”)

strNameMap = Mid(strNameMap, 23) ‘Offset of the table name...

i = 1 If Len(strNameMap) > 0 Then

While (i < Len(strNameMap)) And (Asc(Mid(strNameMap, i)) <> 0)

i = i + 1

Wend

End If

FnGetDeletedTableNameByProp = Left(strNameMap, i - 1)

End Function

Option Explicit

Atribuição de IPs via Access

O endereço IP é um número de 32 bits em IPv4 (versão 4 do IP) e está associado a um único sistema ligado à rede. Para simplificar, esses números são divididos em

cap09.indd 210 1/11/2006 15:59:44

Page 203: Universidade VBA

Access 211

9capítulo

quatro octetos e escritos em formato decimal (com ponto). Todas as máquinas loca-lizadas em uma rede possuem endereços IP, assim como as máquinas que acessam a Internet.

No projeto a seguir desenvolvemos uma ferramenta que permite a atribuição de um endereço IP à máquina local utilizando VBA, a partir de um front-end Access.

Option Compare DatabaseOption Explicit

Type IPINFO dwAddr As Long ‘ IP address dwIndex As Long ‘ interface index dwMask As Long ‘ subnet mask dwBCastAddr As Long ‘ broadcast address dwReasmSize As Long ‘ assembly size Reserved1 As Integer Reserved2 As IntegerEnd Type

Public Function ConvertIPAddressToString(longAddr As Long) As String

Dim IPBytes(3) As Byte Dim lngCount As Long ‘ Converte um endereço IP no formato longo ou hexade-

cimal para a string to a string formatada 255.255.255.255 CopyMemory IPBytes(0), longAddr, 4 ‘ IP Address is sto-

red in four bytes (255.255.255.255) ‘ Converte o valor de 4 bytes para o mesmo formato de

string While lngCount < 4 ConvertIPAddressToString = ConvertIPAddressToString + _ CStr(IPBytes(lngCount)) + _ IIf(lngCount < 3, “.”, “”) lngCount = lngCount + 1

cap09.indd 211 1/11/2006 15:59:44

Page 204: Universidade VBA

212 universidade VBA

Wend End Function

Public Sub GetIPAddresses(Optional blnFilterLocalhost As Boolean = False)

Dim Ret As Long, Tel As Long Dim bytBuffer() As Byte Dim IPTableRow As IPINFO Dim lngCount As Long Dim lngBufferRequired As Long Dim lngStructSize As Long Dim lngNumIPAddresses As Long Dim strIPAddress As String

On Error GoTo ErrorHandler: Call GetIpAddrTable(ByVal 0&, lngBufferRequired, 1)

If lngBufferRequired > 0 Then ReDim bytBuffer(0 To lngBufferRequired - 1) As Byte If GetIpAddrTable(bytBuffer(0), lngBufferRequired, 1)

= 0 Then ‘ Mostra detalhes do endereço de IP atual e

da troca de IP lngStructSize = LenB(IPTableRow) CopyMemory lngNumIPAddresses, bytBuffer(0), 4 While lngCount < lngNumIPAddresses CopyMemory IPTableRow, _ bytBuffer(4 + (lngCount *

lngStructSize)), _ lngStructSize

cap09.indd 212 1/11/2006 15:59:44

Page 205: Universidade VBA

Access 213

9capítulo

strIPAddress = ConvertIPAddressToString (IPTableRow.dwAddr)

If Not ((strIPAddress = “127.0.0.1”) _ And blnFilterLocalhost) Then Debug.Print strIPAddress End If lngCount = lngCount + 1 Wend End If End If

Exit Sub

ErrorHandler: MsgBox “Ocorreu um erro em GetIPAddresses():” & vbCrLf

& vbCrLf & _ Err.Description & “ (“ & CStr(Err.Number) & “)”

End Sub

Option Explicit

Interligando Access e Outlook via VBA

Nosso último projeto interliga o Access ao Outlook, permitindo o envio de e-mails de dentro da interface deste último. O Outlook é o serviço de agenda e gerencia-mento de e-mails do Office, sendo talvez o aplicativo desse tipo mais utilizado no planeta. O problema do Outlook, no entanto e justamente, está na sua aplicação em conjunto com bancos de dados: para quem trabalha com uma base de dados para a qual precisa enviar e-mails, torna-se complexo abrir o Outlook e digitar cada e-mail. Além disso, o Outlook não é auto-gerenciável: se você não configurar as pastas cor-

cap09.indd 213 1/11/2006 15:59:44

Page 206: Universidade VBA

214 universidade VBA

retamente, os e-mails enviados e recebidos “caem em qualquer lugar”. Um pequeno problema para quem utiliza e-mails em casa, mas uma grande confusão para quem precisa trabalhar.

Private Sub Application _ Startup()

End Sub

‘ FnSendMailSafe é o nome que daremos à engine de criação e envio de e-mails

Public Function FnSendMailSafe(strTo As String, _ strCC As String, _ strBCC As String, _ strSubject As String, _ strMessageBody As String, _ Optional strAttachments As String)

As Boolean

On Error GoTo ErrorHandler:

Dim MAPISession As Outlook.NameSpace Dim MAPIFolder As Outlook.MAPIFolder Dim MAPIMailItem As Outlook.MailItem Dim oRecipient As Outlook.Recipient Dim TempArray() As String Dim varArrayItem As Variant Dim blnSuccessful As Boolean

‘ Criamos o objeto MAPI NameSpace Set MAPISession = Application.Session If Not MAPISession Is Nothing Then

‘ Logon na sessão MAPI MAPISession.Logon , , True, False

‘ Criamos um ponto de acesso a um diretório do Outlook

cap09.indd 214 1/11/2006 15:59:44

Page 207: Universidade VBA

Access 215

9capítulo

Set MAPIFolder = MAPISession.GetDefaultFolder(olFolder-Outbox)

If Not MAPIFolder Is Nothing Then

‘ Criamos um novo objeto (e-mail) no diretório Outlook, anteriormente criado

Set MAPIMailItem = MAPIFolder.Items.Add(olMailItem) If Not MAPIMailItem Is Nothing Then With MAPIMailItem

‘ Criação do destinatário TO TempArray = Split(strTo, “;”) For Each varArrayItem In TempArray Set oRecipient = .Recipients.Add(CStr(

Trim(varArrayItem))) oRecipient.Type = olTo Set oRecipient = Nothing Next varArrayItem ‘ Criação dos destinatários CC TempArray = Split(strCC, “;”) For Each varArrayItem In TempArray Set oRecipient = .Recipients.Add(CStr(

Trim(varArrayItem))) oRecipient.Type = olCC Set oRecipient = Nothing Next varArrayItem ‘ Criação dos destinatários BCC TempArray = Split(strBCC, “;”) For Each varArrayItem In TempArray Set oRecipient = .Recipients.Add(CStr(

Trim(varArrayItem)))

cap09.indd 215 1/11/2006 15:59:45

Page 208: Universidade VBA

216 universidade VBA

oRecipient.Type = olBCC Set oRecipient = Nothing Next varArrayItem ‘ Definimos o assunto ou SUBJECT .Subject = strSubject ‘ Definimos o corpo da mensagem ou BODY (HTML

ou texto plano) If StrComp(Left(strMessageBody, 6), “<HTML>”,

vbTextCompare) = 0 Then .HTMLBody = strMessageBody Else .Body = strMessageBody End If

‘ Adiciona anexos à mensagem, se assim for especificado

TempArray = Split(strAttachments, “;”) For Each varArrayItem In TempArray .Attach m ents.Add

CStr(Trim(varArrayItem)) Next varArrayItem

.Send

Set MAPIMailItem = Nothing End With

End If

Set MAPIFolder = Nothing End If

MAPISession.Logoff

cap09.indd 216 1/11/2006 15:59:45

Page 209: Universidade VBA

Access 217

9capítulo

End If ‘ Se tudo funcionou cortretamente, basta apertar OK. blnSuccessful = True ExitRoutine: Set MAPISession = Nothing FnSendMailSafe = blnSuccessful Exit Function ErrorHandler: MsgBox “Um erro ocorreu em Outlook VBA function

FnSendMailSafe()” & vbCrLf & vbCrLf & _ “Error Number: “ & CStr(Err.Number) & vbCrLf

& _ “Error Description: “ & Err.Description,

vbApplicationModal + vbCritical Resume ExitRoutine

End Function

cap09.indd 217 1/11/2006 15:59:45

Page 210: Universidade VBA

cap09.indd 218 1/11/2006 15:59:45

Page 211: Universidade VBA

Apêndice

ap01.indd 219 1/11/2006 16:00:37

Page 212: Universidade VBA

220 universidade VBA

Referências a células e intervalos

Comando: Range(“A1”).Sintaxe: Range (“Célula”).Utilização: define uma única célula como objeto de um comando ou proprie-dade.Variáveis: não há variáveis.Exemplo: com Range(“A1”).Value = 1, definimos que a célula A1 terá valor True (Verdadeiro) ou 1.Veja também: Range(“A1:B5”).

Comando: Range(“A1:B5”).Sintaxe: Range(“célula”:”célula”).Utilização: define um intervalo de células como objeto de um comando ou pro-priedade.Variáveis: não há variáveis.Exemplo: em Range(“A1:C12”).Value = 1 definimos que o intervalo de células entre A1 e C12 é True (Verdadeiro) ou 1.Veja também: Range(“1:5”) e AllowEditRanges.

Comando: Range com seleção de várias áreas.Sintaxe: Range(“célula:célula,célula:célula”).Utilização: define uma seleção de várias áreas (células) como objeto de um comando ou propriedade.Variáveis: não há variáveis.Exemplo: Range(“A1:C12”,C118:D27,E1:F18).Veja também: Range de linhas alternado e Range(“A1:B5”).

Comando: Range de coluna.Sintaxe: Range(“Letra da Coluna:Letra da Coluna”).Utilização: define um intervalo de colunas para utilização de um comando ou propriedade.Variáveis: não há variáveis.Exemplo: Private Sub CommandButton1 _ Click() Columns(“D:D”) End SubEsse comando define que será criado um botão para ativar a coluna D.Veja também: Range(“A:A”) e Range de linhas.

ap01.indd 220 1/11/2006 16:00:37

Page 213: Universidade VBA

Apêndice 221

apêndice

Comando: Range de linha.Sintaxe: Range(“Número da linha:Número da linha”).Utilização: define uma única linha para utilização de um comando ou pro-priedade.Variáveis: não há variáveis.Exemplo: Range(“1:1”).Veja também: Range de linhas alternado e Range de linha.

Comando: Range para intervalo de colunas.Sintaxe: Range(“coluna inicial:coluna final”).Utilização: define um intervalo de colunas como objeto de um comando ou pro-priedade.Variáveis: não há variáveis.Exemplo: Sub Teste() Range(“A:E”).End(xldown).Select End SubEsse comando seleciona todas as colunas de A até E presentes em uma planilha do Excel.Veja também: Range de linhas.

Comando: Range de intervalo de linhas.Sintaxe: Range(“coluna 1:coluna 2”).Utilização: define um intervalo de várias linhas como objeto de um comando, propriedade ou método. Variáveis: não há variáveis.Exemplo: Sub Linhas() Range(“1:10”).End(xlup).Select End SubEsse comando seleciona todas as linhas de 1 a 10 presentes em uma planilha do Excel.Veja também: Range de colunas e Sub.

Comando: Range de linhas avulsas.Sintaxe: Range(“primeiro intervalo de linhas,segundo intervalo de linhas,terceiro intervalo de linhas”).Utilização: define diversos intervalos de linhas, ou de linhas avulsas, como objeto de um comando, variável ou método.Variáveis: não há variáveis.

ap01.indd 221 1/11/2006 16:00:37

Page 214: Universidade VBA

222 universidade VBA

Exemplo: Sub Range de linhas avulsas() Range(“1:19,23, 30:45”).End(xlToRight).Select End SubVeja também: Range de intervalo de linhas.

Comando: Range de colunas avulsas.Sintaxe: Range(“coluna 1,coluna 2,coluna 3”).Utilização: define diversos intervalos de colunas, ou de colunas avulsas, como objeto de um comando, variável ou método.Variáveis: não há variáveis.Exemplo: Sub LastCellInColumn() Range(“A:C,F:S”).End(xlToLeft).Select End SubEsse comando indica qual foi a última coluna utilizada nos intervalos de colunas de A a C e de F a S.Veja também: Range de linhas avulsas.

Comando: Range de células pelo número de índice.Sintaxe: Worksheets(“Nome da Planilha”).Cells(<linha>, <co-luna>).Utilização: utilizada para fazer com que um intervalo de células seja definido por meio de um número de índice, em vez de se utilizar coordenadas exatas.Variáveis: não há variáveis.Exemplo: Sub Índice() Worksheets(“Digerati”)”).Cells(2,5) End SubEsse comando faz com que a célula dois da coluna E da planilha Digerati seja selecionada.Veja também: Worksheets.

Comando: Rows.Sintaxe: [Worksheets(“<Nome da Planilha”)].Rows[(<Número da Linha>)] = True End SubUtilização: seleciona, para a operação, uma, várias ou todas as linhas da pla-nilha.Variáveis: • (<número da linha>): define uma linha específica para a aplicação do comando;

ap01.indd 222 1/11/2006 16:00:37

Page 215: Universidade VBA

Apêndice 223

apêndice

• Worksheets: se Worksheet não é definido antes de Rows, o comando será utilizado na planilha ativa, e não em uma planilha específica.Exemplos: 1. Sub RowBold() Worksheets(“Digerati”).Rows(2).Font.Bold = True End SubCom esse comando, transformamos o conteúdo de toda a segunda linha em negrito.

2. Sub Rows() Worksheets(“Digerati”).Rows.Font.Bold = True End SubEsse comando transforma todas as linhas da planilha Digerati em negrito.Veja também: Columns.

Comando: Columns.Sintaxe: [Worksheets(“<Nome da Planilha”)].Columns [(<número da coluna ou letra da coluna>)].Utilização: seleciona todas as colunas de uma planilha, ou uma determinada coluna.Variáveis: • (<número ou letra da coluna>): define uma determinada coluna para aplicação do comando;• Worksheets: se Worksheet não for definido antes de Columns, o comando será utilizado na planilha ativa, e não em uma planilha específica.Exemplo: Private Sub CommandButton1 _ Click() Columns(“D”) End SubCom esse comando, criamos um botão que ativa a coluna D da planilha atual.Veja também: Worksheets e Rows.

Comando: Union.Sintaxe: Union([Rows/Columns](numero-coordenada do elemento), ([Rows/Columns] (numero-coordenada do elemento), ([Rows/Columns] (numero-coordenada do elemento)).Utilização: para trabalhar com várias linhas ou colunas ao mesmo tempo, crie uma variável de objeto e use o método Union, combinando várias chamadas para as propriedades Rows ou Columns.

ap01.indd 223 1/11/2006 16:00:38

Page 216: Universidade VBA

224 universidade VBA

Variáveis: • Row: define que uma linha será selecionada;• Column: define que uma coluna será selecionadaExemplo: Sub TestUnion() Worksheets(“Digerati”).Activate Dim myUnion As Range Set myUnion = Union(Rows(1), Rows(3), Rows(5)) myUnion.Font.Bold = True End SubCom esse comando, ativamos a planilha Digerati e formatamos em negrito as linhas 1, 3 e 5.Veja também: Column e Rows.

Comando: atalho de Range.Sintaxe: [(célula inicial:célula final].Utilização: Pode-se usar o estilo de referência A1 ou um intervalo nomeado entre colchetes como um atalho para a propriedade Range. Pode-se, também, selecionar as células na planilha atual e criar a referência no código, atribuindo-lhe um nome entre colchetes.Variáveis: não há variáveis.Exemplo: Sub ClearRange() Worksheets(“Digerati”).[A1:B5].ClearContents End SubEsse comando limpa o conteúdo das células A1 e B5 da planilha Digerati.Veja também: Range.

Comando: intervalos nomeados.Sintaxe: Range(“Nome da Planilha.xls!Nome do range”).Utilização: nomeia um intervalo selecionado substituindo as coordenadas de células por um nome fantasia. Para efetuar a ação, selecione as células da planilha e, em seguida, clique na caixa na extremidade esquerda da barra de fórmulas. Digite um nome e, logo após, pressione Enter. Para evocar o intervalo nomeado, utilize o nome deste entre colchetes no código.Variáveis: não há variáveis.Exemplo: 1. Sub SetValue() [MyRange].Value = 1 End Sub

ap01.indd 224 1/11/2006 16:00:38

Page 217: Universidade VBA

Apêndice 225

apêndice

Esse comando define o valor do Range com nome fantasia (lembre-se de co-locar entre colchetes) como 1.

2. Sub FormatRange() Range(“Digerati.xls!MyRange”).Font.Italic = True End SubEsse comando acessa o valor de Range a partir do intervalo selecionado na planilha Digerati.xls.Veja também: Ranges.

Comando: Offset.Sintaxe: [coordenada atual] Offset([-][linha],[-][coluna]) .Utilização: faz com que o conteúdo da célula que está em um determinado número de linhas ou colunas de uma coordenada fixa, ou da célula atualmente ativa, sofra uma determinada ação.O padrão impõe que as coordenadas são definidas de cima para baixo e da esquerda para a direita.Variáveis: • [coordenada atual]: define a localização que deve ser estabelecida como ponto de partida para a montagem da coordenada;• linha: indica que a coordenada será definida após um certo número de linhas;• coluna: indica que a coordenada será definida após um certo número de colunas;• - (sinal de menos): indica que a coordenada será acessada de baixo para cima, ou da direita para a esquerda.Exemplo: ActiveCell.Offset(-3, -2).Range(“A1:C4”).Select.Esse comando faz com que seja selecionada a célula localizada três linhas acima e duas colunas à direita da célula ativa, se ela estiver no intervalo de células A1:C4; o que faz com que o comando não seja executado se a célula-coordenada não pertencer a esse intervalo.Veja também: Worksheets.

Comando: Select.Sintaxe: Sheets [(“Nome da planilha”)][Range (valor do ran-ge)].Select.Utilização: o método Select ativa planilhas e objetos em planilhas, incluindo células e intervalos.

ap01.indd 225 1/11/2006 16:00:38

Page 218: Universidade VBA

226 universidade VBA

Variáveis: • ”Nome da planilha”: é preciso especificar um nome de planilha para que a seleção seja efetuada, mesmo se desejar selecionar algo na planilha atual;• Range: define o intervalo que será selecionado na planilha. Exemplo: Sub Macro1() Sheets(“Digerati”).Select Range(“A1”).Select Range(“B1”).Select End SubEsse comando seleciona as células A1 e B1 da planilha Digerati.Veja também: Sheets e Range.

Comando: Selection.Sintaxe: Selection.[variável].[método].Utilização: a propriedade Selection retorna um objeto que representa a seleção atual na planilha ativa da pasta de trabalho atual. Antes de utilizar a propriedade Selection, é necessário ativar uma pasta de trabalho, ativar ou selecionar uma planilha e, em seguida, selecionar um intervalo. Selection costuma ser utilizado em conjunto com Select.Variáveis: • variável: define a variável de um determinado objeto e que será alterada pela aplicação de Selection ;• método: define o método que será aplicado em uma determinada variável.Exemplo: Sub TesteSelection() Sheets(“Digerati”).Select Range(“A1”).Select Range(“C1:D10”).Select Range(“E1:E10”).Select Selection.Font.Italic = True End SubEsse comando faz com que todos os intervalos declarados para a planilha Digerati sejam selecionados e, e em seguida, estabelece que o conteúdo dessa seleção será formatado em itálico.Veja também: Range e Sheets.

Comando: Areas.Sintaxe: Selection.Areas.[propriedade] [condicional].Utilização: retorna uma coleção Areas do tipo somente leitura (não pode ser gravada ou alterada no código do aplicativo ou no script), representando

ap01.indd 226 1/11/2006 16:00:38

Page 219: Universidade VBA

Apêndice 227

apêndice

todos os intervalos em uma seleção de várias áreas. Para uma única seleção é retornado o próprio Range original.Variáveis: • propriedade: define a propriedade que será aplicada ao comando;• condicional: em alguns casos, deve-se definir uma condição para a aplica-ção da propriedade atrelada ao comando. Essa condicional pode utilizar funções booleanas, como True (Verdadeiro) ou False (Falso) e 0 ou 1, ou utilizar parâmetros de comparação utilizando símbolos matemáticos (<, >, =).Exemplo: If Selection.Areas.Count < 1 Then MsgBox “Copie o conteúdo dessas células.” End IfO exemplo exprime uma condição utilizando If (se). Se a seleção de determi-nadas áreas da planilha possuir algo (ou seja, se existir uma seleção com vários intervalos e estes estiverem ocupados) é enviada para a tela a caixa de mensagem (MsgBox) avisando que esse conteúdo deve ser copiado.Veja também: Selection e MsgBox.

Comando: For...Next.Sintaxe: For [CÓDIGO] Cells NextUtilização: utilizado para criar loops (repetições de um comando) em um mesmo intervalo de células. O retorno é feito combinando uma instrução de loop com um ou mais métodos para identificar as células, uma de cada vez.Usando a propriedade Cells, você pode substituir o contador do loop (ou outras variáveis e expressões) pelos números de índice das células. Variáveis: não há variáveis.Exemplo: Sub CheckValues1() Dim rwIndex As Integer Dim colIndex As Integer For rwIndex = 1 To 10 For colIndex = 1 To 5 If Cells(rwIndex, colIndex).Value <> 0 Then _ Cells(rwIndex, colIndex).Value = 0 Next colIndex Next rwIndex End SubEsse comando checa os valores de um determinado grupo de células – todas as localizadas entre as linhas um e dez e as colunas um a cinco da planilha atual.

ap01.indd 227 1/11/2006 16:00:39

Page 220: Universidade VBA

228 universidade VBA

Note que foram criados os ranges rwIndex e collIndex com os intervalos de linhas e colunas, e foi esse o valor atribuído a Cells. Veja também: Range, Column e Rows.

Comando: For Each...Next.Sintaxe: For Each [CÓDIGO] Range NextUtilização: efetua um loop por um intervalo, fazendo com que a coleção de células seja retornada pela propriedade Range. O Visual Basic define auto-maticamente uma variável de objeto para a próxima célula sempre que o loop é executado.Variáveis: não há variáveis.Exemplo: Sub Teste2() For Each c In Worksheets(“Digerati”).Range(“A1:D10”).Cells If Abs(c.Value) < 0.01 Then c.Value = 0 Next End SubEsse comando faz um loop a partir do intervalo A1:D10, definindo como 0 qualquer valor menor que 0.01.Veja também: Sub e For...Next.

Comando: CurrentRegion.Sintaxe: For [CÓDIGO]ActiveCell.CurrentRegion.Cells If [CONDICIONAL] Next Utilização: se você não souber os limites do intervalo no qual deseja fazer o loop, pode usar a propriedade CurrentRegion para retornar o intervalo que envolve a célula ativa na planilha. Variáveis: não há variáveis.Exemplo: Sub TestedeLoop Dim i AsInteger

For i = 1 To Selection.CurrentRegion.Rows.Count - 1

ActiveCell.FormulaR1C1 = “=Average(RC[-1],RC[-2])”

ActiveCell.Offset(1, 0).Select

ap01.indd 228 1/11/2006 16:00:39

Page 221: Universidade VBA

Apêndice 229

apêndice

Next i

End SubVeja também: Worksheets.

Comando: Activate.Sintaxe: Worksheet [(“Nome da planilha”)]. Activate Range [“Intervalo de Range”].Select Range(“Célula de range”).SelectUtilização: pode-se utilizar o método Activate para ativar uma célula em uma seleção. Apenas uma célula por vez pode ser ativada.Variáveis:• ”Nome da planilha”: é preciso definir um nome para a planilha, entre aspas, para ativá-la;• ”Intervalo de Range”: deve-se definir um intervalo de células entre aspas, no estilo ”A1:A40” (célula inicial, dois pontos, células finais);• ”Célula de Range”: a célula (única) que será ativada utilizando Se-lect. Exemplo: Worksheet(“Digerati.xls”).Activate Range(“A1:A100”).Select Selection.End(xlDown).Select Activate Range(“A1:A100”).SelectVeja também: Range e Worksheet.

Comando: ActiveCell.Sintaxe: Worksheets(“Nome da planilha”).Activate ActiveCell.Value = [VALOR DA CÉLULA]Utilização: essa propriedade retorna um objeto Range representando a célula ativa. É possível aplicar qualquer propriedade ou método de um objeto Range à célula ativa.Variáveis: não há variáveis.Exemplo: Sub TestInRange() If InRange(ActiveCell, Range(“A1:D100”)) Then MsgBox “Célula ativa!” Else MsgBox “Célula não está ativa!” End If End Sub

ap01.indd 229 1/11/2006 16:00:39

Page 222: Universidade VBA

230 universidade VBA

Esse comando define que deve ser mostrada a primeira mensagem caso exista uma cé-lula ativa no intervalo entre A1 e D100. Se há uma célula ativa, mas fora desse intervalo, ou não há célula alguma, deve ser retornada a mensagem Célula não está ativa!.Veja também: MsgBox e Sub.

Procedimentos

Comando: Sub.Sintaxe: Sub [NOME DO PROCEDIMENTO] [( )] [CÓDIGO] End SubUtilização: um procedimento Sub é uma série de instruções do Visual Basic, colocada entre Sub e End Sub, capaz de executar ações (começar e terminar uma instrução), mas não de retornar um valor. Um procedimento Sub pode utilizar argumentos, como constantes, variáveis ou expressões, submetidos a um procedimento de chamada. Caso um procedimento Sub não tenha argumentos, a instrução Sub deve incluir um conjunto de parênteses vazios.Variáveis: ( ): utilizada para indicar que um procedimento Sub não possui argumentos.Exemplo: Sub VerSub() Charts.Add ActiveChart.ChartType = xlXYScatterLines ActiveChart.SetSourceData Source:=Sheets (“Sheet1”).Range(“A3:G14”) ActiveChart.Location Where:=xlLocationAsObject, Name:=”Sheet1” End SubVeja também: Function.

Comando: Function.Sintaxe: Function [NOME DA FUNÇÃO] [( )] [FUNÇÃO] End FunctionUtilização: um procedimento Function é uma série de instruções do Visual Basic colocadas entre as instruções Function e End Function. Um procedi-mento Function é semelhante a um procedimento Sub, com a diferença de que uma função pode retornar um valor. Um procedimento Function pode utilizar argumentos, como constantes, variáveis ou expressões, transmitidos a ele por um

ap01.indd 230 1/11/2006 16:00:39

Page 223: Universidade VBA

Apêndice 231

apêndice

procedimento de chamada. Caso um procedimento Function não tenha argu-mentos, sua instrução Function deve incluir um conjunto de parênteses vazio.Variáveis: ( ): utilizada para indicar que a função não possui argumentos.Exemplos: 1. Function Area() End FunctionEsse comando define que a função Area será utilizada no meio do código, sem a adição de argumentos.

2. Function Area(Length As Double, Width As Double) Area = Length * Width End FunctionEsse comando declara a função Area utilizando argumentos, para que seja feita a multiplicação da largura pelo comprimento.Veja também: Areas e Sub.

Comando: Property>.Sintaxe: [Public | Private] [Static] Property {Get | Let | Set} nome _ da _ propriedade (arguments)] [As type] instruções End PropertyUtilização: o procedimento Property constitui uma série de instruções do Visual Basic que permitem que um programador crie e manipule propriedades personalizadas. Os procedimentos Property podem ser utilizados para criar propriedades do tipo “somente leitura” para formulários, módulos-padrão e módulos de classe.Ao criar um procedimento Property, ele torna-se uma propriedade do módulo que contém o procedimento. O Visual Basic fornece três tipos de procedimentos Property apresentados a seguir:

Procedimento

Property LetProperty GetProperty Set

Descrição

Procedimento que define o valor de uma propriedade.Procedimento que retorna o valor de uma propriedade.Procedimento que define a referência de um objeto.

Tabela Ap. 1.

Geralmente, os procedimentos Property são utilizados em pares: Property Let com Property Get e Property Set com Property Get. A decla-

ap01.indd 231 1/11/2006 16:00:40

Page 224: Universidade VBA

232 universidade VBA

ração de apenas um procedimento Property Get corresponde à declaração de uma propriedade do tipo somente leitura.Variáveis: • Public: indica que a propriedade poderá ser utilizada em todos os proce-dimentos, em todos os módulos e em quaisquer aplicativos; • Private: impede que o conteúdo de um módulo seja referenciado fora do projeto;• Static: as variáveis declaradas com a instrução Static retêm os valores desde que o código esteja sendo executado;• Get: declara o nome, os argumentos e o código que formam o corpo de um procedimento Property, que obtém o valor de uma propriedade;• Let: atribui um valor a uma propriedade;• Set: atribui uma referência de objeto a uma variável ou propriedade.Exemplo: ‘ Primeiro definimos as constantes que serão uti-lizadas no código.

Dim CorAtual As IntegerConst BLACK = 0, RED = 1, GREEN = 2, BLUE = 3

‘ Retorna a cor como uma seqüênciaProperty Get TestColor() As String Select Case CorAtual Case RED TestColor = “Vermelho” Case GREEN TestColor = “Verde” Case BLUE TestColor = “Azul” End SelectEnd PropertyVeja também: Select.

Propriedades

Comando: AddIns.Sintaxe: If AddIns(“Nome do objeto”).Installed = [VALOR] Then.

ap01.indd 232 1/11/2006 16:00:40

Page 225: Universidade VBA

Apêndice 233

apêndice

Utilização: retorna uma coleção AddIns representando todos os suplementos listados na caixa de diálogo Suplementos (menu Ferramentas do Excel). É do tipo somente leitura, ou seja, a listagem não pode ser alterada por código VBA.Variáveis: • valor: utilizam-se aqui os valores booleanos. É possível utilizar True (Verda-deiro) ou False (Falso).Exemplo: If AddIns(“Analysis ToolPak”).Installed = True Then MsgBox “Analysis ToolPak add-in está instalado” Else MsgBox “Analysis ToolPak add-in não está instalado” End IfVeja também: MsgBox.

Comando: AllowEditRanges.Sintaxe: [expressão].AllowEditRanges. Utilização: depois que a coleção AllowEditRanges é retornada, podemos usar o método Add para adicionar um intervalo que pode ser editado em uma planilha protegida.Variáveis: expressão, que retorna um dos objetos da lista utilizada. Exemplo: Sub UseAllowEditRanges()

Dim wksOne As Worksheet Dim strPwd1 As String

Set wksOne = Application.ActiveSheet

strPwd1 = InputBox(“Enter Password”)

‘ Desprotege a planilha. wksOne.Unprotect

‘ Estabelece o intervalo que será editado na plani-lha protegida. wksOne.Protection.AllowEditRanges.Add _ Title:=”Classified”, _ Range:=Range(“A1:A4”), _ Password:=strPwd1

ap01.indd 233 1/11/2006 16:00:40

Page 226: Universidade VBA

234 universidade VBA

‘ Notifica ao usuário o título e o endereço do in-tervalo. With wksOne.Protection.AllowEditRanges.Item(1) MsgBox “Título do intervalo: “ & .Title MsgBox “Endereço do intervalo: “ & .Range.Address End With

End SubVeja também: MsgBox e Areas.

Comando: Border.Sintaxe: expressão.Border.Utilização: representa as opções de visibilidade da borda do objeto. Variáveis: expressão, necessária para a execução do comando. Ela retorna um objeto CallFormat, caso esteja operando com ele, ou ainda qualquer outro que esteja sendo utilizado.Exemplo: Charts(“Chart1”).ChartArea.Border.ColorIndex = 3.Veja também: FormatCondicitions.

Comando: CalculatedMembers.Sintaxe: expressão.CalculatedMembers.Utilização: retorna uma coleção CalculatedMembers, que representa todos os membros e medidas calculados para uma tabela dinâmica OLAP.Variáveis: expressão, necessária para a execução do comando. Expressão que retorna um objeto PivotTable, que por sua vez apresenta um relatório de tabela dinâmica em uma planilha.Exemplo: Sub UseCalculatedMember()

Dim pvtTable As PivotTable

Set pvtTable = ActiveSheet.PivotTables(1)

‘ Adiciona o cálculo de um membro à planilha. pvtTable.CalculatedMembers.Add Name:=”[Beef]”, _ Formula:=”’{[Product].[All Products].Children}’”, _ Type:=xlCalculatedSet

End SubVeja também: AllowEditRanges.

ap01.indd 234 1/11/2006 16:00:40

Page 227: Universidade VBA

Apêndice 235

apêndice

Comando: Caption.Sintaxe: objeto.Caption [= Seqüência].Utilização: texto descritivo que aparece em um objeto para identificá-lo ou descrevê-lo.Variáveis:• objeto: variável obrigatória. Trata-se de um objeto válido;• Seqüência: variável opcional. Trata-se de uma expressão de seqüência que considera o texto exibido como legenda.Exemplo: Private Sub optEuro _ Click() lblDevise1.Caption = “BEF” lblDevise2.Caption = “EUR” CalculEnd Sub

Private Sub optBEF _ Click() lblDevise1.Caption = “EUR” lblDevise2.Caption = “BEF” CalculEnd Sub

Sub Calcul() If IsNumeric(txtMontant) Then If optEuro Then lblResultado.Caption = Arrondi(txtMontant / 40.3399, 2) Else lblResultado.Caption = Arrondi(txtMontant * 40.3399, 0) End If Else MsgBox “O montante não é numérico!” txtMontante.SetFocus End IfEnd SubEsse exemplo mostra a criação de várias legendas utilizando o comando Caption.Veja também: MsgBox e CustomProperties.

Comando: ChartType.Sintaxe: expressão.ChartType.Utilização: retorna ou define o tipo de gráfico XlChartType de leitura/gra-vação.

ap01.indd 235 1/11/2006 16:00:41

Page 228: Universidade VBA

236 universidade VBA

Variáveis: expressão, necessária para a execução do código. Retorna um dos objetos aplicáveis à propriedade.Exemplo: Sub Dia _ top10() Charts.Add ActiveChart.ChartType = xlBubble For i = 1 To 10 ActiveChart.SeriesCollection.NewSeries ActiveChart.SeriesCollection(i).XValues = Tabela1.Cells(1 + i, 124) ActiveChart.SeriesCollection(i).Values = Tabela1.Cells(1 + i, 125) ActiveChart.SeriesCollection(i).Name = Tabela1.Cells(1 + i, 123) ActiveChart.SeriesCollection(i).BubbleSizes = Tabela1.Cells(1 + i, 126) Next End SubVeja também: Dialogs.

Comando: Chart.Sintaxe: Objeto(“Nome do Objeto”).ChartObjects(1).Chart.Utilização: retorna um objeto Chart representando o gráfico armazenado no objeto. É do tipo somente leitura.Variáveis: não há variáveis.Exemplo: Sub MostraChart() Set MyChart = ActiveSheet.ChartObjects(1).Chart Set xv = GetChartRange(MyChart, 2, “xvalues”) Set v = GetChartRange(MyChart, 2, “values”) SeriesRange = xv.Address ValuesRange = v.Address Range(SeriesRange, ValuesRange).Select End SubVeja também: PivotTables.

Comando: Comments.Sintaxe: [CÓDIGO] ActiveSheet.Comments.Utilização: retorna uma coleção Comments representando todos os comentários de células encontrados na planilha especificada. É do tipo somente leitura, ou seja, não faz alterações nos comentários das células.

ap01.indd 236 1/11/2006 16:00:41

Page 229: Universidade VBA

Apêndice 237

apêndice

Variáveis: não há variáveis.Exemplo: For Each c in ActiveSheet.Comments If c.Author = “Tadeu Carmona” Then c.DeleteNextO exemplo exclui todos os comentários feitos na planilha ativa que tiveram como autor o usuário Tadeu Carmona.Veja também: ActiveSheet.

Comando: CubeFields.Sintaxe: Worksheets(“Nome da planilha”).[objeto](1).CubeFields.Utilização: retorna a coleção CubeFields. Cada objeto CubeField contém as propriedades do elemento de campo cubo. É do tipo somente leitura. Os objetos CubeFields são representados em um relatório de tabela dinâmica, baseado em um cubo OLAP. Cada objeto CubeField representa um campo de hierarquia ou medida do cubo.Variáveis: não há variáveis.Exemplo: Sub Macro1()With ActiveWorkbook.PivotCaches.Add(SourceType:=xlExter nal).Connection = _“OLEDB;Provider=MSOLAP.2;Data Source=sha-tadeu-01;Initial‘a contagem de dados começa a ser feita a partir do campo Tadeu da tabela dinâmica atualCatalog=FoodMart 2000;Client Cache Size=25;Auto Synch Pe-riod=10000”.CommandType = xlCmdCube.CommandText = Array(“Vendas”).MaintainConnection = True.CreatePivotTable TableDestination:=”[Book2]Sheet1!R1C1”,TableName:= _“PivotTable1”, DefaultVersion:=xlPivotTableVersion10End With‘a seguir, extraímos dados da tabela dinâmica atual, bus-cando especificamente os dados de estado civil, contidos em CubeFields da mesma tabela.With ActiveSheet.PivotTables(“PivotTable1”).CubeFields (“[Es-tado Civil]”).Orientation = xlColumnField.Position = 1End With

ap01.indd 237 1/11/2006 16:00:41

Page 230: Universidade VBA

238 universidade VBA

‘ Ocorre o mesmo, desta vez com as informações relacionadas ao Produto.With ActiveSheet.PivotTables(“PivotTable1”).CubeFields (“[Produto]”).Orientation = xlRowField.Position = 1End WithVeja também: ActiveSheet e FormatCondictions.

Comando: CustomProperties.Sintaxe: expressão.CustomProperties.Utilização: retorna um objeto CustomProperties, capaz de representar as informações do identificador associadas a uma planilha. CustomProper-ties pode ser utilizado para representar informações adicionais, incluindo metadados XML.Variáveis: expressão, necessária para a execução do comando. É preciso utili-zar uma expressão que retorna um dos objetos válidos para essa propriedade.Exemplo: Public Sub GetFileCustomDocumentProperty() MsgBox CreateObject(“DSOleFile.PropertyReader”).GetDocumentProperties(“C:\Arquivos\planilha.xls”).CustomProperties (“Somente Leitura”).ValueEnd SubVeja também: Panes.

Comando: DataLabel.Sintaxe: .HasDataLabel = <valor booleano>.ApplyDataLabels type:=xlValue .DataLabel.Font.ColorIndex = <valor numérico>Utilização: retorna um objeto DataLabel representando o rótulo de dados as-sociado ao ponto ou linha de tendência. É do tipo somente leitura.Variáveis: • valor booleano: pode ser True (Verdadeiro) ou False (Falso);• valor numérico: utilizado para definir um valor que corresponda a uma das cores utilizadas pela paleta do Office.Exemplo: With Charts(2).SeriesCollection(3).Points(7) .HasDataLabel = True .ApplyDataLabels type:=xlValue .DataLabel.characters.text = “Este é um exemplo de Data Label” End WithVeja também: Panes.

ap01.indd 238 1/11/2006 16:00:41

Page 231: Universidade VBA

Apêndice 239

apêndice

Comando: Dialogs.Sintaxe: (Objeto).Dialogs(Função).Show.Utilização: retorna uma coleção Dialogs representando todas as caixas de diálogo internas. A única utilidade de um objeto Dialog é ser usado com o método Show para exibir a caixa de diálogo correspondente. É uma opção do tipo somente leitura.Variáveis: • objeto: define o objeto (Application, Worksheet) no qual será utilizada a propriedade;• Função: define a função que será utilizada em conjunto com a propriedade Dialogs.Exemplo: Application.Dialogs(xlDialogOpen).ShowCom esse comando, abrimos uma caixa de diálogo na seção atual do Excel.Veja também: Panes.

Comando: Enabled.Sintaxe: objeto.Enabled [= Booleano].Utilização: utilize a propriedade Enabled para ativar e desativar controles. Um controle desativado aparece esmaecido, enquanto um controle ativado não. Além disso, se um controle exibir um bitmap, este ficará esmaecido sempre que o con-trole for definido como False (Falso). Se Enabled for False para um Image, o controle não iniciará eventos, mas também não aparecerá esmaecido.Variáveis: • objeto: define o objeto que será ativado pela propriedade;• booleano:• se definido como True, especifica que o controle está ativado; se for definido como False, especifica que o objeto está desativado.Exemplo: o exemplo seguinte, ao ser inserido em um formulário, habilita a caixa de verificação um e bloqueia a caixa de verificação dois:Private Sub CheckBox1 _ Change() TextBox2.Text = “TextBox2” TextBox1.Enabled = CheckBox1.ValueEnd Sub

Private Sub CheckBox2 _ Change() TextBox2.Text = “TextBox2” TextBox1.Locked = CheckBox2.ValueEnd Sub

ap01.indd 239 1/11/2006 16:00:42

Page 232: Universidade VBA

240 universidade VBA

Private Sub UserForm _ Initialize() TextBox1.Text = “TextBox1” TextBox1.Enabled = True TextBox1.Locked = False CheckBox1.Caption = “Enabled” CheckBox1.Value = True CheckBox2.Caption = “Locked” CheckBox2.Value = False TextBox2.Text = “TextBox2”End SubVeja também: DataLabel.

Comando: Errors.Sintaxe: expressão.Errors.Utilização: permite que o usuário acesse opções de verificação de erros. Variáveis: expressão, necessária para a execução do código. Expressão que retorna um dos objetos da lista Range utilizado em conjunto com a proprie-dade Errors.Exemplo: Sub CheckForErrors()‘Esta função checa erros em um determinado intervalo de células e retorna um erro na forma de uma caixa de mensagem, se o número identificado no código não for True(Verdadeiro). Range(“A1”).Formula = “’12”

If Range(“A1”).Errors.Item(xlNumberAsText).Value = True Then MsgBox “O número está presente no texto.” Else MsgBox “O número está presente no texto.” End If

End SubVeja também: Range, MsgBox e ListColumns.

ap01.indd 240 1/11/2006 16:00:42

Page 233: Universidade VBA

Apêndice 241

apêndice

Comando: Filters.Sintaxe: With .AutoFilter.Filters(1)[condicional]Utilização: retorna uma coleção Filters que representa todos os filtros em um intervalo auto-filtrado. É do tipo somente leitura.Variáveis: a variável condicional exibe a condicional (If), que ativa a utilização de um determinado filtro.Exemplo: o exemplo seguinte define uma variável com o valor da propriedade do filtro Digerati para a primeira coluna no intervalo filtrado da planilha Digerati:With Worksheets(“Digerati”) If .AutoFilterMode Then With .AutoFilter.Filters(1) If .On Then c1 = .Digerati End With End IfEnd WithVeja também: AutoFilter e Worksheets

Comando: FormatConditions.Sintaxe: Worksheets(número/nome da planilha).Range(“intervalo em caixa baixa”).FormatConditions(valor) _Utilização: retorna uma coleção FormatConditions representando todos os formatos condicionais para o intervalo especificado. É do tipo somente leitura.Variáveis:• Worksheets: indica o número da planilha (contando da esquerda para a direita) no qual está o intervalo que será utilizado. Também podemos utilizar diretamente o nome da planilha, ainda que a numeração seja mais confiável;• Range: define o intervalo que será objeto dos formatos condicionais;• FormatConditions: solicita a definição de um valor para utilização da propriedade.Utilize 1 se o formato for True (Verdadeiro).Exemplo: Selection.FormatConditions.Add Type:=xlExpression, Formula1:=”=FINDEN(“”sim C1)”Selection.FormatConditions(1).Font.ColorIndex = 3

Selection.FormatConditions.Add Type:=xlExpression, Formula1:=”=FINDEN(“”não C1)”Selection.FormatConditions(2).Font.ColorIndex = 3Veja também: Comments.

ap01.indd 241 1/11/2006 16:00:42

Page 234: Universidade VBA

242 universidade VBA

Comando: HPageBreaks.Sintaxe: [condicional] [objeto] .[ HPageBreaks].Utilização: retorna uma coleção HPageBreaks representando as quebras de página horizontais da planilha. Pode ser utilizado apenas como somente leitura. Além disso, há um limite de 1.026 quebras de página horizontais por planilha.Variáveis:• condicional: estabelece que para cada objeto especificado de acordo com o parâmetro definido deve ser feita a quebra de páginas;• objeto: define o objeto (Worksheet, na maioria das vezes) no qual será aplicada a propriedade. O objeto pode ser contado numericamente, iniciando a contagem da esquerda para a direita, ou dando-lhe um nome.Exemplo: Sub Cria _ Quebras()Dim i As Integer, x As Integer‘ Ativa uma folha de dados ou planilha e seleciona a pri-meira célula da planilha como ativa, executando uma quebra de página em seguida.ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Offset(1, 0).Se-lectActiveWindow.SelectedSheets.HPageBreaks.Add Before: =Acti-veCell For i = 1 To ActiveSheet.UsedRange.Rows.Count + 1 If Rows(i).PageBreak <> xlNone Then x = x + 1

If x Mod 2 <> 0 Then ActiveWindow.SelectedSheets.PrintOut _ From:=x, To:=x, Copies:=1, Collate:=True End If End If Next i

ActiveSheet.HPageBreaks(x).DeleteEnd SubVeja também: ActiveSheet e Points.

Comando: Hyperlinks.Sintaxe: [condicional] [objeto (Worksheet|Range|Chart) e seu valor].Hyperlinks

ap01.indd 242 1/11/2006 16:00:42

Page 235: Universidade VBA

Apêndice 243

apêndice

Utilização: retorna uma coleção Hyperlinks representando os hiperlinks do intervalo ou da planilha.Variáveis:• expressão: define uma condicional que mostrará ao VBA a situação em que Hyperlinks será utilizado;• objeto: define o tipo de objeto, e seu valor (1 é True), sobre o qual será aplicada a propriedade Hyperlinks. Podemos utilizar os objetos Worksheets (planilhas), Range (intervalo de células) ou Chart (gráfico). Exemplo: Sub HyperlinkXLSFiles()‘ O script seguinte cria uma coleção de hyperlinks das planilhas presentes em um determinado diretório do disco rígido.Dim lCount As Long

Application.ScreenUpdating = FalseApplication.DisplayAlerts = FalseApplication.EnableEvents = False

On Error Resume Next

With Application.FileSearch .NewSearch ‘ Definimos a localização do diretório das pla-nilhas a seguir .LookIn = “C:\MyDocuments\Planilhas” .FileType = msoFileTypeExcelWorkbooks ‘ .Filename = “Book*.xls” If .Execute > 0 Then ‘Planilhas no diretó-rio For lCount = 1 To .FoundFiles.Count ‘Loop through all. ActiveSheet.Hyperlinks.Add Anchor:=Cells(lCount, 1), Address:= _ .FoundFiles(lCount), TextToDisplay:= _ Replace(.FoundFiles(lCount), “C:\MyDo-cuments\Planilhas\”, “”) Next lCount

ap01.indd 243 1/11/2006 16:00:42

Page 236: Universidade VBA

244 universidade VBA

End If End With On Error GoTo 0 Application.ScreenUpdating = True Application.DisplayAlerts = True Application.EnableEvents = TrueEnd SubVeja também: Worksheets.

Comando: ListColumns.Sintaxe: expressão.ListColumns.Utilização: retorna uma coleção ListColumns, que representa todas as colunas de um objeto ListObject. É utilizado como somente leitura.Variáveis: a variável expressão define uma condicional que mostrará ao VBA a situação em que ListColumns será utilizado.Exemplo: Sub DisplayColumnName‘ Definimos inicialmente nomes-atalho para os objetos, uti-lizando o comando Dim. Dim wrksht As Worksheet Dim objListObj As ListObject Dim objListCols As ListColumns ‘ Agora, definimos as ações para cada objeto. Para o terceiro objeto, ListColumns, definimos que ele deve ser chamado pelo objeto objListObj. Set wrksht = ActiveWorkbook.Worksheets(“Sheet1”) Set objListObj = wrksht.ListObjects(1) Set objListCols = oListObj.ListColumns Debug.Print objListCols(2).NameEnd SubVeja também: Worksheets e Sheets.

Comando: ListObjects.Sintaxe: expressão.ListObjects.Utilização: retorna uma coleção de objetos ListObject, do tipo somente leitura, na planilha. Variáveis: a variável expressão define uma condicional que mostrará ao VBA a situação em que ListObjects será utilizado.

ap01.indd 244 1/11/2006 16:00:43

Page 237: Universidade VBA

Apêndice 245

apêndice

Exemplo: mySheet.ListObjects.Add(xlSrcRange, rngRange, , xlNo).Name = “List1”.Veja também: Hyperlinks.

Comando: ListRows.Sintaxe: expressão.ListRows.Utilização: retorna um objeto ListRows que representa todas as linhas de dados do objeto ListObject.Variáveis: a variável expressão define uma condicional que mostrará ao VBA a situação em que ListObjects será utilizado.Exemplo: Sub Macro2()

Do Until ActiveCell.Value = “”

‘ Aqui encontramos, com o auxílio de Offset, o valor que deve ser excluído. If ActiveCell.Value = “PAPER” And ActiveCell.Offset(0, 8).Va-lue = “” Then

‘ Depois de excluirmos, nos movemos para a próxima linha.ActiveCell.Rows(“1:1”).EntireRow.Select Selection.ListObject.ListRows(1).Delete ActiveCell.Offset(0, 1).Range(“A1”).Select

‘ Ou, se não foi feita a exclusão, simplesmente nos movemos para a próxima linha.Else ActiveCell.Offset(1, 0).Select

Loop End SubVeja também: Offset e Worksheets.

Comando: Names.Sintaxe: expressão.Names.Utilização: para um objeto Application, retorna uma coleção Names re-presentando todos os nomes na pasta de trabalho ativa (incluindo todos os nomes específicos). Para um objeto Worksheet, retorna uma coleção Names representando todos os nomes específicos de planilhas (nomes definidos com o

ap01.indd 245 1/11/2006 16:00:43

Page 238: Universidade VBA

246 universidade VBA

prefixo ”NomeDaPlanilha!”). É do tipo somente leitura, ou seja, não permite alteração nos nomes definidos.Variáveis: a variável expressão define uma condicional que mostrará ao VBA a situação em que Names será utilizado.Exemplo: ActiveWorkbook.Names.Add Name:=”teste”, RefersTo-R1C1:= _ “=Sheet1!R1C1”Veja também: Workbook.

Comando: Nodes.Sintaxe: expressão.Nodes.Utilização: retorna um objeto DiagramNodes, que guarda uma lista simples de todos os nós no diagrama especificado, quando aplicado a um objeto Diagram. Pode ser utilizado em conjunto com os objetos Shape ou ShapeRange, que re-presentam desenhos de forma livre. Nesse caso, retorna uma coleção de objetos ShapeNodes.Variáveis: a variável expressão define uma condicional que mostrará ao VBA a situação em que Names será utilizado.Exemplo: Set myDocument = Worksheets(1)With myDocument.Shapes(3).Nodes .Insert 4, msoSegmentCurve, msoEditingSmooth, 210, 100End WithVeja também: Names.

Comando: Panes.Sintaxe: expressão.Panes.[ação].Utilização: retorna uma coleção Panes representando todos os painéis na janela especificada. Os objetos do tipo Pane só existem para planilhas e folhas de macro do Microsoft Excel 4.0, ou para planilhas salvas nesse formato.Variáveis: • expressão: define uma condicional que mostrará ao VBA a situação em que Names será utilizado;• ação: ação que será realizada após o retorno de Panes.Exemplo: Workbooks(“Digerati1.XLS”).Worksheets(“Sheet1”).ActivateActiveWindow.Panes(1).ActivateEsse exemplo ativa o painel do canto superior-esquerdo da janela ativa na planilha Digerati1.xls.Veja também: Worksheets.

ap01.indd 246 1/11/2006 16:00:43

Page 239: Universidade VBA

Apêndice 247

apêndice

Comando: Paramaters.Sintaxe: Sheets(“nome da folha de dados”).QueryTables(valor booleano do filtro).Parameters(valor do parâmetro).Utilização: retorna uma coleção Parameters, representando os parâmetros da tabela de consulta. Cada objeto Parameter representa um único parâmetro de consulta. Variáveis: na variável valor booleano do filtro, utilizamos 1 para indicar que um parâmetro deve ser utilizado.Exemplo: With Sheets(“Digerati”).QueryTables(1).Parameters(1) If .DataType = xlParamTypeVarChar Then .SetParam xlPrompt, “Entre com apenas um caractere” End IfEnd WithVeja também: Phonetics.

Comando: Phonetics.Sintaxe: Set objPhon = ActiveCell.Phonetics.Utilização: retorna um objeto da coleção Phonetics em uso. Todo objeto Phonetic guarda informações sobre uma seqüência específica de caracteres de texto fonético.Variáveis: não há variáveis.Exemplo: Set objPhon = ActiveCell.PhoneticsWith objPhon For Each objPhonItem in objPhon MsgBox “Phonetic object: “ & .Text NextEnd WithO exemplo retorna todos os objetos Phonetics na célula ativa, mostrando os resultados em uma caixa de texto.Veja também: Dialogs.

Comando: PivotFields.Sintaxe: expressão.PivotFields.Utilização: retorna todos os objetos do grupo PivotFields presentes na planilha atual. Um objeto PivotField representa um campo em um relatório de tabela dinâmica.Variáveis: a variável expressão retorna um dos objetos da coleção Pivot-Fields.Exemplo: Set objNewSheet = Worksheets.AddobjNewSheet.Activate

ap01.indd 247 1/11/2006 16:00:43

Page 240: Universidade VBA

248 universidade VBA

intRow = 1For Each objPF In _ Charts(“Chart1”).PivotLayout.PivotFields objNewSheet.Cells(intRow, 1).Value = objPF.Caption intRow = intRow + 1Next objPFVeja também: Parameters.

Comando: PivotFormulas.Sintaxe: expressão.PivotFormulas.Utilização: retorna um objeto PivotFormulas, que representa a coleção de fórmulas para o relatório de tabela dinâmica especificado.Variáveis: a variável expressão retorna um dos objetos da coleção Pivot-Formulas.Exemplo: For Each pf in ActiveSheet.PivotTables(1).PivotFor-mulas r = r + 1 Cells(r, 1).Value = pf.FormulaNextO exemplo cria uma lista de fórmulas para a tabela dinâmica um, presente na planilha atual.Veja também: Filters.

Comando: PivotTable.Sintaxe: expressão.PivotTable.Utilização: retorna um objeto PivotTable representando o relatório de tabela dinâmica que contém o canto superior esquerdo do intervalo especificado, ou o relatório de tabela dinâmica associado ao relatório de gráfico dinâmico.Variáveis: a variável expressão retorna um dos objetos da coleção PivotTable.Exemplo: ‘ Set Pt = ActiveSheet.PivotTables(“ItemList”)O exemplo define o relatório de tabela dinâmica associada à planilha atual.Veja também: ActiveSheet e Charts.

Comando: Points.Sintaxe: pointsArray = .objeto(valor).Points.Utilização: retorna a posição do nó especificado como um par de coordenadas. Coordenadas são pares de valores que representam as coordenadas X e Y de um ponto armazenado em uma matriz bidimensional e são capazes de armazenar coordenadas para vários pontos. Cada coordenada é expressa em pontos.

ap01.indd 248 1/11/2006 16:00:44

Page 241: Universidade VBA

Apêndice 249

apêndice

Exemplo: Set myDocument = Worksheets(1)With myDocument.Shapes(3).Nodes pointsArray = .Item(2).Points currXvalue = pointsArray(1, 1) currYvalue = pointsArray(1, 2) .SetPosition 2, currXvalue + 200, currYvalue + 300End WithO exemplo move 200 pontos à direita o nó dois da forma três do documento Digerati – coordenada cujo ponto inicial é definido por currYValue. Também move o mesmo documento 300 pontos para baixo, coordenada inicial definida por currXValue. A terceira forma precisa ser um desenho livre.Veja também: Nodes.

Comando: PublishObjects.Sintaxe: Set [NOME DO OBJETO] = ActiveWorkbook.PublishOb-jects.Utilização: é uma coleção de todos os objetos PublishObject na pasta de trabalho. Cada objeto PublishObject representa um item em uma pasta de trabalho salva em uma página da Web e pode ser atualizado de acordo com os valores especificados pelas propriedades e métodos do objeto.Variáveis: não há variáveis.Exemplo: Workbooks(3).PublishObjects(1).FileName = _ “\\myserver\public\finacct\statemnt.htm”O exemplo define o local na Web em que é salvo o primeiro item da terceira pasta de trabalho.Veja também: Workbooks.

Comando: QueryTables.Sintaxe: Objeto [Worksheets(número da planilha)], Active-Sheet].QueryTables.Utilização: uma coleção de objetos QueryTable. Cada objeto QueryTable representa uma tabela da planilha construída a partir de dados retornados de uma fonte externa.Variáveis: • Worksheet: define o nome da pasta de trabalho da qual serão filtrados os dados; • ActiveSheet: especifica que os dados serão filtrados a partir da folha de dados ativa;

ap01.indd 249 1/11/2006 16:00:44

Page 242: Universidade VBA

250 universidade VBA

• número da planilha: identifica a planilha que será alvo da filtragem, com a contagem sendo iniciada da esquerda para a direita. Nesse contexto, 1 corresponde à primeira planilha localizada à esquerda da aba de planilhas.Exemplo: Sub SetRefreshTime() With ActiveSheet.QueryTables(1) .RefreshPeriod = 1 End WithEnd SubO exemplo atualiza os dados da planilha ativa na sessão atual do Excel.Veja também: ActiveSheet e Worksheet.

Comando: Range.Sintaxe: expressão.Range[(Cell1, Cell2)] [index].Utilização: em conjunto com AllowEditRange, retorna um objeto Range, que representa um subconjunto dos intervalos que podem ser editados em uma planilha protegida. Quando utilizado em conjunto com Application, Range ou Work-sheet retorna uma célula ou intervalo de células. Ao ser utilizado em conjunto com Shapes, retorna um objeto ShapeRange representando um subconjunto de formas em uma coleção do tipo Shapes.Variáveis:• expressão: necessária para a execução do comando. É uma expressão que retorna um dos objetos descritos;• Cell1: variável necessária. Trata-se do nome do intervalo. Deve ser uma refe-rência no estilo A1 e no idioma da macro. Pode incluir o operador de intervalo (:), o operador de interseção (espaço) ou o operador de união (,). Também pode incluir cifrões de dólar, mas estes são ignorados. Podemos usar um nome definido de local em qualquer parte do intervalo. Se usarmos um nome, este será assumido como linguagem da macro;• Cell2: variável opcional. Trata-se da célula no canto superior esquerdo e inferior direito do intervalo. Pode ser um objeto Range que contém uma única célula, uma coluna inteira, uma linha inteira ou uma seqüência de caracteres que nomeia uma única célula no idioma da macro;• Index: variável necessária. São as formas individuais incluídas no intervalo. Pode ser um número inteiro, especificando o índice da forma, uma seqüência de caracteres, especificando o nome da forma, uma matriz com números inteiros ou seqüências de caracteres. Exemplo: o exemplo seguinte cria um botão que será utilizado para duplicar os dados selecionados em uma tabela:Private Sub CommandButton4 _ Click()

ap01.indd 250 1/11/2006 16:00:44

Page 243: Universidade VBA

Apêndice 251

apêndice

Set r = Worksheets(“Sheet1”).Range(“A16:A29”) ‘search this rangeFor n = 1 To r.Rows.Count

‘if today = date in the range then If Worksheets(“sheet1”).Range(“b4”).Value = r.Cells(n, 1) Then r.Cells(n + IIf([c4] = “Days”, 0, 1), 3).Value = Worksheets(“sheet1”).Range(“b7”) r.Cells(n + IIf([c4] = “Days”, 0, 1), 4).Value = Worksheets(“sheet1”).Range(“b8”) r.Cells(n + IIf([c4] = “Days”, 0, 1), 5).Value = Worksheets(“sheet1”).Range(“b9”) r.Cells(n + IIf([c4] = “Days”, 0, 1), 6).Value = Worksheets(“sheet1”).Range(“b10”) r.Cells(n + IIf([c4] = “Days”, 0, 1), 7).Value = Worksheets(“sheet1”).Range(“b11”) Exit For ‘MsgBox “Duplica dados em “ & r.Cells(n, 1).Address End IfNext n

End SubVeja também: MsgBox, Worksheets.

Comando: Shapes.Sintaxe: objeto [Worksheets(número da planilha) Active Cell].Shapes.[novo objeto de desenho].Utilização: é uma coleção de todos os objetos Shape na planilha especificada. Cada objeto Shape representa um objeto na camada de desenho, como uma AutoForma, uma forma livre, um objeto OLE ou uma figura.Variáveis:• objeto: é possível utilizar a propriedade Shapes em uma planilha de dados (Worksheet) ou na célula ativa da planilha atual (ActiveCell);• número da planilha:

ap01.indd 251 1/11/2006 16:00:44

Page 244: Universidade VBA

252 universidade VBA

identifica a planilha que será o alvo da filtragem, com contagem iniciada da esquerda para a direita. Nesse contexto, 1 corresponde à primeira planilha localizada à esquerda da aba de planilhas;• novo objeto de desenho: indica o objeto de desenho que será inserido na planilha.Exemplo: Set myDocument = Worksheets(1)myDocument.Shapes.SelectAllVeja também: Range e Worksheets.

Comando: SmartTagActions.Sintaxe: expressão.SmartTagActions.Utilização: evoca uma coleção de objetos SmartTagAction, que representa as ações que podem ser executadas com marcas inteligentes.Variáveis: a variável expressão define uma expressão que retorna um objeto SmartTag.Exemplo: Sub UseSmartTagActions() Dim strLink As String

strLink = “urn:schemas-microsoft-com:office:smarttags#stockticker”

‘ Habilita marcas inteligentes que possam ser reconhe-cidas na planilha ActiveWorkbook.SmartTagOptions.EmbedSmartTags = True Application.SmartTagRecognizers.Recognize = True

Range(“A1”).Value = “Digerati”MsgBox Range(“A1”).SmartTags.Add(strLink).SmartTagActions.Item(1).NameEnd SubVeja também: ActiveWorkbook.

Comando: SmartTagRecognizers.Sintaxe: expressão.SmartTagRecognizers.Utilização: retorna uma coleção de objetos SmartTagRecognizer. Esses objetos representam mecanismos de reconhecimento que identificam os dados com tipos de informação à medida que você trabalha no Microsoft Excel.Variáveis: a variável expressão define uma expressão que retorna um objeto SmartTagRecognizers.

ap01.indd 252 1/11/2006 16:00:45

Page 245: Universidade VBA

Apêndice 253

apêndice

Exemplo: Sub Teste de reconhecimento() Dim i% With Application.SmartTagRecognizers If .Count > 0 Then For i = 1 To .Count MsgBox i & “ “ & .Item(i).progID & _ “ “ & .Item(i).Enabled Next End If End WithEnd SubVeja também: MsgBox.

Comando: SmartTags.Sintaxe: expressão.SmartTags.Utilização: retorna um conjunto de objetos SmartTags, que representa os identificadores atribuídos às células presentes em uma planilha.Variáveis: a variável expressão define uma expressão que retorna um objeto SmartTags.Exemplo: Sub ReturnSmartTag()

Dim strLink As String Dim strType As String

‘ Define variáveis SmartTag strLink = “urn:schemas-microsoft-com:smarttags#StockTickerSymbol” strType = “stockview”

‘ Define a marca inteligente que será utilizada na planilha ativa ActiveWorkbook.SmartTagOptions.EmbedSmartTags = True Application.SmartTagRecognizers.Recognize = True

Range(“A1”).Formula = “Digerati” MsgBox Range(“A1”).SmartTags.Parent

End Sub

ap01.indd 253 1/11/2006 16:00:45

Page 246: Universidade VBA

254 universidade VBA

Esse exemplo insere uma marca inteligente na célula A1 e depois,informa ao usuário o ”pai” do identificador da célula A1, que é ”teste”. O exemplo supõe que o sistema host esteja conectado à Internet.Veja também: MsgBox e Range de células.

Comando: Styles.Sintaxe: objeto [ActiveWorkbook,ActiveDocument, Workbook (nome da planilha ou número) (.Styles(“nome do usuário do qual será utilizado o estilo”).ação.Utilização: é uma coleção de todos os objetos Style na pasta de trabalho ativa ou especificada. Todo objeto Style representa uma descrição de estilo para um intervalo, mas aqui é tratado todo o conjunto de estilos da ferramenta. O objeto Style contém todos os atributos de estilo (fonte, formato de número, alinhamento etc.) como propriedades. Variáveis:• objeto: é possível utilizar essa propriedade em uma planilha de dados ativa (ActiveWorkbook) ou em uma planilha nomeada na mesma linha de comando. Podemos também definir o objeto simplesmente como Workbook;• ação: define a ação que será tomada pelo script frente ao objeto determinado e ao estilo proposto para a aplicação. Exemplo: (ActiveDocument)sParStyle = ActiveDocument.Paragraphs(J).StyleEsse exemplo seta um estilo para definição dos parágrafos do documento atual.Veja também: Range de coluna e DataLabel.

Comando: Windows.Sintaxe: objeto [Application, Worksheet, Workbook, ActiveWork-sheet, Document).Windows(número da janela).ação.Utilização: faz com que um processo interrompido seja reativado e passe para o foreground.Variáveis: para um objeto Application, retorna uma coleção Windows repre-sentando todas as janelas em todas as pastas de trabalho. Para um objeto Work-book, retorna uma coleção Windows representando todas as janelas na pasta de trabalho especificada. É um objeto do tipo somente leitura, ou seja, não são possíveis modificações em sua estrutura.Exemplo: Application.Windows(1).Close.Veja também: Workbooks.

ap01.indd 254 1/11/2006 16:00:45

Page 247: Universidade VBA

Apêndice 255

apêndice

Comando: Workbooks.Sintaxe: Workbooks(“nome da planilha”).ação ou Workbooks.ação:=”nome do arquivo”.Utilização: retorna uma coleção de todos os objetos Workbook que estão abertos no aplicativo Microsoft Excel. Um objeto Workbook representa uma pasta de trabalho do Microsoft Excel.Variáveis:• ”nome da planilha”: pode-se utilizar o nome genérico da planilha para definir a ação que será executada;• ação: define a ação que será lançada na planilha;• ”nome do arquivo”: define o arquivo que será alvo da ação de uma pla-nilha. Diferente do que ocorre com ”nome da planilha”, é preciso utilizar o nome real do arquivo, como aparece no gerenciador de arquivos.Exemplos:1. O exemplo seguinte testa a possibilidade de se abrir um Workbook:Sub IsWorkBookOpen()

Dim wBook As Workbook

On Error Resume Next

Set wBook = Workbooks(“Personal.xls”)

If wBook Is Nothing Then ‘Not openMsgBox “Planilha não pode ser aberta”, _vbCritical,”OzGrid.com”Set wBook = NothingOn Error GoTo 0Else ‘It is openMsgBox “A planilha pode ser aberta”, _vbInformation,”OzGrid.com”Set wBook = NothingOn Error GoTo 0End IfEnd Sub

2. O exemplo seguinte executa testes para ver se a planilha existe:Sub IsWorkBookOpen()

ap01.indd 255 1/11/2006 16:00:45

Page 248: Universidade VBA

256 universidade VBA

Dim wBook As Workbook

On Error Resume Next

Set wBook = Workbooks(“Personal.xls”)

If wBook Is Nothing Then ‘Not openMsgBox “Planilha não pode ser aberta”, _vbCritical,”Digerati.com”Set wBook = NothingOn Error GoTo 0Else ‘It is openMsgBox “Sim, a planilha pode ser aberta”, _vbInformation,”Digerati.com”Set wBook = NothingOn Error GoTo 0End IfEnd Sub

3. Esse exemplo abre todas as planilhas em uma pasta (no caso, a pasta Minhas Planilhas):Sub OpenAllWorkbooksInFolder()‘’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’’Dim i As Integer

With Application.FileSearch.LookIn = “C:\Minhas Planilhas”‘* represents wildcard characters.FileType = msoFileTypeExcelWorkbooksIf .Execute > 0 Then ‘Workbook existsFor i = 1 To .FoundFiles.CountWorkbooks.Open (.FoundFiles(i))Next iElse ‘There is Not a WorkbookMsgBox “A planilha não existe”End IfEnd WithEnd SubVeja também: Worksheets.

ap01.indd 256 1/11/2006 16:00:45

Page 249: Universidade VBA

Apêndice 257

apêndice

Comando: Worksheets.Sintaxe: Worksheets(“Nome da folha de dados”).[Range(“célula ou células do intervalo”)].Value.Utilização: para um objeto Application, retorna uma coleção Sheets repre-sentando todas as planilhas na pasta de trabalho ativa. Para um objeto Work-book, retorna uma coleção Sheets representando todas as planilhas na pasta de trabalho especificada. Variáveis:• ”Nome da folha de dados”: define o nome da folha de dados (Worksheet) na qual será aplicada a ação;• ”célula ou células do intervalo”: define o intervalo de células da folha de dados ativa que será o alvo da ação. Em alguns casos, aplica-se Work-sheet de forma direta, sem a definição de um intervalo.Exemplo: 1. Esse exemplo testa a existência da folha de dados:

Sub DoesSheetExist()

Dim wSheet As Worksheet

On Error Resume NextSet wSheet = Sheets(“Sheet1”)If wSheet Is Nothing Then ‘Doesn’t existMsgBox “Folha de dados não existe”, _vbCritical,”Digerati.com”Set wSheet = NothingOn Error GoTo 0Else ‘Does existMsgBox “Sheet 1existe”, _ vbInformation,”Digerati.com”Set wSheet = NothingOn Error GoTo 0End IfEnd Sub

2. Esse exemplo cria uma macro que classifica todas as folhas de dados (Work-sheets) presentes em uma planilha (Workbook) do Excel:Sub SortSheets()

Dim SheetCount As Integer

ap01.indd 257 1/11/2006 16:00:45

Page 250: Universidade VBA

258 universidade VBA

Dim i As IntegerDim j As Integer

SheetCount = Worksheets.Count

If SheetCount = 1 ThenExit Sub

For i = 1 To SheetCount - 1For j = i + 1 To SheetCountIf Worksheets(j).Name < Worksheets(i).Name ThenWorksheets(j).Move Before:=Worksheets(i)End IfNext jNext iEnd If

End SubVeja também: Workbooks, Range e Range de intervalo de linhas.

Objetos

Comando: AddIn.Sintaxe: AddIns(index).ação = valor booleano.Utilização: o objeto AddIn é um membro da coleção AddIns. A coleção AddIns contém uma lista de todos os suplementos disponíveis do Microsoft Excel, independente de estarem instalados. Essa lista corresponde à lista de suplementos exibidos na caixa de diálogo Suplementos (menu Ferramentas).Variáveis:• index: número de índice ou título do suplemento para retornar o objeto escolhido;• ação: define a operação que será realizada com o suplemento;• valor booleano: indica se o suplemento está ou não ativo. True ativa o suplemento.Exemplo: Sub AddIns.Add

Filename:=”C:\Hyperion\Essbase\Bin\essexcln.xll”AddIns(“Hyperion Essbase OLAP Server

ap01.indd 258 1/11/2006 16:00:46

Page 251: Universidade VBA

Apêndice 259

apêndice

DLL”).Installed = TrueVeja também: Addins (Propriedades).

Comando: Adjustments.Sintaxe: rac.Adjustments[valores utilizados no ajuste]Utilização: armazena uma coleção de valores de ajuste para um objeto Word-Art, AutoShape ou algum conector inserido em uma planilha do Excel. Cada valor representa uma maneira pela qual uma alça de ajuste pode ser posicionada. Algu-mas alças de ajuste podem ser ajustadas tanto horizontal quanto verticalmente e, por isso, algumas formas podem ter mais valores de ajuste do que alças de ajuste. Uma forma pode ter até oito ajustes.Variáveis:• Linear (horizontal ou vertical): geralmente, o valor 0,0 representa a extremi-dade esquerda ou superior da forma, e o valor 1,0 representa a extremidade direita ou inferior da forma. Os valores válidos correspondem aos ajustes válidos que você pode fazer manualmente. Por exemplo, se você só pode puxar uma alça de ajuste até metade do caminho da forma, o valor máximo do ajuste correspondente será 0,5. Para tais formas, como conectores e textos explicativos em que os valores 0,0 e 1,0 representam os limites do retângulo definido pelo pontos iniciais e finais do conector ou linha de texto explicativo, números negativos e números maiores que 1,0 são valores válidos;• Radial: um valor de ajuste de 1,0 corresponde à largura da forma. O valor máximo é 0,5, ou a meio caminho da forma;• Ângulo: os valores são expressos em graus. Quando você especifica um valor fora do intervalo entre –180 até 180, ele é normalizado para se situar dentro desse intervalo.Exemplo: Set myDocument = Worksheets(1)Set rac = myDocument.Shapes.AddShape(msoShapeRightArrowCallout, _ 10, 10, 250, 190)With rac.Adjustments .Item(1) = 0.5 ‘adjusts width of text box .Item(2) = 0.15 ‘adjusts width of arrow head .Item(3) = 0.8 ‘adjusts length of arrow head .Item(4) = 0.4 ‘adjusts width of arrow neckEnd WithVeja também: ChartColorFormat e PublishObjects.

ap01.indd 259 1/11/2006 16:00:46

Page 252: Universidade VBA

260 universidade VBA

Comando: Application.Sintaxe: Application.propriedade(“objeto”).ação.Utilização: representa todo o aplicativo Microsoft Excel. O objeto Applica-tion contém definições e opções para o aplicativo como um todo (muitas das opções da caixa de diálogo Opções, do menu Ferramentas). Além disso, todos os métodos que retornem objetos de nível mais alto, como ActiveCell, Ac-tiveSheet e ActiveWorkbook, dentre outros, dependem desse objeto. Variáveis:• propriedade: define a propriedade que será manipulada juntamente com o objeto evocado;• objeto: define o objeto que será manipulado pelo Excel;• ação: define a ação que será aplicada sobre o objeto.Exemplo: 1. O exemplo seguinte cria uma caixa de diálogo utilizando o objeto Appli-cation:Sub ChangeFont()

Application.ScreenUpdating = False

Application.Dialogs(xlDialogFormatFont).Show

End Sub

2. Esse exemplo cola o valor de uma fórmula em uma célula, e não a fórmula como um todo:Sub ColarValores()

Application.ScreenUpdating = False

Range(“A4”).Copy

Range(“D4”).PasteSpecial Paste:=xlValues

Application.CutCopyMode = False

End Sub

3. Esse exemplo move duas linhas para baixo e duas colunas para a direita:Sub MoveToCell()

ap01.indd 260 1/11/2006 16:00:46

Page 253: Universidade VBA

Apêndice 261

apêndice

Application.ScreenUpdating = False

ActiveCell.Offset(3, 2).Select

End Sub

4. O exemplo seguinte seleciona a última linha e a última coluna da lista Sub SelecioneFim():

Application.ScreenUpdating = False

Range(Selection, Selection.End(xlDown)).Select

Range(Selection, Selection.End(xlToRight)).Select

End Sub

5. Esse exemplo adiciona o nome do arquivo e seu caminho (pathname) no rodapé do documento impresso:SubFilenameInFooter()

Application.ScreenUpdating = False

ActiveSheet.PageSetup.CenterFooter = _

ActiveWorkbook.FullName

End SubVeja também: Workbook (propriedade) e Worksheet (propriedade).

Comando: AutoCorrect.Sintaxe: propriedade.AutoCorrect.método = valor booleanoUtilização: contém atributos de AutoCorreção do Microsoft Excel, como colocação de nomes dos dias em maiúsculas, correção de duas maiúsculas ini-ciais, lista de correção automática entre outras opções encontradas no menu Ferramentas do Excel.

ap01.indd 261 1/11/2006 16:00:46

Page 254: Universidade VBA

262 universidade VBA

Variáveis:• propriedade: define a propriedade que será manipulada junto com o objeto evocado;• método: define a ação que será aplicada pela propriedade;• booleano: se o método for True, temos que a AutoCorreção será aplicada na planilha atual ou no arquivo escolhido. Exemplo: With Application.AutoCorrect .TwoInitialCapitals = True .ReplaceText = TrueEnd WithEsse exemplo faz o Excel corrigir todas as palavras que estão com duas iniciais maiúsculas na planilha atual.Veja também: Styles.

Comando: AutoFilter.Sintaxe: worksheet.AutoFilter = booleano.Utilização: traz para o script VBA o esquema de filtros utilizado na planilha atual.Variáveis:• booleano: se a variável for True (verdadeiro), o filtro deve ser aplicado.Exemplos: 1. O exemplo seguinte inicia um filtro:Sub TurnAutoFilterOn()‘check for filter, turn on if none exists If Not ActiveSheet.AutoFilterMode Then ActiveSheet.Range(“A1”).AutoFilter End IfEnd Sub

2. O exemplo seguinte interrompe uma filtragem:Sub TurnFilterOff()‘removes AutoFilter if one exists Worksheets(“Data”).AutoFilterMode = FalseEnd Sub

3. Esse exemplo esconde as setas de filtragem da planilha:Sub HideArrows()

ap01.indd 262 1/11/2006 16:00:47

Page 255: Universidade VBA

Apêndice 263

apêndice

‘hides all arrows except column 2Dim c As Range Dim i As Integer i = Cells(1, 1).End(xlToRight).Column Application.ScreenUpdating = False

For Each c In Range(Cells(1, 1), Cells(1, i)) If c.Column <> 2 Then c.AutoFilter Field:=c.Column, _ Visibledropdown:=False End If Next

Application.ScreenUpdating = True End SubVeja também: Range e Workbooks.

Comando: AutoRecover.Sintaxe: propriedade.AutoRecover.objeto (planilha a ser recu-perada).Utilização: representa os recursos automáticos de recuperação de uma pasta de trabalho. As propriedades para o objeto AutoRecover determinam o caminho e o intervalo de tempo para o backup de todos os arquivos.Variáveis: a variável propriedade define o aspecto em que AutoRecover será utilizado. Application faz com que um objeto AutoRecover (é uma configu-ração de auto-recuperação, portanto) seja recuperado.• Creator é a propriedade utilizada para criar um AutoRecover. Enabled habili-ta a configuração de auto-recuperação criada com o auxílio da propriedade Create. Path define o caminho no qual o arquivo de auto-recuperação deve ser salvo.• Time é a propriedade utilizada para definir o backup periódico de todos os arquivos.Exemplo: Sub SetPath()

Application.AutoRecover.Path = “C:\”

End SubVeja também: Application e Workbooks.

ap01.indd 263 1/11/2006 16:00:47

Page 256: Universidade VBA

264 universidade VBA

Comando: Border.Sintaxe: para o estilo de linha, digite: método.Border.LineStyle = es-tilo de linha utilizadoPara definir a cor de uma borda, utilize: Borders(index).Color = RGB(valores de cor)Utilização: representa a borda de um objeto.Variáveis:• método: define a maneira como a borda será aplicada;• estilo de linha utilizado: define o estilo de linha que será utilizado;• index: identifica a borda, para retornar um único objeto.Exemplo: Sub NovoObjeto() Dim N As Byte, L As Byte Dim Graph As ChartObject

N = 1 With ActiveWorkbook.Worksheets(1) .Range(“A1”) = “Valeurs X” .Range(“B1”) = “Valeurs Y=X+10” .Range(“C1”) = “Valeurs Y=2X” For L = 2 To 10 .Range(“A” & L) = “X=” & N .Range(“B” & L) = N + 10 .Range(“C” & L) = N * 2 N = N + 1 Next L .Range(“A:C”).Columns.AutoFit Set Graph = .ChartObjects.Add(0, 140, 400, 250) End With With Graph.Chart .SetSourceData Worksheets(1).Range(“A1:B10”) .ChartArea.Border.LineStyle = xlDashDotDot .ChartArea.Border.Weight = xlMedium .HasTitle = True .ChartTitle.Text = “Gráfico de teste” .ChartTitle.Characters(0, 9).Font.Bold = True ‘ Definimos as linhas que serão utilizadas .ChartType = xlLine With .Legend

ap01.indd 264 1/11/2006 16:00:47

Page 257: Universidade VBA

Apêndice 265

apêndice

.Font.Bold = True .Font.Italic = True .Position = xlLegendPositionCorner .Top = 10 .Height = 20 End With With .PlotArea .Interior.ColorIndex = 2 .Left = 0 .Top = 30 .Width = Graph.Chart.ChartArea.Width .Height = Graph.Chart.ChartArea.Height - 40 End With End WithEnd Sub

Sub AjoutSerie() Dim Graph As Chart

With ActiveWorkbook.Worksheets(1) Set Graph = .ChartObjects(1).Chart Graph.SeriesCollection.Add .Range(“C1:C10”) End WithEnd SubVeja também: ChartObject.

Comando: CalculatedMember.Sintaxe: propriedade.CalculatedMember.Utilização: representa os campos e itens calculados para tabelas dinâmicas com fontes de dados OLAP (Online Analytical Processing).Variáveis: a variável propriedade define a propriedade que será manipulada juntamente com o objeto evocado. Podem ser utilizadas as propriedades Apli-cation, Creator, Formula, IsValid, Name, Parent, SolveOrder, Sour-ceName e Type.Exemplo: Sub CheckValidity()

Dim pvtTable As PivotTable Dim pvtCache As PivotCache

ap01.indd 265 1/11/2006 16:00:47

Page 258: Universidade VBA

266 universidade VBA

Set pvtTable = ActiveSheet.PivotTables(1) Set pvtCache = Application.ActiveWorkbook.PivotCaches.Item(1)

On Error GoTo Not _ OLEDB

pvtCache.MakeConnection End If

If pvtTable.CalculatedMembers.Item(1).IsValid = True Then MsgBox “O objeto calculado é válido.” Else MsgBox “O objeto calculado não é válido.” End If

End Sub

Nota: com um objeto CalculatedMember, é possível verificar a validade de um campo ou item calculado em uma tabela dinâmica. Para isso, basta utilizá-lo associado à propriedade IsValid.

Veja também: Chart (objeto), Chart (Propriedade).

Comando: CalloutFormat.Sintaxe: objeto.propriedade [ou método].Callout.Utilização: contém propriedades e métodos que se aplicam a textos explicativos de linhas.Variáveis:• objeto: define o objeto no qual serão aplicadas as características configu-radas;• propriedade ou método: define a propriedade ou método que serão utilizados no objeto.Exemplo: o exemplo seguinte precisa ser aplicado a um texto explicativo dentro de uma planilha. As alterações são explicadas em comentários internos: ‘ Define a configuração na caixa em um ângulo de 60°. .Angle = msoCalloutAngle60 ‘ Define que a caixa explicativa terá borda. .Border = True

ap01.indd 266 1/11/2006 16:00:47

Page 259: Universidade VBA

Apêndice 267

apêndice

.PresetDrop msoCalloutDropTop .Type = msoCalloutThreeEnd WithVeja também: ChartArea e Shapes (Propriedades).

Comando: Characters.Sintaxe: Worksheets(“Nome da planilha”).Range(“Intervalo do texto utilizado”) [.Value = “Texto a ser alterado”] .Characters(início,comprimento).Font.estilo da fonte alterada = booleanoUtilização: representa caracteres em um objeto com textos. Pode ser utilizado tanto para inserir como para alterar configurações de texto.Variáveis:• ”Nome da planilha”: aqui, define-se o nome da planilha na qual serão ma-nipulados os caracteres. Deve ser representada entre aspas. Não é preciso utilizar o nome do arquivo – um arquivo ou pasta de trabalho do Excel pode conter várias planilhas, o que retornaria um resultado nulo para o comando;• ”Intervalo do texto utilizado”:define em qual intervalo de células da planilha escolhida será aplicada a alteração ou inserção de caracteres;• Value = “Texto a ser alterado”: ao optar por esse método, inserimos um texto no intervalo selecionado em uma determinada planilha;• (início,comprimento): definem, respectivamente, a posição numérica do caractere inicial (com o texto lido da esquerda para a direita) e o número de caracteres a partir do qual o novo texto será inserido ou uma nova formatação será realizada.Exemplo: With Worksheets(“Plan1”).Range(“A1;B1;C1;D2”) .Value = “Isto é apenas um texto” ‘ a seguir formatamos toda a linha como negrito .Characters(1, 15).Font.Bold = True ‘ não satisfeitos, definimos toda a linha como itálico também .Characters(1, 15).Font.Italic = True

End WithO exemplo adiciona um texto formatado ao intervalo de células da planilha indica-da. Utilizando ponto-e-vírgula podemos inserir o mesmo texto em várias células.Veja também: Range(“A1”), Range com seleção de várias áreas e Work- sheets.

ap01.indd 267 1/11/2006 16:00:48

Page 260: Universidade VBA

Comando: Chart.Sintaxe: Worksheets(“nome da planilha”).ChartObjects(índice).Chart. _Em conjunto com o índice: Charts(número do índice ou nome da folha de dados).Para ativar um gráfico, com a propriedade ActiveChart:Charts(1).ActivateWith ActiveChart .Type = xlLine .HasTitle = valor booleano .ChartTitle.Text = “título do gráfico”End WithUtilização: representa um gráfico em uma pasta de trabalho. O gráfico pode ser um gráfico incorporado (contido em um ChartObject) ou uma folha de gráfico separada.Variáveis:• “nome da planilha”: assim como em outros casos, deve ser declarado o nome inscrito na aba de seleção da folhas de dados, que passa a ser o nome pelo qual o Microsoft Office reconhece o objeto folha de dados;• índice: valor que corresponde ao objeto no qual será aplicada uma ação. Se uma planilha, por exemplo, possui um único objeto de gráfico em seu interior e quisermos utilizar esse gráfico, declaramos a planilha no início da linha e, em seguida, o índice do gráfico como um.Exemplo: 1. O exemplo seguinte insere um gráfico em uma planilha:Sub RecordedAddChartObject()

Charts.Add ActiveChart.ChartType = xlXYScatterLines ActiveChart.SetSourceData Source:=Sheets(“Sheet1”).Range(“A3:G14”) ActiveChart.Location Where:=xlLocationAsObject, Name:=”Sheet1”

End Sub

2. Nesse exemplo, um gráfico de série é adicionado à planilha:Sub RecordedAddSeries()

ap01.indd 268 1/11/2006 16:00:48

Page 261: Universidade VBA

ActiveChart.SeriesCollection.NewSeries ActiveChart.SeriesCollection(6).XValues = “=Sheet1!R4C1:R14C1” ActiveChart.SeriesCollection(6).Values = “=Sheet1!R4C7:R14C7” ActiveChart.SeriesCollection(6).Name = “=Sheet1!R3C7”

End SubVeja também: ChartArea e Shapes (Propriedades).

ap01.indd 269 1/11/2006 16:00:48

Page 262: Universidade VBA

ap01.indd 270 1/11/2006 16:00:48

Page 263: Universidade VBA

ap01.indd 271 1/11/2006 16:00:48

Page 264: Universidade VBA

ap01.indd 272 1/11/2006 16:00:48

Page 265: Universidade VBA

PARCERIA JÚLIO BATTISTI - DIGERATI • Este e-book é uma parceria entre o meu site

www.juliobattisti.com.br e a Editora Digerati, com a qual eu mantenho contrato para revenda deste e-book, em formato PDF, através do meu site.

Nota sobre direitos autorais: IMPORTANTE: Nas propriedades do E-book estão gravados o nome completo, e-mail e demais dados do comprador. Se for repassada cópia para outros usuários e este E-book for parar em um site ou Blog, para download gratuito, quem será responsabilizado Criminalmente, conforme previsto nas Leis 9118 e 9610, será o comprador do E-book, que foi quem repassou cópias para outros usuários, O QUE É PROIBIDO. Seja honesto. Este E-book é de uso pessoal, individual, não compartilhado. NÃO REPASSE CÓPIAS!!! Ao adquirir este E-book você tem o direito de lê-lo na tela do seu computador e de imprimir uma cópia para o seu uso pessoal. É vetada a distribuição deste arquivo, mediante cópia ou qualquer outro meio de reprodução, para outras pessoas. Se você recebeu este E-book através do e-mail ou via ftp de algum site da Internet, ou através de um CD de Revista ou via e-mail recebido de um “amigo”, saiba que você está com uma cópia pirata, não autorizada. A utilização de uma cópia pirata, não autorizada, é crime de Violação de Direitos Autorais conforme Leis 9118 e 9610, sujeita a pena de 2 a 5 anos de Cadeia. Denuncie o site ou revista que está disponibilizando a cópia, através do e-mail [email protected] Se você tiver sugestões sobre novos cursos que gostaria de ver disponibilizados, entre em contato pelo e-mail: [email protected]. Visite periodicamente o site www.juliobattisti.com.br para ficar por dentro das novidades:

• Mais de 900 cursos e vídeos-aula em diversos assuntos. • Artigos e dicas sobre Certificações da Microsoft. • Artigos sobre Carreira e Trabalho. • Centenas de Livros sobre os mais Variados Assuntos. • Dicas de livros e sites sobre diversos assuntos. • Simulados gratuitos, em português, para os exames da Microsoft.

PARCERIA JÚLIO BATTISTI - DIGERATI