Você está na página 1de 364

Word

2000 e 97
Segredos e Soluções
ASSOCIAÇÃO BRASILEIRA DE DIREITOS REPROGRÁFICOS

Preencha a ficha de cadastro no final deste livro


e receba gratuitamente informações
sobre os lançamentos e as promoções da
Editora Campus.

Consulte também nosso catálogo


completo e últimos lançamentos em
www.campus.com.br
CARLOS MACHADO

Word
2000 e 97
Segredos e Soluções
© 2000, Editora Campus Ltda.

Todos os direitos reservados e protegidos pela Lei 5.988 de 14/12/73.


Nenhuma parte deste livro, sem autorização prévia por escrito da editora,
poderá ser reproduzida ou transmitida sejam quais forem os meios empregados:
eletrônicos, mecânicos, fotográficos, gravação ou quaisquer outros.

Capa
Simone Villas Boas
Editoração Eletrônica
RioTexto
Copidesque
Maria Thereza R. Corrêa de Araújo
Revisão Gráfica
Eliane de Souza
Cláudia Gomes de Amorim
Projeto Gráfico
Editora Campus Ltda.
A Qualidade da Informação.
Rua Sete de Setembro, 111 – 16º andar
20050-002 Rio de Janeiro RJ Brasil
Telefone: (21) 509-5340 FAX (21) 507-1991
E-mail: info@campus.com.br

ISBN 85-352-0591-8

CIP-Brasil. Catalogação-na-fonte.
Sindicato Nacional dos Editores de Livros, RJ

M13w
Machado, Carlos
Word 2000 e 97 : segredos e soluções / Carlos Machado.
– Rio de Janeiro : Campus, 2000
: + CD-ROM

ISBN 85-352-0591-8

1. Microsoft Word (Programa de computador). 2. Visual


Basic (Linguagem de programação de computador). I. Título

00-0486 CDD – 005.3


CDU – 004.42
00 01 02 03 5 4 3 2 1

Todos os esforços foram feitos para assegurar a precisão absoluta das informações apresentadas nesta
publicação. A editora responsável pela publicação original, a Editora Campus e o(s) autor(es) deste livro
se isentam de qualquer tipo de garantia (explícita ou não), incluindo, sem limitação, garantias implícitas
de comercialização e de adequação a determinadas finalidades, com relação ao código-fonte e/ou às
técnicas descritos neste livro, bem como ao CD que o acompanha. A Editora Campus e o(s) autor(es)
não se responsabilizam por problemas relacionados à funcionalidade do código-fonte para datas
a partir de 01/01/2000.
DEDICATÓRIA
Para Maria José, minha mulher, pelo apoio de sempre.

AGRADECIMENTOS
Ao analista de sistemas Antonio Augusto Ferreira, que, a meu pedido, desenvol-
veu a biblioteca Extens32.dll, para escrever valores monetários por extenso. Te-
nho especial apreço por essa DLL porque sei que é, comprovadamente, uma fer-
ramenta utilíssima no dia-a-dia dos escritórios.
A Alexandre Palareti, que talvez não faça idéia do quanto me estimulou ao
fazer insistentes cobranças para que eu escrevesse este livro.

O AUTOR
Carlos Machado é jornalista especializado em informática, área em que trabalha
desde 1988. Envolvido com programação desde os pré-históricos tempos do
DOS, dedica especial atenção a soluções que atacam dificuldades do dia-a-dia.
Acredita que, mesmo modestas, elas é que mostram ao usuário a verdadeira uti-
lidade da tecnologia.
Carlos Machado é formado em jornalismo e também estudou engenharia,
de onde trouxe o gosto por temas técnicos. Embora tenha escrito dezenas de so-
luções na área de programação, publicadas em revistas e na Internet, este é o seu
primeiro trabalho na forma de livro. Carlos Machado é editor da revista Info
Exame, da Editora Abril.

V
Sumário

PARTE 1
INTRODUÇÃO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . IX

1 TRINTA PROJETOS E UM LANCE DE DADOS . . . . . . . . . . . . . . . . . . . 3


Um sumário das soluções práticas desenvolvidas neste livro . . . . . . . . . . . . . . 3
O que é cada projeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2 COMO USAR O CD-ROM . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9


Instalação e uso dos arquivos de exemplo . . . . . . . . . . . . . . . . . . . . . . 9
Como instalar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
Observações importantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

3 DICAS, TRUQUES E TOQUES . . . . . . . . . . . . . . . . . . . . . . . . . . 12


Pequenas soluções que tornam seu trabalho com o Word mais rápido e agradável. . . 12
Ao lado do texto, sem truques . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

4 FIQUE RICO NA BOLSA DE TEMPO . . . . . . . . . . . . . . . . . . . . . . . 34


Invista um minuto e ganhe milhões (de minutos) em produtividade . . . . . . . . . . 34
Estilos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Modelos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
Menus e barras de ferramentas . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
Formulários. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43

5 MUITO PRAZER, VBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46


Uma breve apresentação do Visual Basic for Applications . . . . . . . . . . . . . . 46
Um pouco de história . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
VB, VBA e VBScript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Com você, o VBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
Partes de um projeto VBA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
Procedimentos do Visual Basic . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Tipos de variáveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Escopo das variáveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59

PARTE 2
6 O SISTEMA INFORMA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Um programa que mostra dados sobre a máquina, o Windows e o Word . . . . . . . 69
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
7 QUANTOS ANOS VOCÊ TEM? . . . . . . . . . . . . . . . . . . . . . . . . . 76
Calcule idades com precisão, baseado na data atual fornecida pelo micro . . . . . . 76
Desenho do formulário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78

8 DUAS DATAS E UM NÚMERO . . . . . . . . . . . . . . . . . . . . . . . . . . 80


Um programa que calcula datas e prazos simples . . . . . . . . . . . . . . . . . . 80
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84

9 SEU WORD SALVA ARQUIVOS XMW? . . . . . . . . . . . . . . . . . . . . . . 86


Descubra quais arquivos externos seu Word sabe ler ou escrever . . . . . . . . . . . 86
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

10 MUITO ALÉM DO VELHO E CONHECIDO DOC . . . . . . . . . . . . . . . . . 94


Crie um conversor de arquivos do Word para vários outros tipos de documentos . . . 94
A lógica do conversor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101

11 NA TABUADA DO 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
Crie documentos com numeração seqüencial automática . . . . . . . . . . . . . 104
Memorando numerado interno . . . . . . . . . . . . . . . . . . . . . . . . . . 107
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110

12 DE UM EM UM, PARA VÁRIOS DOCUMENTOS . . . . . . . . . . . . . . . . . 113


Crie documentos com numeração seqüencial automática . . . . . . . . . . . . . 113
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116

13 PALAVRAS QUE VALEM DINHEIRO . . . . . . . . . . . . . . . . . . . . . . . 117


Duas soluções para escrever, automaticamente, valores monetários por extenso . . . . 117
A macro EscreveExtenso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
O aplicativo Valor por Extenso . . . . . . . . . . . . . . . . . . . . . . . . . . 121
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

14 DOCUMENTOS À LA CARTE . . . . . . . . . . . . . . . . . . . . . . . . . . 124


Torne, realmente, automática a emissão de memorandos e outros papéis . . . . . . 124
Construção do formulário . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
O código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130

15 PARA NÃO REPETIR O REPETIDO . . . . . . . . . . . . . . . . . . . . . . . . 132


Ensine o Word a contar e marcar palavras já usadas dentro de um documento. . . . . 132
O mecanismo de busca e contagem. . . . . . . . . . . . . . . . . . . . . . . . 134
Histórico de busca . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137

16 TODAS AS FONTES, NA TELA E NO PAPEL . . . . . . . . . . . . . . . . . . . 139


Um aplicativo para visualizar e imprimir as fontes instaladas no sistema . . . . . . . 139
Catálogo de fontes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148

17 UM PROJETO CHEIO DE ESTILO . . . . . . . . . . . . . . . . . . . . . . . . 150


Organize catálogos de todos os estilos disponíveis no Word. . . . . . . . . . . . . 150
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
VIII
18 NO PARAÍSO DAS SECRETÁRIAS . . . . . . . . . . . . . . . . . . . . . . . . 155
Um programa que demonstra recursos do VBA aplicados a tabelas do Word . . . . . 155
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162

19 O WORD TAMBÉM TOCA MÚSICA! . . . . . . . . . . . . . . . . . . . . . . 164


Uma aplicação para executar arquivos MP3, WAV e MID . . . . . . . . . . . . . . 164
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168

20 OS OBJETOS COMANDAM O RITMO . . . . . . . . . . . . . . . . . . . . . 169


Faça a programação com objetos soar como música aos seus ouvidos . . . . . . . 169
A solução tradicional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
Com orientação a objeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
SoundPlayer: criação de uma classe de objetos . . . . . . . . . . . . . . . . . . 175
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182

21 MALA DIRETA NUM CLIQUE . . . . . . . . . . . . . . . . . . . . . . . . . . 184


Produza cartas personalizadas com dados do Word, do Access ou do Excel . . . . . 184
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191

22 NO COMANDO DE TODAS AS BARRAS . . . . . . . . . . . . . . . . . . . . 193


Uma aplicação que lista todas as barras de menus e de ferramentas do Word . . . . . 193
O código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 200

23 TODOS OS ÍCONES À SUA DISPOSIÇÃO . . . . . . . . . . . . . . . . . . . 202


Como criar um catálogo de todas as imagens de botões disponíveis no Word . . . . . 202
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 208

24 UM QUEBRA-CABEÇA DE NÚMERO E CORES . . . . . . . . . . . . . . . . . . 211


Domine os 16,7 milhões de cores existentes no arco-íris de seu monitor . . . . . . . 211
O aplicativo Cores. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213
O código do programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216

25 FAZENDO OS PAPÉIS DA SORTE . . . . . . . . . . . . . . . . . . . . . . . . 218


Construa um programa que organiza e imprime cupons para sorteios . . . . . . . . 218
O formulário do projeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 220
O código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 224

26 CLONES AO GOSTO DO FREGUÊS . . . . . . . . . . . . . . . . . . . . . . 226


Produza documentos numerados com quantidade de cópias indicada pelo usuário . . 226
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 228

27 PARA ACABAR COM A “LETRA DE MÉDICO” . . . . . . . . . . . . . . . . . . 230


Um programa que emite receitas para médicos e dentistas . . . . . . . . . . . . . 230
O documento-modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
O formulário frmReceita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 232
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239

28 EPA! WORD COM BANCO DE DADOS? . . . . . . . . . . . . . . . . . . . . 242


Use o processador de texto para gerenciar arquivos do Access . . . . . . . . . . . 242
O código por trás do formulário. . . . . . . . . . . . . . . . . . . . . . . . . . 246
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 253 IX
29 OS DADOS ESTÃO NA PLANILHA . . . . . . . . . . . . . . . . . . . . . . . 255
No Word, use os métodos do Access para gerenciar arquivos do Excel . . . . . . . . 255
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 258

30 DO BANCO DE DADOS PARA O DOCUMENTO . . . . . . . . . . . . . . . . 260


Monte um controle imobiliário com o Word e recursos de bancos de dados . . . . . 260
Ficha do projeto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260
As caixas Tratamento, Mês e Ano . . . . . . . . . . . . . . . . . . . . . . . . . 262
Caixa de combinação Localizar . . . . . . . . . . . . . . . . . . . . . . . . . 263
Detector de alterações . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 263
Emissão de recibos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265
Relatório . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269

31 UM RECIBO PARA TODAS AS TRANSAÇÕES. . . . . . . . . . . . . . . . . . . . 273


Crie um gerador de recibos configurável para diferentes usos e situações . . . . . . 273
O que faz o Gerador de Recibos . . . . . . . . . . . . . . . . . . . . . . . . . 274
Orelha Empresa e Cidade . . . . . . . . . . . . . . . . . . . . . . . . . . . . 277
O aplicativo por dentro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 279
O formulário . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 280
O código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 282
Comentários finais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289

32 FAÇAM AS SUAS APOSTAS! . . . . . . . . . . . . . . . . . . . . . . . . . . 291


Como construir um jogo de dados gráfico com três modalidades de apostas . . . . . 291
Desenho da interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 294
A lógica do programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 295
Modalidade Comum. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
Modalidade Ordem . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 297
Modalidade Soma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 298
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 300

33 NÃO FIQUE FORA DO PRAZO! . . . . . . . . . . . . . . . . . . . . . . . . 302


Um calendário que faz operações com datas, e sabe contar sábados,
domingos e feriados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 302
Construção do formulário principal . . . . . . . . . . . . . . . . . . . . . . . . 305
Formulário frmFeriados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 311
Formulário frmNovosFeriados . . . . . . . . . . . . . . . . . . . . . . . . . . 313
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 318

34 MAGO DE CASA TAMBÉM FAZ MILAGRE . . . . . . . . . . . . . . . . . . . . 323


Crie, você mesmo, um Assistente para extrair informações de bancos de dados. . . . 323
A lógica do Assistente . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 327
Saída para o Word . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 337
Saída para o Excel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338
Detalhes finais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 339
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341

35 INSTALE E DESINSTALE SEUS PROGRAMAS . . . . . . . . . . . . . . . . . . 343


Monte um instalador de aplicações num documento do Word. . . . . . . . . . . . 343
Para ir mais além . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 350

X
Introdução

O LADO ESCURO DA LUA


Este livro foi escrito com um objetivo: mostrar ao leitor que alguns dos programas
de escritório, com os quais ele convive no dia-a-dia, também podem funcionar
como poderosas ferramentas para a criação de funções novas e personalizadas,
que jamais estarão disponíveis nas caixas de diálogo e menus desses programas.
A idéia do software de escritório como ferramenta para criar outras ferra-
mentas pode ser aplicada, hoje, a uma vasta gama de produtos. No entanto, es-
colhi trabalhar com o Microsoft Word, que é, de longe, o software mais utiliza-
do no Brasil. Assim, se o livro fizer jus ao seu objetivo, a idéia poderá chegar a
um número mais amplo de usuários.
A obra está organizada em duas partes. Na primeira, tenta-se aproximar o
leitor de alguns aspectos do uso interativo do Word que vão facilitar a compreen-
são da parte final. Esta última é dedicada à criação de aplicações, usando o Visual
Basic for Applications, VBA, a linguagem de desenvolvimento embutida em aplica-
tivos do Office 97 e do 2000 e em dezenas de outros programas do mercado.
Na porção inicial do livro, mostra-se, por exemplo, como criar, personali-
zar e apagar menus e barras de ferramentas. Esse conhecimento será útil mais
tarde, quando o leitor quiser que as próprias macros sejam acionadas a partir de
menus ou de botões em barras de ferramentas. Fica evidente que essa parte do
volume foi concebida com os olhos voltados para a outra, que trata de progra-
mação. Mesmo assim, tudo que está incluído nela interessa a qualquer usuário
avançado, mesmo aquele que não se deseja envolver com o que vem depois.
Interessa ainda a qualquer usuário minimamente curioso o capítulo “Di-
cas, truques e toques”, também incluído na primeira parte. Esse capítulo reúne
dezenas de informações úteis sobre a operação do Word 2000 ou do 97. Não se
trata de procedimentos mirabolantes, que serviriam apenas para o leitor mos-
trar que sabe. São dicas escolhidas a dedo, com o critério do uso prático.
Com esse mesmo espírito, a primeira parte do livro contém ainda um capí-
tulo no qual se faz uma apresentação sumária de cada um dos projetos que serão
desenvolvidos na Parte 2. A idéia é que, antes mesmo de analisar os projetos, o
leitor possa tirar proveito deles, inclusive utilizando-os no dia-a-dia.
A Parte 2 consiste em trinta pequenos capítulos, cada qual correspondente a
um projeto. Seguem-se, aqui, os mesmos critérios adotados no início do livro:
quase todos os projetos voltam-se para necessidades práticas do dia-a-dia.Um cal-
cula datas e prazos, levando em conta fins de semana e feriados. Outro gera reci-
bos para quem presta serviços mensais. Outro, ainda, automatiza a emissão de re-
ceitas médicas. São, quase sempre, soluções pequenas e de utilidade indiscutível.
Cada projeto termina com uma seção chamada “Para ir mais além”. Nela,
o leitor encontra sugestões sobre como ampliar ou redirecionar a solução. Em
alguns casos, foi feito um esforço para tornar o produto imediatamente utilizá-
vel. O exemplo típico desse esforço é dado pela aplicação Receita Médica. Tra-
ta-se de um programa no qual o usuário pode configurar tudo (nome, endereço,
especialidade médica ou odontológica e até o cabeçalho e o rodapé da receita
emitida). Portanto, é só pegar e usar.
No corpo de cada um desses trinta capítulos, o projeto é comentado passo
a passo e discutem-se as dificuldades de desenvolvimento e as saídas encontra-
das. Com essa abordagem, o objetivo do livro não é ensinar o leitor a programar
em Visual Basic. É, principalmente, mostrar como essas soluções foram feitas e
que ele também poderia chegar a elas, com algum esforço e curiosidade.
Curiosidade. Acredito que esta seja a chave. Não sei de nenhuma pessoa com
grande conhecimento na área de computadores que não tenha sido impulsionada por
esse motor. E isso vale, inclusive, para quem concluiu um curso de graduação na área.
Portanto, este livro é dedicado aos curiosos, a quem gosta de saber que
sempre é possível tirar mais de uma ferramenta como o Word, fazendo-a traba-
lhar em seu favor. Acredito que este volume também seja útil a estudantes que
estejam dando os primeiros passos em programação. Não existe aqui uma pos-
tura didática formal, mas há alguma experiência a transmitir na base da aprendi-
zagem fundamentada em exemplos.
Penso também que algumas soluções mostradas aqui interessam até mesmo
aos profissionais de informática. Em boa parte dos casos, eles estão voltados para
os grandes problemas – bancos de dados corporativos, redes, aplicações para a
Internet – e não têm condições de debruçar-se diante de um assunto “menor”,
como o desenvolvimento em programas de escritório. Nesse aspecto, o usuário
comum fica órfão, inclusive nas grandes empresas. Ele não tem a técnica que lhe
permite resolver os problemas. E quem a tem, está ocupado em outras tarefas...
Pelas características mostradas acima, o livro volta-se para o usuário inter-
mediário ou avançado do Word. Isso não entra em contradição com as indicações
registradas na ficha que abre cada capítulo de desenvolvimento. Lá, você vai en-
contrar níveis iniciante, intermediário e avançado. Essa classificação não se refere
aos usuários do Word em geral, mas especificamente ao programador VBA.
O Word é como a lua. Tem um lado claro, brilhante, ao alcance de todos os
olhares. Mas esconde, também, uma face desconhecida. Entretanto, tenho cer-
teza, existe no ar uma curiosidade imensa. As pessoas querem saber, explorar,
descobrir. Este volume é uma lanterna apontada para esse lado escuro. Espero,
sinceramente, que ele seja útil.
CARLOS MACHADO
XII São Paulo, janeiro de 2000
PARTE 1
1
Trinta projetos
e um lance de
dados

Um sumário das soluções práticas


desenvolvidas neste livro
Os trinta projetos de desenvolvimento reunidos na Parte 2
deste livro trabalham com a idéia de mostrar, na prática,
como usar os principais recursos de programação do
VBA/Word disponíveis nas versões 97 e 2000. Cada pro-
jeto ocupa um capítulo e exige um nível técnico crescen-
te. Inicialmente, o foco do projeto está apenas num item
técnico. Passo a passo, a complexidade das aplicações
vai-se expandindo. Vamos avançar de um simples cálculo
de idade até a estrutura complicada de um assistente para
extrair informações de qualquer banco de dados Access.
Sempre que possível, são discutidas as dificuldades
do processo de desenvolvimento, ao lado de saídas alter-
nativas que o leitor poderia adotar. Ao percorrer estas pá-
ginas, deve-se sempre ter em mente que o objetivo delas
não é decretar: “Esta é a maneira correta de fazer isso.”
Assim como um idioma natural, as linguagens e ferramen-
tas de programação também são flexíveis. Não há uma
forma “certa” de escrever uma carta, um relatório, um bi-
lhete. Do mesmo modo, não existe uma receita definitiva
em programação. Portanto, o leitor deve encarar estes
projetos como pontos de partida, como sugestões para
que ele mesmo encontre soluções.
Nos projetos, procura-se trabalhar com os recursos disponíveis no
VBA/Word, sempre de olho em objetivos práticos. Nada de pirotecnias de pro-
gramação, acessíveis somente aos que dominam artes inacessíveis para mortais
comuns. Alguns projetos voltam-se imediatamente para tarefas cotidianas. É o
caso, por exemplo, daquele que automatiza a emissão de memorandos numera-
dos (Capítulo 14). Ou, então, do outro que emite receitas médicas (Capítulo 27)
e ainda do gerador universal de recibos para prestadores de serviços (Capítu-
lo 31). Trata-se de aplicações prontas. Mesmo quem não tem a menor curiosida-
de a respeito de programação pode beneficiar-se, imediatamente, desses progra-
mas.

F I G U R A 1 . 1 Gerador de Recibos: para prestadores de serviços

Outros projetos, embora sem o mesmo apelo prático, voltam-se para o de-
senvolvedor em ambiente VBA/Word. São ferramentas nas quais ele pode se
apoiar em sua tarefa de criar novas soluções. Destacam-se, nesse caso, o Catálo-
go de Fontes (Capítulo 16), os Exercícios com Tabelas (Capítulo 18) e o Instala-
dor de Aplicações (Capítulo 35). Este último, adaptado, pode servir de modelo
para a instalação de quaisquer programas no ambiente do Word.
Para não dizer que cuidei apenas de assuntos ligados direta ou indireta-
mente à reprodução vil metal, incluí também um projeto que é útil em termos da
experiência de programação, mas absolutamente fútil em termos de produtivi-
dade. Trata-se do game Álea, um jogo de azar com dois dados e três modalida-
des de aposta. Além de demonstrar procedimentos gráficos, o desafio desse pro-
grama é manter a aleatoriedade em cada jogada. Aqui, o comando pertence ao
acaso. Afinal, como escreveu o mestre Mallarmé, um lance de dados jamais abo-
lirá o acaso.

4
F I G U R A 1 . 2 Catálogo de Fontes: listagem na tela e em
documento para impressão

F I G U R A 1 . 3 Álea, um jogo de azar com dois dados e três


modalidades de aposta

Além de apresentar em detalhes a lógica de construção de cada projeto, os


capítulos da Parte 2 deste volume sempre terminam com uma seção chamada
“Para ir mais além”. Nela, o leitor encontra sugestões sobre como ampliar e per-
sonalizar o projeto ou simplesmente refazê-lo a partir de outra perspectiva.
Também no final de cada capítulo estão uma ou mais dicas de programa-
ção. Algumas delas são bastante complexas e renderiam assunto para outros de-
senvolvimentos. Todos os projetos e dicas de código encontram-se no CD-ROM
que acompanha o livro. Veja no próximo capítulo como instalar e usar os recur-
sos desse CD.
Espero que os trinta projetos da Parte 2 sirvam de base para você tomar
gosto e construir trinta vezes trinta outras soluções da própria cabeça. Veja, a se-
guir, uma descrição sumária de cada projeto incluído na parte final do livro.

5
O que é cada projeto
CAPÍTULO PROJETO O QUE FAZ

6 Informações Demonstra como obter informações sobre o sistema


do Sistema operacional, a máquina e o Word. Acessa o Painel de
Controle e o utilitário Informações do Sistema, do
Windows.

7 Cálculo de Idade Calcula a idade exata, em anos, a partir da data de


nascimento. Propicia um primeiro contato com funções
do VBA associadas a data e hora.

8 Cálculo de Datas Executa operações de soma e subtração com datas e


prazos. Representa a introdução a um tema que será
desenvolvido integralmente no Capítulo 33, num dos
projetos mais complexos do livro.

9 Conversores de Produz uma tabela com todos os conversores de


Arquivos arquivos disponíveis no Word. Indica os tipos de
arquivo que o programa pode ler e salvar.

10 Conversor de Converte arquivos no formato DOC, do Word 2000 ou


Arquivos DOC 97, para TXT, RTF e HTML, além de DOC do Word 6.0
e do Word 2.0. Útil quando se deseja converter grande
quantidade de arquivos.

11 Documento Produz documentos com numeração seqüencial do tipo


Numerado 001/2000, 002/2000. Na virada do ano, recomeça a
Simples contagem. Trabalha com um arquivo INI para
armazenar as informações de data e numeração.

12 Vários Semelhante ao projeto 11, controla a numeração


Documentos seqüencial de vários tipos de documentos ao
Numerados mesmo tempo: memorandos, cartas, ofícios e
relatórios.

13 Gerador de Escreve, automaticamente, números por extenso, em


Valores por reais. Trabalha também com outras moedas.
Extenso

14 Memorando Produz memorandos numerados, automatizando


Numerado também o preenchimento do cabeçalho do documento:
nomes do remetente e dos destinatários principal e
secundários, além de data e assunto.

15 Contador de Ferramenta auxiliar na revisão de texto. Conta palavras


Expressões ou expressões repetidas e, opcionalmente, destaca-as
com o pincel marcador.

16 Catálogo Exibe na tela amostras das fontes disponíveis no


de Fontes Windows. Também produz um catálogo para
impressão com fontes em tamanho escolhido pelo
usuário.
6
CAPÍTULO PROJETO O QUE FAZ

17 Catálogo de Lista, na tela e no papel, todos os estilos disponíveis no


Estilos Word – os embutidos no programa e os criados pelo
usuário.

18 Exercícios com Executa dez operações com tabelas, usando métodos


Tabelas do VBA/Word. Cria, destrói e formata tabelas. Adiciona
e subtrai linhas e colunas. Efetua cálculos com valores
das células.

19 Som no Toca arquivos de áudio WAV e MID a partir do


Word 1 Word, usando o acessório Mídia Player. Demonstra
como executar operações por meio de programas
externos.

20 Som no Gera listagens de arquivos de áudio e dispara a


Word 2 execução de sons WAV, MID e MP3 em programas
MP3 players. Destaque para o desenvolvimento,
empregando programação orientada a objeto.

21 Mala Direta Organiza malas diretas com informações extraídas


de três diferentes fontes de dados: arquivos do Word,
bancos de dados Access e planilhas Excel.

22 Barras de Lista todas as barras de comandos existentes


Ferramentas no Word, permitindo exibi-las e ocultá-las.
Oferece informações detalhadas sobre cada barra.
Lista também os botões e outros controles existentes
em cada uma.

23 Botões de Exibe, em barras de ferramentas enormes, todos os


Comando botões de comando existentes no Word. Auxilia o
programador a escolher ícones para os próprios
aplicativos.

24 Cores RGB Demonstra o sistema de cores usado nos monitores.


Apresenta, na prática, como se formam os 16,7
milhões de cores do sistema RGB e como se calculam
os números associados a essas cores.

25 Bilhetes Produz bilhetes numerados com base num


Numerados layout de documento definido pelo usuário.
Demonstra a programação com objetos de desenho do
Word.

26 Documentos Gera documentos numerados múltiplos, em


Repetidos quantidades indicadas pelo usuário. Se, por exemplo, a
quantidade é 3, os documentos obedecem à seqüência
1,1,1-2,2,2 etc.

27 Receita Médica Automatiza completamente a emissão de receitas


médicas. Configurável, pode ser usado, de imediato,
por médicos ou dentistas, sem a necessidade de
qualquer modificação no projeto.
7
CAPÍTULO PROJETO O QUE FAZ

28 Banco de Dados Gerencia bancos de dados Access a partir do Word,


no Word usando apenas programação VBA. Não requer a
presença do Access no sistema.

29 Planilha Excel Trabalha, no Word, com uma planilha Excel, tratada


como Banco de como banco de dados do Access. Não exige a presença
Dados do Excel.

30 Do Banco de Gera relatórios e outros documentos com informações


Dados para o extraídas de um banco de dados Access. O exemplo é
Documento adaptado para uma imobiliária e produz recibos de
aluguel.

31 Gerador Um programa que é a mãe de todos os recibos. Assim


de Recibos como o Receita Médica (projeto 27), é configurável
para cadastrar clientes, usuários e tipos de serviços
prestados.

32 Jogo de Afinal, uma diversão – que ninguém é de ferro! Jogo


Dados Álea de azar com dois dados e três modalidades de aposta.
Demonstra características gráficas do VBA.

33 Prazo Certo Calcula prazos, levando em conta uma tabela de


feriados atualizável pelo usuário. Traz embutidos os
feriados nacionais, fixos e móveis, até 2010. Para
advogados, contadores e escritórios comerciais.

34 Assistente de Um assistente que conduz o usuário, passo a passo,


Bancos de Dados para abrir e extrair informações de qualquer banco de
dados Access. O resultado é apresentado numa tabela
do Word ou numa planilha Excel.

35 Instalador de Mostra como instalar programas a partir de um


Aplicações documento do Word. Este demonstrativo instala os
arquivos e os módulos de programação do projeto 31
(Gerador de Recibos).

8
2
Como usar
o CD-ROM

Instalação e uso dos arquivos de exemplo


Todos os exemplos de programação citados neste livro
estão reproduzidos no CD-ROM que o acompanha. Na
maioria dos casos, o texto inclui apenas as partes mais
importantes do código. Não se preocupe: no CD, inva-
riavelmente, você vai encontrar a rotina ou projeto na
íntegra. Isso vale, inclusive, para as rotinas incluídas
como dicas no final dos capítulos.
A estrutura dos arquivos e diretórios do CD-ROM é
simples. Somente na Parte 2 do livro existem listagens de
código. Como essa parte contém trinta capítulos, estes se
refletem no CD. Para cada um existe uma pasta: Capítulo
6, Capítulo 7 etc. Dentro desses diretórios, você encontra
todos os itens necessários para o funcionamento do pro-
jeto ou dica constante no capítulo.
Desse modo, você vai encontrar, nesses diretórios,
arquivos conforme a tabela seguinte:

TIPO DE ARQUIVO O QUE É

.DOC Documento comum do Word

.DOT Modelo do Word. Pode conter


documento-base (por exemplo, o
modelo para um tipo de recibo) e/ou
projeto de automação VBA
.FRM Arquivo de formulário do VBA

.FRX Arquivo complementar do formulário VBA


TIPO DE ARQUIVO O QUE É

.BAS Arquivo de módulo do VBA. Contém apenas código

.CLS Arquivo de classe VBA. Refere-se a programação orientada a


objeto

.MDB Banco de dados do Access

.XLS Pasta de trabalho do Excel

Como instalar
Somente alguns arquivos são necessários para que você possa executar qualquer
um dos projetos em seu micro. Portanto, dê um clique duplo no arquivo Insta-
lar.dot. Esse modelo do Word, que contém código, vai copiar para o seu disco
os arquivos necessários à execução de qualquer programa do livro.
A qualquer momento, você pode recorrer ao CD e executar programas
(normalmente arquivos DOT) diretamente a partir dele. Como já foi dito antes,
cada programa está contido no diretório correspondente ao capítulo.

Observações importantes
1. Todos os projetos e códigos isolados deste livro foram testados exausti-
vamente em máquinas com o Word 97 e o Word 2000.No entanto, há
mais versões do Word espalhadas por aí do que supõe a nossa vã filoso-
fia. Então – embora não tenhamos constatado isso –, há possibilidade de
algum código não funcionar. Nesse caso, primeiro tente reconstruir o
projeto em seu micro, carregando os componentes (arquivos FRM, BAS
etc.) que estão no diretório correspondente. Se, mesmo assim, não fun-
cionar, entre em contato conosco.
2. Ao carregar projetos que envolvem o uso da tecnologia DAO (Data
Access Objects) de bancos de dados, eles tendem a não funcionar, num
primeiro momento, em sua máquina. Isso vale tanto para rodar um pro-
jeto pronto – diretamente do CD ou copiado dele – como para a impor-
tação do projeto a partir dos arquivos FRM e BAS. O programa vai exi-
bir uma mensagem nos seguintes termos: “Erro de compilação. O tipo
definido pelo usuário não foi definido.”
Não se preocupe. No ambiente do VBA, acione Ferramentas/Refe-
rências. Na tela que se abre, marque a opção:
n Microsoft DAO 3.5 Object Library, se estiver no Word 97; ou
n Microsoft DAO 3.6 Object Library, se seu Word for o 2000.
10
F I G U R A 2 . 1 Ajuste para bancos de dados: aqui, marcada a
opção para o Word 2000

3. Quando você copiar um arquivo do CD para o seu disco rígido, não se


esqueça de ajustar os atributos desse arquivo. No CD-ROM, por defini-
ção, ele é do tipo somente leitura. Ao ser copiado para o disco rígido,
essa característica se mantém. Então, você não poderá editar esse arqui-
vo. Para evitar que isso ocorra, depois de copiar o arquivo, clique nele
com o botão direito, selecione Propriedades e desligue a opção Somente
Leitura.
4. Se sua versão do Word é a 2000, vá em Ferramentas/Macro/Segurança e
escolha o nível de segurança médio. Se o nível vigente for alto, você não
vai conseguir abrir os programas executando os arquivos DOT. Com
essa configuração, o Word simplesmente desativa as macros contidas no
documento – e não dá nenhum aviso ao usuário.

11
3
Dicas, truques e
toques

Pequenas soluções que tornam seu trabalho


com o Word mais rápido e agradável
Neste capítulo você encontra dezenas de jeitinhos e mace-
tes extraídos da pesquisa ou do uso cotidiano do Word 97
e do 2000. Na maioria dos casos, os procedimentos se
aplicam às duas versões do produto. As situações de vali-
dade exclusiva para uma ou outra versão estão claramen-
te indicadas no texto.

Seleção rápida: coluna


Para selecionar rapidamente toda uma coluna de tabela,
faça o seguinte: leve o ponteiro do mouse até a borda supe-
rior da primeira célula da coluna e clique quando aparecer
uma pequena seta em negrito apontando para baixo.

F I G U R A 3 . 1 Quadrados para seleção de tabelas


Seleção rápida: tabela inteira
O Word 2000 aperfeiçoou bastante os recursos de tabelas. Uma das novidades é
um pequeno quadrado que aparece no canto superior esquerdo ou no canto in-
ferior direito da tabela quando se passa o mouse sobre ela. Para selecionar toda a
tabela, basta clicar num desses quadrados. Os dois têm também outras funções.
O quadrado superior, cujo nome oficial é alça de movimentação, serve como
ponto de apoio para arrastar toda a tabela. O outro, chamado alça de redimen-
sionamento, permite redefinir o tamanho da tabela.

F I G U R A 3 . 2 Lista numerada na tabela

Numeração automática de colunas


Você está trabalhando com uma tabela. Depois de aprontá-la, decide que seria
melhor incluir uma coluna à esquerda, numerando seqüencialmente cada linha
da tabela. Por favor, nem pense em sair escrevendo: 1, descer para a próxima li-
nha; 2, descer para a linha seguinte... Nada disso: selecione a coluna a ser nume-
rada e acione o botão numeração (aquele que mostra os números 1, 2, 3, segui-
dos de linhas). Pronto. A coluna está numerada. Em textos comuns, se você tiver
uma série de parágrafos e quiser numerá-los, o procedimento é o mesmo: sele-
cione os parágrafos e clique no botão Numeração.

Tabulação dentro da célula


Cada célula de uma tabela funciona como uma página normal do Word. Nela,
você pode definir diferentes tipos de parágrafos, recuos à esquerda e à direita,
fontes etc. Você só não pode acionar a tecla Tab para obter o espaçamento de ta-
bulação, como faz numa página normal. Isso porque, na tabela, Tab serve como
comando de mudança para a próxima célula. Então, o que fazer para tabular
dentro de uma célula? Simples: acione Ctrl+Tab.

Célula sem quebras


Quando há no documento uma tabela que passa de uma página para outra, é co-
mum uma linha da tabela ficar dividida entre as duas páginas. Há uma forma de
evitar isso, que é a mesma usada para os parágrafos. Selecione as células partidas
e acione o comando Formatar/Parágrafo, clique na orelha Quebras de Linha e 13
de Página e ligue a opção Manter Com o Próximo. Para que essa configuração
valha para todas as linhas da tabela, aplique o mesmo comando à tabela inteira.
Isso vale para o Word 97 e para o Word 2000. Neste último, no entanto, tam-
bém há um novo caminho. Selecione a linha desejada e clique em Tabela/Pro-
priedades da Tabela. Na caixa de diálogo Propriedades da Tabela (não existia
no Word 97), selecione a orelha Linha e desligue a opção Permitir Quebra de
Linha Entre Páginas. Como padrão, essa opção fica ligada.

Hifenização automática
Quer que, como padrão, o documento seja automaticamente hifenizado?
Escolha Ferramentas/Idiomas/Hifenização. Na caixa de diálogo que se abre,
ligue a caixa de verificação Hifenizar o Documento Automaticamente. Acio-
ne OK. Mas ainda não terminou. A hifenização automática é uma função do
Word que só vale para cada documento. Para transformá-la num padrão, o
caminho é um pouco mais longo. Crie um documento e adicione a ele a hife-
nização automática. Em seguida, salve-o como um modelo. Agora, quando
quiser trabalhar com esse recurso, abra um documento novo baseado naque-
le modelo.

F I G U R A 3 . 3 Word 2000: nova caixa de diálogo para


14
tabelas
Ao lado do texto, sem truques
Até o Word 97, você precisava fazer algumas ginásticas para posicionar uma ta-
bela lado a lado com o texto do documento. Um desses truques era colocar a ta-
bela dentro de uma caixa de texto (objeto de desenho). No Word 2000, esse tru-
que não é mais necessário. A nova caixa de diálogo exibida pelo comando Tabe-
la/Propriedades da Tabela permite dispor a tabela em várias posições em relação
ao texto: à esquerda, centralizada, à direita etc. Basta selecioná-la e escolher a
posição desejada.

Direto do Excel, sem escala


Aposto que, para inserir num documento uma tabela do Excel, você abre a pla-
nilha, copia o pedaço desejado e cola-o no texto do Word. Não é preciso fazer
isso; o Word sabe ler diretamente a planilha. Acione Arquivo/Abrir, no Word.
Na caixa Arquivos do Tipo, indique Planilha do Microsoft Excel (*.xls) e aponte
para o arquivo desejado. Surge nova janela, Abrir Planilha. Ela lhe permite abrir
a pasta de trabalho inteira ou escolher uma folha de cálculo específica. Dentro
desta, pode ainda escolher uma região de células.

Buquê de documentos
Você está trabalhando num projeto que envolve, por exemplo, vários textos do
Word e planilhas Excel. Que tal organizar um documento que funcione como
um menu, ou porta de entrada, para todos os documentos do projeto? Faça o se-
guinte: escreva uma página de introdução com a lista dos documentos e o sumá-
rio do conteúdo de cada um deles. Agora, a dica: adicione hyperlinks. Assim, a
partir dessa introdução, com um clique você passa a ter acesso direto aos outros
documentos. Essa solução funciona, inclusive, em ambiente de rede – desde que
os documentos se encontrem num local acessível a todos os usuários. Se quiser
fazer o encadeamento perfeito, inclua em cada documento do buquê um link
para o documento-índice.

Palavra errada no dicionário


Sem querer, você inclui no dicionário do Word uma palavra errada. E agora?
Calma. Acione Ferramentas/Opções e ponha em primeiro plano a orelha Orto-
grafia e Gramática. Clique no botão Dicionários e, na próxima tela, no botão
Editar. Se for o caso, o Word vai avisar que, para editar o dicionário, será preci-
so desligar a correção automática. Aceite. A lista de palavras que você incluiu no
dicionário vai aparecer. Localize o termo incluído por engano, elimine-o (ou
corrija-o) e salve o documento.

15
F I G U R A 3 . 4 Sinônimos para a palavra “aparece”

Sinônimos
Ao escrever, de repente você percebe que já usou a mesma palavra uma porção
de vezes e gostaria de variar. Quer encontrar um sinônimo rapidamente? Colo-
que o cursor sobre a palavra e tecle Shift+F7. O Word abre a janela do dicioná-
rio e oferece o leque de sinônimos que ele tem a apresentar. Não é nenhum su-
perdicionário, mas quebra o galho. Se você é um profissional da escrita e quer
mais, instale em sua máquina um Aurélio ou um Michaelis eletrônico.

Dicionários personalizados
Quem escreve documentos ligados a diferentes áreas de conhecimento precisa,
muitas vezes, de dicionários especializados. Por exemplo, um vocabulário para a
área médica, outro para a de psicologia etc. O Word aceita que você crie esse
tipo de dicionário. Primeiro, crie um novo documento e escreva nele as palavras
iniciais de um dicionário específico. Cada termo deve ocupar uma linha. Assim:

Explorer
Java
WinZip
Word
add-on
barramento
bug
cavalo-de-tróia
drive
drives

Observe que há duas ordens alfabéticas: primeiro, as palavras com ini-


16 ciais maiúsculas; depois, as outras. Salve o arquivo como Somente Texto, com
a extensão DIC. Verifique onde está seu dicionário personalizado padrão
(Usuario.dic) e coloque lá o novo glossário. O diretório varia, conforme a ver-
são do Word. Agora, dê o comando Ferramentas/Opções, orelha Ortografia e
Gramática. Clique no botão Dicionários e, na caixa Dicionários Personaliza-
dos, marque aquele que você acabou de criar. Na hora de fazer a verificação
ortográfica (Ferramentas/Ortografia e Gramática), clique no botão Opções e
escolha o dicionário desejado.

Salvar tudo, fechar tudo


No Word 97, você pode trabalhar ao mesmo tempo com múltiplos documentos.
Edita aqui, corrige ali, de repente você fez modificações em vários deles e não
salvou. Para evitar a tarefa de colocar cada documento em primeiro plano e sal-
vá-lo, faça o seguinte. Pressione a tecla Shift e abra o menu Arquivo. Veja que lá
aparece um comando incomum: Salvar Tudo. Dispare esse comando e todos os
documentos serão salvos de uma vez. O mesmo procedimento pode ser adotado
para fechar os arquivos. Observe que, com a tecla Shift, também aparece o co-
mando Fechar Tudo.

F I G U R A 3 . 5 Estrutura do documento: navegação título a título

Estrutura do documento
Quando você estiver escrevendo documentos como o deste capítulo – no forma-
to um título, um bloco de texto – e quiser tomar pé da situação (quantos blocos
já escreveu, qual título vem antes de qual), clique no botão Estrutura do Docu-
mento. Ele divide a janela do Word em duas partes. À esquerda, os títulos. À di-
reita, seu texto. Clique num título e o cursor se desloca exatamente para o tre-
cho correspondente.
17
Pincel de formatos
Durante a elaboração de um texto, você quer que este parágrafo tenha o mesmo
formato (recuo, fonte, cor etc.) de outro que você já escreveu no documento
atual ou em outro documento. Não perca tempo refazendo, passo a passo, aque-
la formatação. Vá ao parágrafo que deseja tomar como modelo, selecione-o e
clique no botão Pincel. Observe que o cursor assume a figura de um pincel. Ago-
ra, selecione o parágrafo de destino. Pronto.

Aperte Ctrl+Z, o texto sumiu!


Digitou algo errado, o texto sumiu? Acione imediatamente Ctrl+Z (Desfazer) e
fique tranqüilo: tudo volta ao que era antes do susto. O comando Ctrl+Z tam-
bém é providencial para anular ações automáticas que o Word faz e você não
quer. Entre essas ações estão iniciar uma lista numerada; transformar em hyper-
link um endereço da Internet que você digita; ou colocar maiúscula inicial numa
palavra que você escreveu, conscientemente, com minúscula.

Personalização
Você já usava o Word (95, 97 ou 2000) há algum tempo e agora, por qualquer
motivo (micro ou disco novo, reformatação etc.), precisa mudar de máquina.
Como transferir para a nova instalação as macros do Word, as entradas de Auto-
Texto, os itens de AutoCorreção e as palavras adicionadas ao dicionário perso-
nalizado? Fácil. Copie para a nova máquina os arquivos ACL (AutoTexto), DIC
(Dicionário) e o modelo Normal.dot (macros e personalizações do ambiente de
trabalho). Cada um desses arquivos deverá substituir um novo – e não persona-
lizado – criado pelo Word. Não se esqueça de copiar também outros arquivos
DOT que você tenha criado.

F I G U R A 3 . 6 Barra de ferramentas padrão: dobrada em L

18
Mágica na barra de ferramentas
No Word 2000, as barras de ferramentas fazem um pouco de mágica. Para eco-
nomizar espaço, as duas barras principais (Padrão e Formatação) ficam lado a
lado na tela, e não uma em cada linha. É óbvio que, dessa maneira, não há lugar
para as duas, completas, mesmo em telas de 800´ 600 ou 1024´ 768 pixels. A so-
lução: cada barra forma uma espécie de L, cuja perna vertical se abre quando
você clica numa pequena seta. Nessa perna fica escondido o restante dos botões.
O mais interessante, porém, é que, quando se aciona um dos botões escondidos,
ele, imediatamente, passa para o lado visível da barra de ferramentas.

Seguro morreu de velho...


Por mais cuidadoso que você seja, não há como considerar-se fora do perigo de
perder um texto no qual você vinha trabalhando durante horas. No entanto,
você pode minimizar os riscos. Para isso, configure o Word para sempre fazer
uma cópia de segurança dos documentos. Como? Clique em Ferramentas/Opções
e traga para o primeiro plano a orelha Salvar. No quadro Opções de Salvamen-
to, ligue a caixa Criar Sempre Backup. Sempre que você salvar um documento, a
versão mais nova vai para o arquivo DOC normal e a anterior é mantida num ar-
quivo com o mesmo nome e extensão WBK (Word Backup). Se, por acaso, você
perder o DOC, pode recuperá-lo – se não todo, pelo menos parte dele – abrindo
o arquivo WBK.

Impressão sem aquela folha a mais


É comum encontrar usuários reclamando que o Word os faz desperdiçar papel
porque sempre imprime, além do documento, uma folha com o resumo estatís-
tico: número de páginas do documento, número de linhas, data de elaboração
etc. Muitas vezes esses usuários agem como se essa folha viesse do outro mundo.
Mas não há mistério nenhum. Basta acionar Ferramentas/Opções, orelha Impri-
mir, e desligar o item Incluir no Documento/Propriedades do Documento. E é
só. Aliás, o padrão dessa opção é desligado. Se a impressão inclui as proprieda-
des do documento, deve ser porque o próprio usuário, ou outra pessoa com
acesso ao micro, modificou a configuração básica.

Modelo com imagem


Acione, no menu, o comando Arquivo/Novo. Passe pelas diferentes orelhas da
janela Novo e verifique: alguns modelos, quando selecionados, exibem uma
imagem no lado direito da tela, outros não. Para incluir aquela miniatura de
pré-visualização num modelo, abra o arquivo DOT, dê o comando Arqui-
vo/Propriedades e, na caixa de diálogo, ative a orelha Resumo. Ligue a caixa Sal-
var Visualização da Figura. Salve o modelo e feche-o. Agora, tire a prova: volte 19
ao comando Arquivo/Novo e selecione modelo recém-criado. Detalhe: o arqui-
vo do modelo fica maior, porque incorpora um bitmap com a imagem miniatu-
rizada do documento.

F I G U R A 3 . 7 Modelo com previsão de página: figura


embutida

Desformatação rápida (1)


Suponha que você esteja editando um texto que outra pessoa escreveu. Pouco
moderada nos destaques, essa pessoa abusou das expressões em negrito, por
exemplo. Naturalmente, você pode selecionar os trechos um a um e desligar o
negrito. Mas há um meio bem mais rápido. Selecione o texto todo (Ctrl+T) ou
uma parte dele, ligue o negrito e em seguida o desligue. Pronto. Toda a área se-
lecionada retorna ao padrão normal.

Desformatação rápida (2)


Você vai editar um texto escrito por outra pessoa. Naturalmente, ela traba-
lha com um padrão de formatos que não tem nada a ver com o seu. Para ajus-
tar o documento ao padrão que você usa, selecione todo o texto e dispare a
combinação de teclas Ctrl+Shift+B. Esse comando aplica o estilo Normal à
seleção.

Imprimir parte de um documento


Quando você quer imprimir somente parte de um texto, certamente você copia
aquela parte, cola-a num documento novo, imprime e descarta esse documento.
Experimente um caminho mais curto. Selecione o trecho a ser impresso e, no
20 menu, acione Arquivo/Imprimir. Na janela Imprimir, clique na opção Seleção.
Atenção para o detalhe: isso não vai funcionar se você clicar no botão Imprimir
– que não exibe a caixa de diálogo e assume que você quer uma cópia do docu-
mento inteiro.

Figuras ocultas
Ao trabalhar com documentos longos, cheios de objetos gráficos (tabelas, figu-
ras, desenhos), o Word se torna lento quando é preciso navegar nele para cima e
para baixo. Isso ocorre porque o programa consome recursos do sistema para
exibir as imagens. Para ganhar mais agilidade nesses documentos, garanta que o
modo de visualização está em Exibir/Layout da Página. Em seguida, clique em
Ferramentas/Opções/orelha Exibir e ligue a caixa Espaços Reservados a Figuras.
A partir de agora – e não só para o documento atual –, o Word passará a mostrar
um quadro em branco no lugar das imagens. Para exibir as figuras, desfaça a
configuração.

Seleção vertical
Para selecionar texto verticalmente, mantenha pressionada a tecla Alt e movi-
mente o mouse. Essa função é útil, por exemplo, quando se deseja negritar os
números de itens de uma lista numerada. Pode ser usada também para destacar a
primeira letra de uma seqüência de parágrafos de uma só linha – não somente
com negrito, mas também aumentando o corpo da letra. Outra forma de traba-
lhar com a seleção vertical é ligá-la com a combinação de teclas Ctrl+Shift+F8
e depois desligá-la com o mesmo comando.

“Incorretor” ortográfico
Logo depois que o Word 2000 é instalado, quando se digita uma palavra como
“transformá-lo”, o corretor ortográfico entra em ação e automaticamente muda
a expressão para “transforma-lo”, sem acento. Se, imediatamente, você der o
comando Ctrl+Z, confirmando o seu “erro”, o Word incluirá a palavra com
acento na lista de exceções da AutoCorreção. Para corrigir essa trapalhada, vá
até Ferramentas/ AutoCorreção/orelha AutoCorreção e desligue a caixa Usar as
Sugestões do Verificador Ortográfico Automaticamente. A idéia é boa, mas se é
para entortar o que está certo – não, obrigado.

Clicar e digitar
Um dos novos recursos do Office 2000 chama-se Clicar e Digitar. Ele permite
que você insira texto numa área em branco do documento, sem antes teclar Tab
ou Enter para posicionar o cursor no local desejado. Para experimentar o Clicar
e Digitar, primeiro garanta que o documento esteja na opção Exibir/Layout de 21
Impressão ou Exibir/Layout da Web. Depois, escolha um ponto qualquer da pá-
gina e dê nele um clique duplo. O cursor se posiciona no local, e você começar a
digitar. Se o recurso não funcionar, é possível que esteja desativado. Então, acio-
ne Ferramentas/Opções, orelha Editar e ligue a caixa Ativar Clicar e Digitar.

F I G U R A 3 . 8 Janela Data e Hora no Word 2000: três idiomas

Data e hora
Para inserir a data e a hora atuais no seu documento, você pode acionar o co-
mando Inserir/Data e Hora e escolher, na caixa de diálogo que se abre, um dos
vários formatos de data e/ou hora que o programa oferece. No Word 2000, essa
caixa, além de trazer mais opções, opera em três idiomas: português, inglês e es-
panhol. Se você quiser que a data seja atualizada quando o documento for aber-
to, não se esqueça de ligar a caixa de verificação Atualizar Automaticamente.
Mas atenção: você verá uma nova data cada vez que abrir o documento em dias
diferentes. Se a intenção é registrar a data em que o documento foi produzido,
prefira trabalhar com a opção Inserir/Campo. Nela, indique, em Categorias,
Data e Hora; e em Campo, CreateDate.

Dias e meses sem maiúscula


Quem reclamava, com razão, que o Word 97 escrevia o nome dos meses e dos
dias da semana com iniciais maiúsculas não tem mais do que se queixar. No
Word 2000 e mesmo no 97 com o Windows 95 ou o 98 atualizados, isso não
ocorre mais. Na verdade, o problema não estava no Word, e sim no arquivo
Oleaut32.dll. As versões mais novas dessa DLL corrigiram o problema. A atua-
lização pode ocorrer por meio da instalação de qualquer programa que traga o
22 arquivo em edição mais recente – por exemplo, o Internet Explorer 5.0.
F I G U R A 3 . 9 Detalhe da janela Imprimir do Word 2000: zoom

Dezesseis páginas por folha!


O Word 2000 traz uma característica nova que, com certeza, será muito bem re-
cebida por todos os usuários. Trata-se da opção de Zoom na impressão, que per-
mite imprimir 2, 4, 6, 8 ou 16 páginas de um documento na mesma folha de pa-
pel. Para utilizá-la, acione Arquivo/Imprimir e, no quadro Zoom, indique o nú-
mero de páginas e um tamanho de papel (Carta, A4 etc.). Atenção: como pa-
drão, a caixa Ajustar ao Tamanho do Papel fica em Sem Dimensionamento. Se
você não determinar um tamanho específico, a impressão sairá com as letras en-
cavaladas. Pelo menos é o que acontece com uma HP DeskJet 660C. A impres-
são com duas páginas por folha é interessante quando se quer produzir um do-
cumento no formato de livro. Antes de imprimir, experimente para descobrir o
melhor tamanho de letra a ser usado. Lembre que, para aumentar a quantidade
de texto ocupando o mesmo espaço, o tamanho da letra terá de ser reduzido.
Naturalmente, só é possível obter dezesseis páginas por folha se o texto de cada
uma não passar de algumas poucas palavras, escritas com letras bem grandes.

Economia de papel
A opção de imprimir múltiplas páginas por folha não se aplica apenas à pro-
dução de livretos. Ela serve também para economizar papel. Quando estiver
trabalhando com rascunhos ou documentos para sua própria leitura, impri-
ma duas páginas por folha. Não é nada, não é nada, você consome a metade
do papel!

Impressão frente e verso


Quer imprimir um documento em frente e verso, usando apenas os recursos do
Word? Comande Arquivo/Imprimir e, na caixa onde está a opção-padrão Todas
as Páginas do Intervalo, escolha Páginas Ímpares. Depois, pegue todas as pági-
nas impressas e coloque-as outra vez na bandeja de papel, para imprimir o outro
lado. Agora, acione outra vez Arquivo/Imprimir e escolha Páginas Pares.

23
Maiúsculas e minúsculas
Depois de escrever o título de um documento em letras maiúsculas e minúscu-
las, você decide que seria melhor colocá-lo todo em maiúsculas. Então, o que
faz? Seleciona o texto e procura o comando Formatar/Maiúsculas e Minúscu-
las? Está certo, mas há alternativas de teclado: acione Ctrl+Shift+A para deixar
a seleção toda em maiúsculas. O mesmo comando desfaz a formatação. Outra
solução similar é Shift+F3, que troca os caracteres todos de caixa alta para bai-
xa, ou vice-versa.

Um pincel que pinta formatos


Muita gente vê aquele pincelzinho na barra de ferramentas e não sabe direito
para que ele serve. O pincel copia formatos. Digamos que existe em seu docu-
mento um parágrafo com tipo e tamanho de letra, ajuste de margens e outras de-
finições. Você quer aplicar em outro parágrafo os mesmos padrões. Coloque o
cursor no parágrafo-modelo e clique no botão Pincel. O cursor do mouse passa
a exibir um pincel. Agora, selecione o parágrafo de destino. Pronto, ele assumiu
as definições do outro.

Pincel via teclado


Você também pode usar o teclado para copiar e colar formatos, em lugar da fer-
ramenta pincel. Para isso, coloque o cursor no parágrafo cuja formatação você
deseja copiar e acione simultaneamente as teclas Ctrl+Shift+C. Agora, selecio-
ne o parágrafo de destino e tecle Ctrl+Shift+V. Note a semelhança desses co-
mandos com Ctrl+C (Copiar) e Ctrl+V (Colar). A vantagem da operação com
o mouse é exatamente a dica visual representada pelo cursor em forma de pin-
cel. Em compensação, é preciso “armar”o pincel a cada aplicação de formato,
enquanto a cópia pelo teclado pode ser aplicada seguidamente a diferentes pará-
grafos.

Interface monodocumento
Até a versão 97, o Word era um aplicativo do tipo MDI – sigla, em inglês, de
Multiple Document Interface, ou seja, interface de múltiplos documentos. No
Word 2000 isso mudou. Agora, o programa é monodocumento. Claro que você
continua podendo abrir diversos documentos de uma só vez. Mas cada um deles
ocupa uma cópia – instância, como dizem os programadores – do Word. Portan-
to, quando se executa o comando Janela/Organizar Tudo, os vários clones ati-
vos do Word dividem entre si o espaço disponível na tela do PC. Antes, eles
compartilhavam a tela do Word. Como são várias cópias do programa, a melhor
maneira de passar para outro documento é clicar no ícone dele na barra de tare-
24 fas do Windows.
Fechar e abrir
Como o Word 2000 adotou a interface monodocumento (veja a dica anterior),
você não encontra mais, no menu Arquivo, a opção Fechar. Então, ao fechar o
documento, você fecha com ele a instância do programa que o contém. Há ape-
nas uma exceção para esse comportamento. É quando somente um documento
está aberto. Nesse caso, o Word exibe, à direita da barra de menus, um botão
com um X, que fecha apenas o documento, mantendo o programa ativo. Quan-
do o Word se encontra nessa situação – nenhum documento ativo –, o primeiro
arquivo aberto vai-se alojar na instância ativa do programa. Os seguintes assu-
mirão janelas próprias.

Temas da Web
Na versão 2000, o Word e todos os outros programas do Office tornaram-se
ferramentas da Web. Um dos sinais disso no Word é a possibilidade de gerar do-
cumentos com figuras de fundo e estilos próprios – os chamados temas –, simila-
res às páginas da Web. Para escolher um tema, acione Formatar/Tema. A opção
se aplica mesmo que sua intenção seja gerar um arquivo DOC tradicional, e não
um documento HTML.

Arquivos utilizados
No menu Arquivo, o Word – assim como numerosos outros programas – apre-
senta uma lista dos últimos arquivos editados. Como padrão, aparecem ali ape-
nas os quatro últimos arquivos. Se você quiser que esse número seja outro – por
exemplo, cinco, seis ou oito –, acione Ferramentas/Opções e traga para o pri-
meiro plano a orelha Geral. Na caixa, junto à Lista de Arquivos Utilizados, indi-
que o número desejado. Você pode também não querer que essa lista seja mos-
trada. Nesse caso, desmarque a caixa Lista de Arquivos Utilizados.

Fontes TrueType incorporadas


Você escreve um documento, no qual capricha na formatação e usa uma fonte
TrueType bonita instalada em seu micro. Só que sua intenção é enviar esse do-
cumento para outra pessoa, que possivelmente não tem essa fonte em seu micro.
Se for assim, todo o seu esforço de designer vai por água abaixo. E então? Cal-
ma, dá-se um jeito. Acione Ferramentas/Opções/orelha Salvar e ative o item
Incorporar Fontes TrueType. Com isso, a fonte vai ficar embutida no próprio
documento. O destinatário, portanto, vai poder ver o texto exatamente como
você o está vendo agora.

25
F I G U R A 3 . 1 0 Temas no estilo da Web, outra novidade do Word
2000

Listas numeradas
Ao trabalhar com listas numeradas, sempre que você abre um novo parágrafo, o
Word abre um novo item da lista. Mas há situações em que é preciso abrir um
parágrafo sem criar novo item. Para isso, em lugar de Enter, digite Shift+Enter.
Quando você voltar a usar Enter, a lista continuará.

Ir para onde?
Num documento longo, para fazer o Word saltar rapidamente para uma deter-
minada página, acione Editar/Ir Para, digite o número da página e clique no bo-
tão Ir Para. Se quiser um caminho mais curto, dê um duplo clique na divisão da
barra de status que exibe os números da linha e da coluna em que o cursor está
localizado.

Substituição inteligente
No Word 2000, é possível substituir uma expressão no texto pelo conteúdo da
Área de Transferência do Windows. Veja como. Copie para a Área de Transfe-
rência (Editar/Copiar, ou Ctrl+C) o objeto que substituirá o texto. Esse objeto
pode ser texto ou imagem. Em seguida, acione o comando Editar/Substituir
(Ctrl+U). Na caixa Localizar, digite o texto a ser substituído. Na caixa Substi-
26
tuir Por, digite ^c. Isso equivale ao conteúdo da Área de Transferência.
Exemplo de situação em que esse recurso pode ser útil: sua empresa opera em
São Paulo e no Rio de Janeiro, sendo que alguns serviços ela oferece somente
numa das duas cidades. Você está escrevendo um guia desses serviços e quer
incluir, ao lado da descrição de cada um, um pequeno ícone de São Paulo ou
do Rio. Então, no lugar onde deve ficar o ícone, escreva, por exemplo: img_SP
e/ou img_RJ. Depois, coloque os ícones na memória e comande Editar/Substi-
tuir. Clique no botão Mais e desligue todas as caixas de verificação. Por fim,
clique em Substituir Tudo. Um lembrete: para evitar erros, marque o lugar
para as imagens com códigos que não corram o risco de ser confundidos com
alguma parte do texto.

Linhas rápidas
Existem várias maneiras rápidas de traçar uma linha horizontal. Todas elas estão
definidas como formatos automáticos do Word. Basta digitar uma seqüência de
sinais iguais e teclar Enter. Veja a tabela a seguir:

SEQÜÊNCIA DE... (+Enter) PRODUZ EXEMPLO

Hifens (- - -) Linha fina

Sublinhados (___) Linha grossa

Sinais de igual (===) Linha fina dupla

Til (~~~) Linha ondulada ~~~~~~~~~~~~~~~~~

Cercas (###) Uma linha grossa entre


duas finas

Asteriscos (***) Linha interrompida,


formada por quadrados

Tamanho da fonte
No Word 97 ou 2000, não é necessário ir à caixa Tamanho da Fonte, na barra
de ferramentas, para redimensionar as letras. Selecione o texto desejado e acio-
ne Ctrl+Shift+>, repetidamente, para aumentar a fonte, ponto a ponto; e
Ctrl+Shift+<, para diminuí-la.

27
F I G U R A 3 . 1 1 No Word 2000, nova tela para inserir hyperlinks

Inserir hyperlink
No Word 2000, a inserção ou exclusão de hyperlinks no texto ficou bem mais
fácil. Agora, não é mais preciso ir ao menu Inserir/Hyperlink. Basta selecionar
a expressão desejada, clicar nela com o botão direito e escolher Hyperlink. O
Word abre uma nova caixa de diálogo, onde se pode digitar o texto a ser exibi-
do como hyperlink e o arquivo ou página Web para o qual ele remete. O inte-
ressante é que essa tela também exibe o histórico de navegação de seu browser.
Assim, se o destino é uma página que está no histórico, clique nela para encur-
tar caminho.

Remover hyperlink
A remoção de hyperlinks também ficou mais fácil com o Word 2000. Basta cli-
car com o botão direito no hyperlink e, no menu de contexto, escolher Hyper-
link e, depois, Remover Hyperlink.

Alguns limites do Word


O Word 2000 consegue gerenciar arquivos com tamanho máximo de 32 MB.
No entanto, o número de janelas abertas no programa não tem limite. Ou, di-
zendo de forma menos ambiciosa, seu limite é a memória disponível. Cada di-
cionário personalizado pode medir até 366.590 bytes ou um máximo de
10.000 palavras.

Hora de salvar, salvar


Os botões Salvar (disquetinho) e Imprimir (impressora) na barra de ferramentas
28 do Word vêm da fábrica juntos. Assim, aposto que muitas vezes você imprimiu o
documento quando o que queria, na verdade, era salvar. Para evitar esse trans-
torno, transfira o botão Imprimir para longe do Salvar. É fácil: pressione Alt e,
com o mouse, arraste o botão para a direita, liberando-o no ponto da barra de
ferramentas que achar mais conveniente. Você já sacou: esta também é a dica
para mover qualquer botão – Alt+arrasto do mouse.

Tabela mais ou menos


Quer criar uma tabela sem usar nenhum comando para inserção de tabela? Faça
o seguinte: digite o sinal + seguido de hifens (-), em seguida outro sinal +. Repi-
ta a seqüência e, no final, tecle Enter. Algo assim:

+- - - - - - - +- - - - - - - +- - - - - - - + <Enter>

Descrição de formatos
Para saber rapidamente as formatações de parágrafo e caractere que estão apli-
cadas num documento, acione Shift+F1. O ícone do cursor se transforma numa
seta combinada com um sinal de interrogação. Clique em qualquer ponto de um
parágrafo e o Word apresenta uma caixa de diálogo com a descrição completa
dos formatos de fonte e parágrafo, aplicados ao trecho escolhido. Para desativar
o recurso, acione Esc.

Adeus, sobrescrever
Durante a digitação, você esbarra na tecla Ins e, sem perceber, liga o modo So-
brescrever (o quadrinho SE fica ativado, em preto, na barra de status). Daí em
diante, o que você digita passa a substituir o que já estava escrito. Tempo per-
dido, porque é necessário apertar Ins (ou dar um duplo clique no quadro SE) e
acionar o botão Desfazer até retomar a situação anterior. Para evitar esses pe-
quenos acidentes, desligue definitivamente a possibilidade de acionar Ins de
forma inadvertida. Acione Ferramentas/Personalizar e clique no botão Tecla-
do. Agora, na caixa Categorias, escolha Todos os Comandos e, em Comandos,
selecione Sobrescrever. Por fim, selecione Insert em Teclas Atuais e, em segui-
da, o botão Remover. Feche as duas caixas de diálogo ativas.

Gravação rápida? Fuja dela!


Seguro morreu de velho. Por isso, acione Ferramentas/Opções/orelha Salvar.
Nela, ligue as opções Criar Sempre Backup, Permitir Gravações em Segundo
Plano e Salvar Info de AutoRecuperação a Cada 10 Minutos (o número você de-
fine). No entanto, desligue a caixa Permitir Gravação Rápida. Essa opção tem
mais chances de gerar documentos corrompidos.
29
F I G U R A 3 . 1 2 Descrição de formatos para fontes e parágrafos

Os três últimos passos


Você acabou de editar um trecho lá no meio de um documento longo e voltou
para o início dele. Quer voltar àquele trecho? Acione Shift+F5. Esse comando,
emitido sucessivamente, devolve o cursor aos três últimos locais de edição. Fun-
ciona, inclusive, para arquivos já gravados em disco e recém-abertos. Ao
abri-los, tecle Shift+F5 e retorne ao último ponto editado.

O cão e a raposa
Muitas vezes você está produzindo o layout de um documento e precisa preen-
chê-lo com texto falso. Então, ou você perde tempo criando um texto qualquer
ou abre um documento, copia um trecho dele e cola-o repetidamente no docu-
mento-layout. Existe uma forma muito mais rápida de fazer isso. Escreva:

=rand(2,5)

Depois, tecle Enter. Epa, o texto foi escrito automaticamente! É isso. Esse
comando usa a frase “A ligeira raposa marrom ataca o cão preguiçoso.” Os alga-
rismos entre parênteses indicam, respectivamente, o número de parágrafos e as
vezes em que a frase se repete em cada parágrafo. Essa dica funciona tanto no
Word 2000 como no 97.

30
Entrelinhamento
Quer mudar, num piscar de olhos, o entrelinhamento do texto no Word? Pres-
sione Ctrl+1, para espaço simples; Ctrl+2, para espaço duplo; e Ctrl+1.5,
para a distância de uma linha e meia.

F I G U R A 3 . 1 3 Cadastre figuras como entradas de


AutoCorreção

Assinatura digital
A AutoCorreção é um recurso que vai além do texto: ela também trabalha com
figuras. Se você está escrevendo um documento no qual precisa, repetidamente,
incluir uma mesma imagem como vinheta, faça o seguinte. Insira a figura no tex-
to e selecione-a. Em seguida, comande Ferramentas/AutoCorreção. Uma cópia
da imagem aparece na caixa Por da tela AutoCorreção. Na caixa Substituir, digi-
te a expressão que deve ser trocada pela vinheta. Crie uma seqüência de caracte-
res incomum (por exemplo, “vt_jazz”) para evitar substituições indesejadas.
Agora, digite vt_jazz nos lugares onde desejar colocar aquela vinheta. Com esse
procedimento, você pode também cadastrar, como entrada de AutoCorreção,
sua assinatura digitalizada.

31
Configurações e personalizações
Uma das coisas mais corriqueiras é encontrar usuários do Word reclamando que o
programa não se comporta da maneira esperada. Em geral, essas queixas se vol-
tam contra as numerosas automatizações do programa. Como ponto de partida,
deve-se ter em mente que todo procedimento automático, com certeza, tem uma
forma de ser desligado. É interessante, por exemplo, que o processador de texto
corrija as frases não iniciadas com letra maiúscula. No entanto, há situações em
que o usuário quer, conscientemente, começar as sentenças com letra minúscula.
Nesses momentos, a automação, em vez de ajudar, atrapalha. Para esses ca-
sos, você tem sempre duas alternativas. Se a situação é passageira, uma típica ex-
ceção, acione Ctrl+Z (desfazer), logo após a intervenção do Word, e anule a
correção indesejada. Mas você também pode concluir que aquele item de corre-
ção automática não será bem-vindo em nenhum momento. Portanto, a solução
é desativá-lo de forma permanente.
No Word, em qualquer das versões mais recentes, a desativação de ações
automáticas, assim como a maioria das configurações do comportamento do
programa, encontra-se em alternativas do menu Ferramentas – notadamente na
caixa de diálogo Opções. Vejamos, a seguir, alguns problemas comuns nessa
área e como resolvê-los.
1. Os objetos de desenho não são impressos – Acione Ferramentas/Op-
ções/orelha Imprimir. Certifique-se de que a caixa Objetos de Desenho
esteja ligada.
2. O Word demora muito na hora de imprimir – Em Ferramentas/Op-
ções/orelha Imprimir, confira se está ativada a caixa Impressão em Se-
gundo Plano. Ligada, essa opção garante impressão mais rápida. Com
ela, o Word transfere todo o documento para um arquivo temporário
no disco rígido. Feita a transferência, o processador de texto fica livre
para outros trabalhos. Em segundo plano, o gerenciador de impressão
do Windows entra em ação e vai liberando aquele arquivo conforme a
velocidade da impressora. Isso ocorre, mesmo quando há mais de um
trabalho esperando para ser impresso (a chamada fila de impressão, ou
spool). Se a impressão em segundo plano não estiver ativa, o trabalho é
enviado diretamente para a impressora, sem a intermediação do geren-
ciador. Assim, o Word só fica liberado depois que a última página do
documento é processada pela impressora.
Atenção: esse problema pode, também, ter uma raiz localizada fora do
Word. A impressora, no Windows, pode estar configurada para comu-
nicação direta com o micro, sem a intervenção do gerenciador (spoo-
ling). Para ajustar isso, vá ao Painel de Controle, acione Impressoras e
ponha em primeiro plano a orelha Detalhes. Agora, clique no botão
Configuração do Spool e ative a opção Colocar os Trabalhos em Spool
para que a impressão termine mais rapidamente.
32
3. O Word imprime uma página a mais com o resumo do documento – Mui-
tos usuários se queixam de que o programa os força a desperdiçar uma
folha de papel ao imprimir cada documento. Para eliminar isso, acione
Ferramentas/Opções/ orelha Imprimir e desligue o item Propriedades
do Documento.
4. Verificação ortográfica – Como você sabe, o Word sublinha em verme-
lho as palavras digitadas com erro ou as desconhecidas em seus dicioná-
rios. Para desativar a verificação ortográfica, acione Ferramentas/Op-
ções/orelha Ortografia e Gramática e desligue a caixa Verificar Ortogra-
fia ao Digitar. Também é possível fazer isso somente para o documento
atual: Ferramentas/Opções/Ortografia e Gramática, caixa Ocultar Erros
de Ortografia Neste Documento.
5. Alinhamento do texto e das linhas de tabela – Ao passar do Word 6.0/95
para o Word 97 ou 2000, você pode enfrentar problemas com o alinha-
mento do texto dentro das células em tabelas. Tipicamente, a tabela se
mostra normal na tela, mas desencontrada ao ser impressa. Para corrigir
isso, acione Ferramentas/Opções, orelha Compatibilidade. Em Opções
Recomendadas Para, escolha a versão do Word com a qual as tabelas
funcionavam corretamente. Em seguida, ligue a opção Ajustar a Altura
da Linha à Altura da Grade na Tabela. Há ainda numerosas outras op-
ções. Experimente com elas e veja os resultados.
Outra fonte de configurações e procedimentos automáticos é o item AutoCor-
reção do menu Ferramentas. Se você não deseja que endereços da Web ou de correio
eletrônico sejam automaticamente associados a hyperlinks, desligue, na orelha Auto-
Formatação, os itens Substituir/Internet e Caminhos de Rede por Hyperlinks.
Vários outros ajustes podem ser feitos em Opções ou em AutoCorreção.
Esses dois itens são principais “suspeitos” de automações indesejadas. Procure lá
e, na maioria dos casos, a resposta estará com eles. Veja também outras soluções
que podem ajudá-lo a aproveitar melhor o Word no próximo capítulo deste li-
vro, que reúne dezenas de dicas sobre como obter melhores resultados no uso
do processador de texto.

33
4
Fique rico na
bolsa de tempo

Invista um minuto e ganhe milhões


(de minutos) em produtividade
A idéia deste livro, conforme foi mostrado no texto de
apresentação, não é ensinar o leitor a usar o Word. Presu-
me-se que quem se aproximou deste volume já tenha ra-
zoável prática com o programa. A intenção, aqui, é desta-
car aspectos do Word que normalmente passam desper-
cebidos para o usuário – e, em alguns casos, até mesmo
para os mais curiosos.
Tenho certeza de que esses aspectos meio esqueci-
dos, quando passam a fazer parte do dia-a-dia do usuário,
podem contribuir diretamente para elevar sua produtivi-
dade – seja para atingir objetivos profissionais, seja ape-
nas para satisfação pessoal. Em qualquer caso, o ponto
central é extrair muito mais da ferramenta que está aí,
instalada em sua máquina.
Neste capítulo, vamos analisar alguns itens básicos
para o uso mais profundo e mais produtivo do Word.
Avançando dos temas mais simples para os mais comple-
xos, vamos passar por itens como modelos, menus e bar-
ras de ferramentas, formulários e macros. Vamos visitar –
ou revisitar, para quem já conhece – os conceitos básicos
de alguns recursos do Word que serão fundamentais para
a compreensão do que virá nos próximos capítulos.
Portanto, o que você vai encontrar aqui não são ain-
da os exercícios práticos de desenvolvimento, mas o está-
gio preparatório para chegar a eles. Estamos apenas aquecendo os motores para
então entrar no Visual Basic for Applications, VBA. Mesmo para quem não pre-
tende entrar no território da programação, existem vantagens em prestar aten-
ção nesses aspectos do Word.
Usar recursos como estilos e modelos representa um investimento. Gas-
ta-se um quarto de hora aqui e ganha-se esse espaço de tempo multiplicado por
milhões, no dia-a-dia. É uma bolsa de valores sempre em alta, e a moeda em jogo
é o tempo. Como já disseram que tempo é dinheiro, aplique nesses recursos e
torne-se um milionário...

Estilos
Já tive a oportunidade de receber textos de usuários do Word de longa data, nos
quais os parágrafos eram definidos à mão. Ou seja, para estabelecer o recuo in-
dicativo do parágrafo, o autor acionava a tecla de espaço um certo número de
vezes. Pensando tecnicamente, isso representa um absurdo. Afinal, a função bá-
sica de um programa como o Word é facilitar o trabalho, o que inclui a automa-
ção de tarefas desse tipo. Só que, por falta de curiosidade ou de aviso, muita gen-
te não aproveita o potencial da incrível ferramenta que tem nas mãos.
Um recurso do Word que resolveria o problema dos parágrafos definidos
com a barra de espaço são os estilos. O que é isso? Estilo é um conjunto de for-
matos reunidos num padrão. Esses formatos podem abranger: fontes, parágra-
fos, tabulações, bordas, idiomas, molduras e numeração.
Digamos que você sempre escreve relatórios nos quais é preciso – ou você
quer – manter um padrão. Por exemplo, letra Courier New, corpo 12; parágra-
fo com linhas justificadas, espaço entre linhas equivalente a 1,5 linha e recuo de
2 cm na primeira linha. Pelo caminho mais longo, toda vez que iniciar um novo

F I G U R A 4 . 1 Caixa de diálogo para criar e modificar estilos 35


relatório, você será obrigado a navegar pelos menus e fazer todos esses ajustes.
Ao contrário, se você definir um estilo, fará essa operação apenas uma vez. Nas
outras, simplesmente escolherá o estilo, que vai trazer, automaticamente, todos
os formatos desejados.
Para criar um estilo, acione o comando Formatar/Estilo e clique no botão
Novo. Na tela Novo Estilo, dê um nome ao estilo a ser criado e clique na caixa
Adicionar ao Modelo. Isso garante que o estilo será armazenado e poderá ser
usado em outros documentos. Caso contrário, ele será válido apenas para o do-
cumento atual. Agora, clique no botão Formatar e escolha o que pretende defi-
nir: fonte, parágrafo etc. Repita esta última operação para especificar outras ca-
racterísticas, como idioma.
Ao concluir as definições e acionar OK, o novo estilo passará a fazer parte
da lista existente na caixa de ferramentas Formatação. Para acioná-lo, basta es-
colhê-lo no início da escrita de um documento. Ou, então, selecionar um texto
inteiro, ou parte dele, e aplicar o estilo.
Em certos casos, é possível criar estilos encadeados. Observe, na tela Novo
Estilo (ou Modificar Estilo – que é a mesma, em outra situação), a presença da
caixa Estilo para o Parágrafo Seguinte. Normalmente, ela é preenchida com o
próprio estilo que está sendo criado ou modificado. Se você indicar ali outro es-
tilo, o que acontece? Sempre que abrir um novo parágrafo, o Word o ajustará
para o estilo indicado.
Você deve estar pensando: muito bem, e onde isso pode ser útil? Um exem-
plo são as teses e outros escritos acadêmicos. Em geral, o autor da tese costuma
apresentar o próprio texto em parágrafo e caracteres normais e as citações que
faz de outros autores num parágrafo com grande recuo à esquerda, letras em itá-
lico e menor espaçamento entre linhas. Veja, na Figura 4.2, um exemplo esque-
mático desses dois estilos.

F I G U R A 4 . 2 Exemplo dos estilos usados em teses: texto e


citação
36
Numa tese, o usuário poderia criar um estilo e batizá-lo, por exemplo,
como Texto Principal. Para as citações, criaria outro, chamado Citação. Este
poderia ter Texto Principal na caixa Estilo para o Parágrafo Seguinte. Assim,
concluída uma citação, quando o usuário acionasse Enter, o próximo parágrafo
cairia automaticamente em Texto Principal. Embora simples, esses exemplos
mostram bem as vantagens de quem aproveita melhor os recursos do Word.
O conceito de estilo pode ser aplicado, por exemplo, para mudar o padrão
do parágrafo com que o Word trabalha. Em geral, esse padrão corresponde a
um parágrafo alinhado à esquerda, com espaçamento de uma linha e caracteres
Times New Roman, no tamanho 10 pontos. Para mudá-lo, basta acionar For-
matar/Estilo, escolher o estilo Normal e clicar no botão Modificar. Você pode
querer transformar em padrão outra fonte e outro esquema de parágrafo.
As definições de estilo feitas no Word são gravadas no modelo Normal,
contido no arquivo Normal.dot. No Word 97, esse arquivo fica num subdiretó-
rio do Office. No 2000, ele foi transferido para \Application Data\Microsoft\
Modelos, um subdiretório do Windows. Isso significa que, se você apagar o ar-
quivo Normal.dot, perderá os estilos personalizados que criou e passará a ter
apenas os estilos que vêm no Word, em situação idêntica à do momento da ins-
talação.

Modelos
Ao lado do estilo, o modelo é outro conceito fundamental para a compreensão
de como funciona o Word. Mais amplo que o estilo, o modelo representa uma
espécie de matriz para a criação de documentos. Veja um exemplo. No dia-a-dia
de um escritório, é muito comum a emissão de documentos idênticos, em for-
mato e em conteúdo.
Para escrever um memorando, pode-se abrir um documento anterior, já
enviado, modificar o que for necessário (data, nome do destinatário etc.), e
salvá-lo com outro nome. Para evitar isso – que, além de dar trabalho, seria
uma fonte de erros –, criou-se o modelo. No exemplo do memorando, o mo-
delo pode conter todos os dados básicos já preenchidos e todas as formatações.
Ele é salvo como um arquivo DOT (o T vem de template – modelo, gabarito,
em inglês).
Quando se cria um documento novo a partir de um modelo, tem-se uma
cópia fiel do original, sem afetar a matriz que permanece inalterada para servir
de base a outros documentos idênticos. Num escritório comercial ou de advoca-
cia, por exemplo, preenchem-se todos os dias vários contratos de conteúdo
idêntico. Num contrato de aluguel, por exemplo, mudam apenas os nomes do
locador e do locatário, além do endereço do imóvel. Eis aí uma aplicação típica
para um modelo. Contido num modelo, o contrato já está pronto: falta apenas
preencher os dados variáveis. Mais adiante, neste volume, vamos mostrar como
automatizar o preenchimento de documentos desse tipo.
37
Como você já deve ter percebido, o modelo vai mais longe que o estilo,
porque abraça o documento como um todo, e não apenas definições de forma-
to. Portanto, o modelo pode estabelecer o tamanho e a orientação da página (re-
trato, paisagem), cabeçalho, rodapé, ilustrações e todo o conteúdo básico do do-
cumento.
Embora os modelos sejam tão abrangentes, criar um modelo é uma das ope-
rações mais desconcertantemente fáceis que existem no Word. Pegue um docu-
mento qualquer e acione Arquivo/Salvar Como. Dê um nome para o documento
e, na caixa Salvar Como Tipo, escolha Modelo do Documento (*.dot). Clique em
OK, e pronto: você acabou de criar um modelo. Isso leva a uma definição sumá-
ria: modelo, no Word, é qualquer documento que se salve como modelo. Não
existe exagero nesta frase: ela vale até mesmo para um documento vazio.
O Word admite dois tipos de modelos: o global e o temporário. Global é
aquele cujas características estão disponíveis durante todo o tempo. O temporá-
rio, ao contrário, só oferece seus recursos quando um documento baseado nele
está aberto no Word. O Normal.dot é um exemplo de modelo global. Tudo que
ele contém – estilos, macros etc. – pode ser utilizado a qualquer momento. No
entanto, os recursos de modelos como o Memorando Elegante – um dos gabari-
tos que acompanham o Word – só podem ser usados se um documento-clone es-
tiver aberto no momento.
Você pode transformar qualquer modelo em recurso global. Basta copiá-lo
para a pasta Iniciar, dentro do diretório do Office. No Word 2000, o diretório
correto é C:\Windows\Application Data\Microsoft\Word\Inicialização. A loca-
lização exata muda com a versão do programa e com o tipo de instalação do
Office ou do Word que você possa ter feito. Em todo caso, a indicação encon-
tra-se em Ferramentas/Opções/orelha Arquivos, item Inicialização.
Existe uma diferença sutil entre abrir um modelo e abrir um novo arquivo
baseado nesse modelo. Para abrir um modelo, acione Arquivo/Abrir e aponte
para o arquivo do modelo, um DOT. Você faz isso quando pretende modificar o
modelo.
Para abrir um novo arquivo com base num modelo, acione Arquivo/Novo
e indique, na caixa de diálogo, o modelo que deseja usar. Outra forma é, no
Windows Explorer, dar um duplo clique no arquivo DOT. O Word cria, auto-
maticamente, um novo clone daquele modelo.
Documentos e modelos do Word 97 e do 2000 têm ainda um ponto co-
mum muito importante no contexto deste livro: ambos podem conter macros.
Ou seja, programas em Visual Basic for Applications (VBA), em geral destinados
a automatizar tarefas repetitivas.

Menus e barras de ferramentas


Os menus e barras de ferramentas representam um dos recursos do Word que
mais oferecem campo para a criatividade do usuário. É possível criar novos me-
38 nus e barras de ferramentas, modificar os existentes, ocultar botões, redefinir
comandos – enfim, fazer uma festa completa. Aqui, nossa intenção é destacar al-
gumas operações fundamentais para quem pretende desenvolver ou simples-
mente usar macros. Vamos ver como criar, incluir ou excluir botões na barra de
ferramentas, como criar ou eliminar opções de menu, e como associar macros a
botões ou comandos de menu.
As operações com menus e barras de ferramentas passam todas pelo co-
mando Personalizar. Há várias maneiras de acioná-lo. Uma delas é clicar com o
botão direito do mouse em qualquer menu ou barra de ferramenta e, no menu
pop-up, escolher Personalizar. Com isso, abre-se a caixa de diálogo Personali-
zar. Outro caminho é acionar o menu Ferramentas, opção Personalizar. Apren-
da este procedimento: ele se repetirá diversas vezes nos próximos passos.

F I G U R A 4 . 3 Tela Personalizar: edição de menus e barras de


ferramentas

Criar uma barra de ferramentas


Para criar uma nova barra de ferramentas, o primeiro passo é abrir a caixa de
diálogo Personalizar. Agora, traga para o primeiro plano a orelha Barras de Fer-
ramentas e clique no botão Nova. Digite o nome da barra de ferramentas – diga-
mos, Teste – e acione OK. Uma pequena barra flutuante aparece na tela. Vamos,
a seguir, agregar botões a essa barra de ferramentas.

Incluir um botão numa barra de ferramentas


Para instalar um novo botão numa barra de ferramentas, exiba outra vez a tela
Personalizar. Desta vez, selecione a orelha Comandos. Neste exemplo, vamos
integrar à barra de ferramentas Teste um comando interno do Word que não é
representado por um botão nas barras de ferramentas clássicas do programa.
Trata-se do comando Configurar Página, pertencente ao menu Arquivo.
39
F I G U R A 4 . 4 Para instalar o botão, arraste a macro para a barra

Em Personalizar/Comandos, selecione Arquivo na caixa Categorias. Na ja-


nela à direita, localize o item Configurar Página e arraste-o para a barra Teste.
Feche a janela e experimente o novo botão. O procedimento seria idêntico se,
em vez de instalar esse comando na barra Teste, você o arrastasse para uma bar-
ra de ferramentas do Word.
Nesse caso, a operação resultou muito simples porque escolhemos um co-
mando do Word para o qual já existia internamente um ícone associado. Vamos
agora a um exercício um pouco mais complexo. Volte à tela Personalizar/Co-
mandos. Escolha AutoTexto em Categorias e arraste o item Atenciosamente
para a barra Teste. Agora, o que apareceu lá não foi um ícone, mas a expressão
“Atenciosamente,”. Podemos deixá-la como está (seria um botão apenas com
texto) ou modificá-la.

40 F I G U R A 4 . 5 Menu pop-up para alterar botão de comando


Volte à tela Personalizar/Comandos e clique no botão Atenciosamente, em
Teste. Agora, clique em Modificar Seleção. No menu que surge, você tem nume-
rosas opções. Veja algumas:
a) Você pode mudar a legenda que aparece no botão. Basta editar a caixa
Nome.
b) Outra alternativa é escolher Imagem e Texto. Isso permite criar um botão que
reúne um ícone e uma legenda.
c) A alternativa Estilo Padrão dá lugar apenas para um ícone.
d) Alterar Imagem do Botão exibe uma coleção de ícones. Escolha um para o botão.
e) Editar imagem do botão abre um editor de ícones, no qual você pode dese-
nhar um botão, pixel a pixel.
f) Copiar Imagem do Botão permite que você clique em outro botão e copie o
ícone dele.
g) Colar Imagem do Botão completa a operação do comando anterior quando
aplicada ao botão de destino.

F I G U R A 4 . 6 Opções de imagens para a face dos botões

Como criar um novo menu e suas opções


Ative Personalizar/Comandos e escolha o último item de Categorias, Novo
Menu. Agora, arraste o item Novo Menu, da caixa Comandos para a barra de
ferramentas Teste. Em seguida, selecione a categoria Todos os Comandos e ar-
raste alguns itens para Novo Menu, na barra de ferramentas.
41
Excluir um botão ou item de menu
A eliminação de qualquer item de menu ou da barra de ferramentas também
passa pela tela Personalizar. Basta abrir essa caixa de diálogo e arrastar o item
até ela. Outra forma de eliminar um botão ou o menu inteiro (não vale para item
de menu) é pressionar a tecla Alt e, ao mesmo tempo, arrastar com o mouse o
botão ou menu para fora da barra onde se encontra. Dessa forma, é possível ex-
cluir, até mesmo, os menus e botões do próprio Word.

Excluir uma barra de ferramentas


Na tela personalizar, orelha Barra de Ferramentas, marque o objeto que deseja
apagar e acione o botão Excluir.

Formulários
Os formulários constituem uma forma de trabalhar com documentos protegi-
dos contra modificações. Normalmente, eles são um modelo de documento
provido de campos para digitação. Como o texto é protegido, o usuário só pode
escrever nesses campos. A criação de um formulário começa com a barra de fer-
ramentas Formulários (Exibir/Barras de Ferramentas).
Essa barra oferece vários botões, com campos, como caixa de texto (ou
campo de formulário texto, como o Word denomina), caixa de seleção e caixa
de combinação. Assim, além de digitar, o usuário pode marcar com um tique ou
escolher opções numa lista.

F I G U R A 4 . 7 Barra de ferramentas Formulários

Para o formulário, escreve-se o documento normalmente e, depois, inse-


rem-se os campos nos locais onde devem entrar as variáveis. Veja, na Figura 4.8,
um exemplo bem simples. Mas o formulário só funciona como tal depois de
protegido. Para isso, acione Ferramentas/Proteger Documento e escolha For-
mulários. A senha é opcional. Salve o arquivo como um modelo, feche-o e abra,
em seguida, um documento baseado nesse modelo.
Observe o documento: as partes cinzentas são os campos. Para adicionar
opções na caixa de combinação, durante o desenho do formulário, clique nela
com o botão direito e acione Propriedades. Uma caixa de diálogo se abre, com
espaço para você digitar as opções desejadas. Tente alterar o texto fora dos cam-
pos – não é possível. Para fazer novas edições no formulário, é necessário voltar
42 ao menu Ferramentas e acionar Desproteger Documento.
F I G U R A 4 . 8 Exemplo de um formulário para digitação

Os formulários podem ser usados para o preenchimento e automatização de


documentos mais complexos, como pedidos comerciais. O usuário digita os pro-
dutos, quantidades e preços e o documento calcula os totais. Embora os formulá-
rios de digitação direta sejam um recurso engenhoso, sua tendência é perder espa-
ço para aplicações escritas em Visual Basic for Applications (VBA), adotado pelo
Word a partir da versão 97. As possibilidades oferecidas por essa linguagem são
infinitamente superiores. Eis porque não vamos nos estender aqui sobre a elabo-
ração de formulários. Na segunda parte deste volume, você vai encontrar vários
projetos que automatizam o preenchimento de documentos a partir do VBA.

Macros
Desde os primeiros tempos da microcomputação, alguns aplicativos mais sofis-
ticados oferecem ao usuário meios para que ele possa automatizar seqüências de
tarefas repetitivas, ou expandir as funções existentes nesses aplicativos. Nor-
malmente, as macros são o recurso usado para isso. No Word para Windows, a
primeira linguagem de macro foi o WordBasic, presente no aplicativo até a ver-
são 7.0 (ou 95). A partir da versão seguinte, a 8.0 (ou 97), o WordBasic foi subs-
tituído pelo Visual Basic for Applications (VBA), linguagem de macros que re-
presenta um subconjunto da linguagem Visual Basic.
Como em qualquer outro aplicativo, o VBA no Word tem dois grandes
blocos de comandos. Um vem diretamente da linguagem Visual Basic. Trata-se
dos itens genéricos da linguagem, como sua sintaxe e comandos básicos. O ou-
tro bloco reúne os objetos específicos do Word – ou de outro aplicativo que te-
nha incorporado o VBA.
Para entender melhor a diferença entre o núcleo genérico e o núcleo espe-
cífico do VBA, vejamos um exemplo. Tanto o Word como o Excel trazem em-
butido o VBA como ferramenta de programação. Em qualquer um dos dois apli-
cativos – assim como no Access, no PowerPoint e em mais de uma centena de
outros programas do mercado –, o código abaixo vai funcionar do mesmo
modo, exibindo ao usuário a mensagem mostrada na Figura 4.9.

Sub Mensagem()
MsgBox “Bem-vindo ao VBA.”, vbOKOnly, “Mensagem”
End Sub 43
F I G U R A 4 . 9 Mensagem ao usuário

Isso acontece porque o comando MsgBox faz parte do núcleo básico do Vi-
sual Basic. No entanto, você não vai obter sucesso se tentar rodar no Excel uma
macro escrita no Word, fazendo referências a parágrafos, notas de rodapé ou pá-
ginas com duas colunas. Claro, esses são objetos específicos do processador de
texto, não existem no Excel. Do mesmo modo, é inútil tentar rodar no Word um
código que envolva objetos típicos do Excel, como planilha ativa ou célula A23.
Portanto, em cada aplicativo o VBA junta a linguagem comum, Visual Basic,
a comandos, funções e propriedades específicos do aplicativo. Isso significa que
mesmo o programador experiente em Visual Basic precisa familiarizar-se com
os objetos privativos de qualquer programa que tenha adotado o VBA.

VBA rápido e prático


Se alguém lhe dá uma macro para Word (97 ou 2000), como você faz para inte-
grá-la ao seu programa? Vejamos. Você pode receber apenas o texto do progra-
ma. Exemplo: um amigo lhe fornece o texto abaixo e diz que ele abre a Calcula-
dora do Windows, a partir do Word. O que você faz?

Public Sub Calcular()


On Error GoTo Calc_Err

Dim lngX As Long


Dim Caminho As String, Programa As String
Caminho = “c:\windows\calc.exe”
Programa = “Calculadora”

If Tasks.Exists(Programa) = True Then


Tasks(Programa).Activate
Else
lngX = Shell(Caminho, vbNormalFocus)
End If
Tasks(Programa).WindowState = wdWindowStateNormal

Calc_Fim:
44
Exit Sub
Calc_Err:
MsgBox Err.Description
Resume Calc_Fim
End Sub

Em primeiro lugar, no Word, acione Alt+F11. Abre-se a janela do Visual


Basic. Vá ao menu Inserir e escolha Módulo. Na janela à esquerda, surgirá um
item chamado Módulo1 (se já houver um Módulo1, será Módulo2 etc.). Copie
para a memória o texto do programa e cole-o na janela maior. Salve e volte para
o Word (Alt+F11), de novo. A macro está lá, mas como você vai fazer para exe-
cutá-la? Você poderia ir ao menu Ferramentas/Macro/Macros. A opção Calcu-
ladora está lá. Selecione-a e clique no botão Executar. Perfeito, não?
Mas facilitemos as coisas: que tal se você puder chamá-la a partir de um bo-
tão na barra de ferramentas? Vamos lá. Clique em Ferramentas/Personalizar.
Ponha em primeiro plano a orelha Comandos e localize Macros, na caixa Cate-
gorias. A macro Normal.Módulo1.Calculadora aparece na lista da direita.

F I G U R A 4 . 1 0 Tela Personalizar: para instalar uma macro


num botão

Arraste a linha da macro para uma barra de ferramentas onde haja espaço
para mais um botão. No início, o botão vai ficar enorme. Na caixa Personalizar,
clique em Modificar Seleção e escolha Estilo Padrão. Agora, clique de novo em
Modificar Seleção e selecione Alterar Imagem de Botão. Escolha um ícone (exis-
te um que é uma calculadora), e pronto. Agora, você pode acionar a Calculadora
sem sair do Word.
(O texto desta macro, para você não precisar digitá-lo, está no arquivo Cal-
culadora.txt, no diretório Capítulo 6, do CD-ROM.)
45
5
Muito prazer,
VBA

Uma breve apresentação do Visual Basic for


Applications
Se você nunca se aproximou do Visual Basic, em nenhu-
ma de suas formas, neste capítulo terá oportunidade de
travar um contato inicial com essa linguagem. O Visual
Basic, somadas todas as suas modalidades, é hoje a ferra-
menta de desenvolvimento mais usada no mundo inteiro.
Para essa popularidade do VB, concorre, em primeiro lu-
gar, o fato de ser uma linguagem de estrutura ágil e acessí-
vel ao aprendizado. É muito mais fácil – e rápido – apren-
der VB que qualquer outra linguagem de programação.
Outro fator que impulsiona o Visual Basic para a po-
sição que ocupa hoje no mercado é, inegavelmente, a po-
derosa influência da Microsoft. Segundo a empresa, o Vi-
sual Basic conta hoje com mais de 3 milhões de programa-
dores, que utilizam:
n o Visual Basic completo – o pacote da linguagem, ven-

dido como produto independente; ou


n a linguagem de macro Visual Basic for Applications

(VBA), presente em numerosos aplicativos, como


Word, Access e Excel, da própria Microsoft, além de
títulos de outras 150 empresas; ou
n a linguagem de scripts VBScript, embutida no Win-

dows – 98, NT 4.0 e 2000 – que serve para implemen-


tar tarefas de automação nesses sistemas operacionais
ou em páginas da Web.
Assim, o Visual Basic é uma espécie de esperanto, dentro da plataforma
Windows. Ele está em toda parte: em aplicativos de escritório (CorelDraw, Co-
rel WordPerfect, nas versões mais recentes), traçadores de fluxogramas (Visio),
programas de engenharia (AutoCAD) e até em softwares de gestão, como o R/3,
da SAP. Para mais informações sobre o VBA, consulte o site da linguagem:
http://msdn.microsoft.com/vba.

Um pouco de história
Criado, em 1964, pelos americanos John Kemeney e Thomas Kurtz, o Basic é
uma ferramenta concebida desde o início com o objetivo de facilitar o aprendi-
zado. Aliás, isso está expresso no próprio nome da linguagem, que significa “bá-
sico”, mas na verdade é um acrônimo de Beginner’s All-purpose Symbolic
Instruction Code – algo como código simbólico de instrução para principiantes.
A caracterização como linguagem para principiantes representou, ao mes-
mo tempo, um bem e um mal para o Basic. O lado positivo está na facilidade de
aprendizado, que se mantém até hoje, mais de 35 anos depois da primeira for-
mulação da linguagem. Mas a combinação das expressões “fácil”e “para princi-
piantes” conduziu também à idéia de uma linguagem de pouca profundidade,
voltada apenas para exercícios breves, sem maior conseqüência.
Isso mudou com a ascensão do Visual Basic, cuja primeira versão apareceu
no mercado em 1992. A Microsoft, que fora responsável, nos anos 70, por tra-
zer o Basic dos computadores de grande porte para os micros, lançava, nos
anos 90, o primeiro Basic para o ambiente gráfico Windows, que então começa-
va a decolar.
Esse Basic para Windows trazia algumas novidades de peso. A primeira,
claro, era o aspecto visual. Podia-se desenvolver aplicações, com os mesmos
procedimentos usados para desenhar com o Paintbrush (antecessor do Win-
dows Paint): escolher um controle numa caixa de ferramentas e usá-lo para tra-
çar objetos nas tela.
Outro aspecto pioneiro do Visual Basic era o nível de expansibilidade.
Além de trazer controles embutidos (caixa de texto, caixa de combinação, bar-
ras de rolamento etc.), o programa aceitava a agregação de controles externos,
adquiridos no mercado. Assim, mesmo os programadores que não tinham con-
dições técnicas de elaborar objetos mais sofisticados podiam usá-los, sem grande
dificuldade. Em muitos casos, tudo que era preciso saber sobre esses objetos era
escolher características numa caixa de propriedades.
Esses controles externos foram, primeiro, os VBX (Visual Basic Extensi-
ons, de 16 bits), e, depois, os OCX, de 32 bits. A idéia revelou-se tão poderosa
que os controles OCX tornaram-se um padrão, adotados por várias outras lin-
guagens, como C/C++, Delphi etc. Do ponto de vista econômico, os VBX e
OCX propiciaram o surgimento de um ramo especializado da indústria de soft-
ware: os fabricantes de componentes, essas peças e partes inteligentes que po-
47
dem ser incluídas num projeto para acelerar e facilitar seu desenvolvimento. De-
pois da Internet, os OCX evoluíram, passando a se chamar objetos ActiveX e
podendo ser incluídos em projetos isolados, em rede local ou ligados à Web.
Outra faceta da expansibilidade do Visual Basic está no acesso quase irres-
trito que a linguagem pode ter à API (funções internas) do Windows. Com isso,
os programadores mais avançados podem estender o poder de fogo da lingua-
gem, referindo-se diretamente a objetos e procedimentos existentes na própria
estrutura do sistema operacional.
Hoje, o Visual Basic encontra-se na versão 6.0. Ao longo do tempo, o pro-
duto foi incorporando novidades, entre as quais se destacam a capacidade de ge-
renciar bancos de dados. Nesse caso, o programa cedeu sua linguagem ao Access
e tomou emprestado deste o sistema de gerenciamento de dados. Isso ocorreu
na versão 3.0 do Visual Basic. Outra aquisição importante foram os recursos de
programação orientada a objeto, presentes no VB desde a versão 4.0.

VB, VBA e VBScript


Quais as diferenças entre Visual Basic, Visual Basic for Applications e VBScript?
VBA e VBScript são subconjuntos do Visual Basic. O VB é a linguagem plena,
com todos os recursos para o desenvolvimento de aplicações comerciais e gráfi-
cas. O VBA, por sua vez, inclui grande parcela dos recursos do VB, mas tem uma
limitação fundamental: ele não gera aplicativos autônomos. Pode, na verdade,
produzir soluções complexas, mas elas funcionam somente dentro do programa
hospedeiro: por exemplo, Word, Excel. O VBScript representa um subconjunto
de recursos ainda menor. Trata-se de uma linguagem para a automação de pro-
cedimentos na plataforma Windows e em páginas Web.
Ainda com relação às diferenças, é importante notar que toda aplicação
VBA funciona nos moldes de uma caixa de diálogo do programa hospedeiro.
Isso equivale a dizer que, em geral, só é possível retomar o trabalho normal com
o programa-pai depois de encerrada a aplicação. Neste parágrafo, já usei duas
vezes a palavra aplicação VBA. Antes, todo código escrito com uma linguagem
embutida se chamava macro. Mas, com o nível de complexidade atingido pelo
VBA, é possível criar verdadeiras aplicações. Elas abrem bancos de dados, escre-
vem arquivos, manipulam recursos do Windows e têm condições de acessar a
Internet. Portanto, embora o termo macro esteja correto, os programas VBA são
muito mais que isso.

Com você, o VBA


Muito bem, você está aí com seu Word 97 ou 2000. Tenha o prazer de conhecer
o VBA. Para isso, acione Ferramentas/Macro/Editor do Visual Basic. Ou, mais
curto, Alt+F11. Abre-se o ambiente de programação do Visual Basic. Para vol-
tar ao Word, acione de novo Alt+F11.
48
F I G U R A 5 . 1 Janela do VBA: quatro subdivisões principais

O ambiente de desenvolvimento do VBA compõe-se de algumas divisões


fundamentais, com as quais você se depara logo no primeiro contato. Além do
menu e da barra de ferramentas, a janela divide-se em cinco partes (todas ocultá-
veis via menu Exibir):
n Janela Explorer de Projeto, ou Janela de Projeto – Exibe os todos os ele-
mentos que fazem parte de um ou mais projetos: formulários, módulos
e módulos de classe.
n Janela Propriedades – Lista as definições de propriedades de um objeto
selecionado num formulário.
n Janela de Verificação Imediata ou, simplesmente, Janela Imediata —
Espaço auxiliar de programação. A partir desta janela, pode-se verificar
o valor de uma variável, executar programas no ambiente VBA ou fora
dele, consultar o valor de constantes intrínsecas. Enfim, uma janela de
extrema utilidade. Com o tempo, você aprenderá a tirar bom proveito
dela.
n Janela de Código ou de Formulário – Trata-se da maior subdivisão do
conjunto. Nela estão reunidos todos os módulos de formulário e módu-
los de código disponíveis.
n Janela Pesquisador de Objeto – Lista toda a hierarquia de objetos do
Word e do VBA, com suas funções e sintaxe de acesso. O Pesquisador de
Objeto é uma das fontes mais importantes para o entendimento das rela-
ções entre recursos do Word. À medida que você for se aprofundando
mais no uso do VBA, mais vai perceber a importância dessa janela. Para
acessá-la, acione Exibir/Pesquisador de Objeto ou simplesmente F2.
49
Naturalmente, como se trata de um ambiente de programação, o VBA tem
ainda uma série de outras janelas, como a Caixa de Ferramentas, que reúne os
controles (caixa de texto, etiquetas, caixas de listagem etc.) com o quais se dese-
nham os formulários. Mas, por enquanto, fiquemos por aqui. Nossa intenção,
neste volume, não é fazer uma descrição completa de cada canto escondido do
VBA. Ao contrário, a abordagem é prática: vamos falar deste ou daquele item à
medida que ele se tornar necessário para o desenvolvimento de uma solução
concreta. Essencialmente, mostraremos aqui os componentes básicos de um
projeto VBA e como criá-los.

Observação importante – Neste livro, sempre que escrevermos Vi-


sual Basic, VB, VBA, estaremos nos referindo a esse ambiente ou à lingua-
gem que lhe dá suporte. Quando o objeto da citação for o Visual Basic –
a linguagem como produto separado –, isso ficará claro no texto.

Partes de um projeto VBA


Todas as partes que compõem um projeto VBA estão contidas em módulos. Há
três tipos de módulos: formulários, módulos de código (ou apenas módulos) e
módulos de classe.
Os formulários (ou, em inglês, forms) são as telas dos aplicativos. Eles abrigam
caixas de texto, caixas de combinação, barras de rolamento e outros objetos que
compõem a interface do Windows. Ao longo deste livro, usaremos, indiferente-
mente, os termos formulário e form. Em alguns casos, você verá, de forma redun-
dante, formulário (form) ou formulário (UserForm) . Aí, a intenção é diferenciar o
formulário de programação, do VBA, do formulário-documento do Word.
Cada formulário possui uma parte visível, que são as telas, e outra invisível,
que abriga código de programação. Naturalmente, os termos visível e invisível
são aqui empregados do ponto de vista do usuário: para você, programador,
tudo é visível.
Os módulos propriamente ditos abrigam apenas código de programação. Os
módulos de classe são idênticos nesse aspecto. A única diferença está em que os
módulos de classe são utilizados somente em programação orientada a objeto.
Como se cria um formulário? É simples. Basta selecionar o projeto deseja-
do e acionar o comando Inserir/UserForm. Por que selecionar um projeto? Por-
que você pode criar formulários no projeto Normal (que fica gravado no mode-
lo Normal.dot e disponível para todos os projetos) ou em qualquer outro docu-
mento ou modelo personalizado. Inserido o formulário, ele, geralmente, assu-
me o nome UserForm1, UserForm2 etc. Para dar a ele um nome personalizado,
clique no form e vá à janela Propriedades. Lá, escreva o novo nome na linha
Name. Em geral, para facilitar o reconhecimento, os formulários recebem, no
50 nome, o prefixo frm: frmCores, frmAtributos.
F I G U R A 5 . 2 Módulo de programação, com destaque para a
janela Declaração

A inserção de módulos e de módulos de classe é semelhante à de for-


mulários. Basta recorrer ao menu Inserir. Formulários, módulos e módulos
de classe têm, em cada projeto, seu armazenamento próprio. Na janela Pro-
jeto, eles ficam dentro de pastas separadas. Isso ajuda a organizar os compo-
nentes.
Os módulos de programação – de puro código ou a janela de código associ-
ada aos formulários – têm aspecto idêntico. Trata-se de janelas para edição de
texto, encimadas por duas caixas de combinação que exibem os nomes Geral e
Declaração. Nos formulários, a caixa Geral exibe a lista dos controles (caixas de
texto, rótulos, botões de comando etc.). Quando se seleciona um desses contro-
les na caixa Geral, a outra caixa, Declaração, passa a exibir a lista dos eventos as-
sociados ao controle em destaque.
Nos módulos de puro código, a caixa Geral, normalmente, não tem conte-
údo, enquanto Declaração lista as subs e funções pertencentes ao módulo.

Caixa de ferramentas e controles


Outro item importante no ambiente de programação do Visual Basic é a Cai-
xa de Ferramentas. Nela estão os controles que você deve arrastar para o for-
mulário. Para tornar a caixa de ferramentas visível, acione o comando Exi-
bir/Caixa de Ferramentas. Mas, coerentemente, isso só ocorre quando um
formulário tem o foco. Se você não consegue distinguir o controle pelo ícone
que o identifica, passe o cursor do mouse sobre ele e aparecerá uma legenda
pop-up.
O VBA traz catorze controles embutidos. Veja abaixo a caracterização bá-
sica de cada um. As expressões entre parênteses correspondem aos nomes dos
controles como vão aparecer no código VBA. 51
F I G U R A 5 . 3 Caixa de ferramentas

CONTROLE DESCRIÇÃO

Rótulo Caixa de texto que não pode ser editada pelo usuário.
(Label) Neste livro, pelo hábito de lidar com versões antigas do
Access e com todas as versões do Visual Basic, esses
controles são chamados, indiferentemente, de rótulos,
etiquetas ou labels.

Caixa de texto Espaço no formulário reservado para digitação. Pode ter


(TextBox) uma ou múltiplas linhas.

Caixa de combinação Controle que combina (daí o nome) uma caixa de texto e
(ComboBox) uma caixa de listagem.

Caixa de listagem Caixa que exibe informações textuais, uma em cada


(ListBox) linha.

Caixa de seleção Pequeno controle que pode ser ligado ou desligado com
(CheckBox) um clique do mouse. Ativado, ele apresenta o sinal de um
tique. No VBA atual é chamado de caixa de seleção, mas a
própria Microsoft já chamou esse controle de caixa de
verificação.

Botão de opção Também conhecido como botão de rádio, esse


(OptionButton) controle, normalmente, é utilizado em grupos e dentro
de uma moldura. Qual a diferença entre um grupo de
botões de opção e um grupo de caixas de seleção?
No primeiro, somente uma alternativa pode ser escolhida.
No outro, pode-se marcar uma, nenhuma ou várias
alternativas.

Botão de ativação Talvez uma tradução mais correta para esse controle fosse
(ToggleButton) botão de comutação. Ele ativa ou desativa uma
característica. Essencialmente, tem papel semelhante ao da
caixa de seleção. Se ele se mostrar pressionado, a opção
está ativa.

Moldura Em geral, esse controle não faz nada. Apenas ajuda a


(Frame) organizar a interface – por exemplo, reunindo em si um
conjunto de botões de opção ou caixas de seleção.
52
CONTROLE DESCRIÇÃO

Botão de comando Normalmente, um clique nesse controle dispara uma


(CommandButton) operação. É, com certeza, o objeto mais popular de todas
as interfaces gráficas.

Faixa de tabulação Embora tenha funções diferentes, esse controle é quase


(TabStrip) sempre substituído pelo Multipágina.

Multipágina Implementa, num formulário, o recurso encontrado no


(Multipage) Windows e no próprio Word: as caixas de diálogo com
múltiplas orelhas, ou guias.

Barra de rolagem Representa um controle deslizante como os que se usavam


(ScrollBar) antigamente em aparelhos de som para aumentar ou
baixar o volume. Conforme você a desenhe, assume
posição horizontal ou vertical.

Botão de rotação Botão com duas setas, uma para cima e outra para
(SpinButton) baixo, usado em combinação com caixas de texto
ou rótulos nos quais é preciso incrementar ou reduzir
um número. Um exemplo desse objeto está no ajuste
do ano, na opção Data/Hora do Painel de Controle do
Windows.

Imagem Objeto para suporte de figuras no formulário.


(Image)

Além dos controles nativos, o ambiente do VBA aceita a incorporação de


outros disponíveis no Windows. Um exemplo disso é mostrado no Capítulo 33,
na aplicação Prazo Certo. Seu formulário principal inclui o objeto calendário,
que vem no pacote do Office Professional, tanto na versão 97 como na 2000.
Esse controle contém em si toda a inteligência do calendário gregoriano e facili-
ta não somente as consultas, como também as entrada de dados e as operações
baseadas em datas.

Propriedades e eventos
Formulários e objetos apresentam propriedades e eventos. As propriedades cor-
respondem a características do objeto, como comprimento (Width), altura (He-
ight) ou Cor de fundo (BackColor). Algumas propriedades são comuns a quase
todos os controles, como a posição horizontal, ou esquerda (Left), e a posição
vertical (Top). A referência, no caso, é o canto superior esquerdo do formulário,
que representa a posição (0, 0). Observe que, nesse caso, a coordenada vertical,
ao contrário do que você aprendeu sobre o plano cartesiano, cresce de cima
para baixo (Figura 5.4).

53
F I G U R A 5 . 4 Coordenadas no formulário

Os eventos correspondem a ocorrências que afetam o objeto enquanto o


programa está em execução. São eventos, por exemplo, as seguintes ações:
n o clique do mouse num botão de comando ou num formulário;
n o pressionamento de uma tecla;
n a recepção do foco da ação por uma caixa de texto;
n o duplo clique do mouse numa caixa de listagem.
Nesses exemplos, todos os eventos são provocados pelo usuário. No en-
tanto, também existem eventos que não dependem diretamente do usuário. É o
caso de Initialize e Terminate, que ocorrem respectivamente quando um formu-
lário é ativado e quando ele está sendo desativado e excluído da memória.
A cada evento pode corresponder um trecho de código, indicando o com-
portamento que o programa deve assumir diante daquela situação específica. Se
você tem, por exemplo, um botão chamado cmdMensagem, a rotina cmdMen-
sagem_Click representa o que o programa deve fazer quando ocorrer um clique
no botão. Se a intenção é exibir um aviso, a rotina ficará assim:

Private Sub cmdMensagem_Click()


MsgBox “Você clicou no botão Mensagem.”
End Sub

E o resultado, na prática, será a exibição de uma caixa de mensagem:

F I G U R A 5 . 5 Caixa de mensagem

54
Cada controle tem um evento-padrão e uma propriedade-padrão. O even-
to-padrão você identifica da seguinte maneira. Num formulário, desenhe uma
caixa de texto. O nome dela, antes de você personalizá-lo, será TextBox1. Dê
um duplo clique nesse objeto. Abre-se a janela de código do formulário, no
evento-padrão. Para caixas de texto e barras de rolagem, o padrão é Change.
Para botões de comando, figuras Image e formulários, o evento-padrão é Click.
O método para identificar a propriedade-padrão também é simples. Para
definir uma propriedade, usa-se o nome do objeto e o nome da propriedade, se-
parados por ponto, e o valor. Por exemplo, para ocultar uma caixa de texto cha-
mada txtValor:

txtValor.Visible = False

A propriedade-padrão é aquela assumida pelo objeto sem necessidade de


nomeá-la. Cada controle tem sua propriedade padrão. Para caixas de texto, ela
é a propriedade Text. Portanto, em lugar de escrever

txtValor.Text = “250,56"

você pode indicar, direto:

txtValor = “250,56"

Veja, a seguir, as propriedades-padrão de alguns controles:

CONTROLE PROPRIEDADE-PADRÃO

Caixa de texto Text

Rótulo, ou etiqueta Caption

Botão de opção Value (True/False)

Procedimentos do Visual Basic


Procedimento é uma seqüência de instruções executadas como uma unidade.
Por isso mesmo, um procedimento não pode estar contido em outro. Além dis-
so, todo código executável deve estar dentro de um procedimento. Há dois
principais tipos de procedimentos no Visual Basic: Sub (abreviação de subpro-
grama ou sub-rotina) e Function.
As diferenças entre Sub e Function são sutis. Mas, para uma distinção inici-
al, vale considerar que a Sub executa ações, mas não retorna um valor. Diferen-
temente, o procedimento Function sempre retorna um valor. Em outras pala-
vras, você recorre a um procedimento sub quando deseja que um conjunto de 55
ações seja realizado; e a um procedimento Function quando precisa obter uma
resposta. À sub você diria: “imprima o documento”. À function, perguntaria:
“qual o valor das contas a pagar para o mês de agosto?” e receberia o valor como
resposta.
Toda sub começa com a instrução Sub e termina com End Sub. Da mesma
forma, um procedimento function começa com Function e termina com End
Function. Todos os procedimentos associados a eventos do Visual Basic são do
tipo Sub.

Tipos de variáveis
Ao desenvolver um aplicativo, você lida com diferentes tipos de variáveis. Algu-
mas são números, outras são texto e outras se referem a objetos do sistema,
como controles ou programas. Nas versões atuais, o Visual Basic e o VBA (não o
VBScript) reconhecem os tipos de dados mostrados na tabela a seguir.

TAMANHO DE
TIPO DE DADOS ARMAZENAMENTO INTERVALO

Byte 1 byte de 0 a 255

Boolean 2 bytes True ou False

Integer 2 bytes de -32.768 a 32.767


(inteiro)

Long (número 4 bytes de -2.147.483.648 a 2.147.483.647


inteiro longo)

Single (vírgula 4 bytes de –3,402823E38 a -1,401298E-45 para


flutuante de valores negativos; de 1,401298E-45 a
precisão simples) 3,402823E38 para valores positivos

Double (vírgula 8 bytes de –1,79769313486231E308 a


flutuante de dupla -4,94065645841247E-324 para valores
precisão) negativos; de 4,94065645841247E-324 a
1,79769313486232E308 para valores
positivos.

Currency (número 8 bytes de -922.337.203.685.477,5808 a


inteiro em escala) 922.337.203.685.477,5807

Decimal 14 bytes +/-79.228.162.514.264.337.593.543.950.


335 sem vírgula decimal;
+/-7,9228162514264337593543950335
com 28 casas decimais à direita; o menor
número diferente de zero é
+/-0,0000000000000000000000000001.
56
TAMANHO DE
TIPO DE DADOS ARMAZENAMENTO INTERVALO

Date 8 bytes De 1 de janeiro de 100 a 31 de dezembro


de 9999

Objeto 4 bytes Qualquer referência Object

String 10 bytes + De 0 a, aproximadamente, 2 bilhões


(comprimento comprimento
variável) da seqüência

String Comprimento De 1 a, aproximadamente, 65.400


(comprimento fixo) da seqüência

Variant 16 bytes Qualquer valor numérico até o intervalo de


(com números) um Double

Variant 22 bytes + O mesmo intervalo de String de


(com caracteres) comprimento da comprimento variável
seqüência

Os valores indicados na coluna Tamanho de Armazenamento referem-se


ao espaço consumido para guardar cada tipo de variável. Para obter o melhor
resultado em suas aplicações, é preciso que você diga ao VBA a qual tipo perten-
ce cada variável. A identificação das variáveis se faz com a instrução Dim:

Dim strNome As String


Dim intContador As Integer

Para que não pareça uma palavra vinda do nada, Dim provém de dimensio-
nar. Aliás, por causa disso usa-se “declarar uma variável” ou “dimensionar uma
variável”. O termo dimensão faz sentido, porque as variáveis têm tamanho. Pri-
meiro, pelo espaço que ocupam em disco ou na memória. Depois, por causa de
sua extensão. No Visual Basic, assim como em outras linguagens, o espectro dos
números inteiros (Integer) varia de -32.768 a 32.767. Portanto, se sua variável
deve abrigar números além desses limites, você não pode declará-la como intei-
ro (As Integer). Caso contrário, haverá um estouro de capacidade.
Naturalmente, você também não pode querer somar variáveis numéricas
com variáveis de texto. Tudo isso parece muito óbvio, mas confusões desse tipo
são muito comuns entre os novatos em programação. Para reduzir as possibili-
dades desse tipo de erro, uma das primeiras coisas que você deve fazer, ao come-
çar a programar com Visual Basic, é acionar, no ambiente do VBA, o comando
Ferramentas/Opções e ligar a alternativa Requerer Declaração de Variável. O
que é isso?
Com essa opção ligada, se você usar uma variável não declarada, o VBA
produzirá um erro. Também será um erro se você declarar uma variável chama-
da intControle e depois referir-se a ela como intContorle, trocando letras na di- 57
gitação. Sem aquela opção ligada, o VBA assume que essa segunda forma é outra
variável – o que conduzirá a falhas em seu programa. Aliás, em muitos casos, es-
sas são as falhas mais difíceis de detectar, porque estão justamente onde você
não procura. Além disso, você passa e repassa a rotina e não vê a troca de letra.
Há ainda uma última desvantagem quando você não explicita suas variá-
veis. O programa pode não conter erros, mas vai rodar de forma mais lenta, já
que o VB terá um trabalho extra convertendo e identificando variáveis.
Para resumir a questão dos tipos de variáveis, podemos classificá-los em
seis grandes grupos:

GRUPO TIPOS

Variáveis Numéricas Byte


(Inteiros) Boolean
Integer
Long

Variáveis Numéricas Single


(Vírgula flutuante) Double
Currency
Decimal

Variáveis Numéricas Date


(Data)

Variáveis-Objeto Objeto

Variáveis de Texto String


(Comprimento variável)
String
(comprimento fixo)

Variants Variant (texto)


Variant (número)

Se você observar direitinho, vai perceber que esses seis grupos na verdade
podem ser resumidos em três: variáveis numéricas, variáveis de texto e de obje-
tos. No entanto, as subdivisões dos dois primeiros tipos são necessárias para de-
finir as dimensões das variáveis.
As variáveis do tipo Variant merecem atenção especial. Como o nome su-
gere, elas pertencem a um ramo mutante, que pode assumir a condição de texto,
número, data/hora ou objeto. Quando você não declara o tipo de uma variável,
este é automaticamente definido como Variant. Aí está mais um problema. Um
valor que, por exemplo, poderia ocupar apenas um byte (variável Byte) passa a
ocupar até 22 bytes. Também assumem a condição de Variants as variáveis de-
claradas sem tipo explícito. Por exemplo:

58 Dim Valor
É claro que existem motivos para a existência desse tipo de variável. No
entanto, eles não são muito comuns. Por isso, faça um esforço especial para indi-
car claramente o tipo da variável. Mesmo que seja Variant.

Escopo das variáveis


Além da classificação por tipos, as variáveis também se definem conforme a ex-
tensão de sua validade dentro de um projeto. Uma aplicação envolve formulá-
rios e módulos. Dentro de cada um desses contêineres existem ainda os procedi-
mentos, notadamente as funções e as sub-rotinas. Esquematicamente, pode-se
representar um projeto com o esboço mostrado na Figura 5.6. Os quadrados e
círculos são, respectivamente, subs e funções.
Algumas variáveis são declaradas (Dim strNome As String) dentro de um
procedimento (sub ou função), e têm validade apenas nesse espaço. Outras são di-
mensionadas da mesma forma, na área de declarações do módulo ou formulário.
Essas têm alcance mais abrangente: valem em todo o espaço do módulo ou for-
mulário. Um exemplo: a variável strNome está declarada como válida para todo
um módulo. Num procedimento qualquer, atribui-se a ela o valor “Teresa”:

strNome = “Teresa”

Agora, esse valor pode ser obtido ou redefinido com base em qualquer pro-
cedimento do módulo.
Há outro tipo de variáveis ainda mais abrangente. Trata-se daquelas que
são declaradas a partir de um módulo ou formulário e marcadas com a instrução
Public. Por exemplo:

Public strNome as String

Essa variável pode ser lida ou modificada a partir de qualquer procedimen-


to do projeto, pertença ele a um módulo ou a um formulário. Para simplificar,
podemos associar o projeto a um país; os formulários e módulos aos Estados; e
os procedimentos aos municípios. Assim, fica fácil entender que existem variá-
veis de alcance municipal, estadual e federal.
De modo semelhante, existem subs e funções que só valem dentro de seus
módulos ou formulários. Essas são marcadas com a instrução Private. Um pro-
cedimento do tipo private (privado), pertencente ao módulo A, não pode ser
chamado de qualquer código do formulário B. No entanto, se esse procedimen-
to for declarado como Public, será visto de qualquer outro procedimento do
projeto. Portanto, existem também procedimentos estaduais e federais.
Para que uma macro, contida num módulo de programação, apareça na
lista de macros da caixa Ferramentas/Macro/Macros, é preciso que ela seja de-
clarada como pública. Outro detalhe importante: só se consideram macros os
59
F I G U R A 5 . 6 Esquema de um projeto VBA: os quadrados são
subs; os círculos, funções

procedimentos públicos do tipo sub – funções não. Vale lembrar, também, que
um procedimento público fica disponível para todos os projetos carregados no
ambiente.
Mediante o comando Arquivo/Exportar Arquivo, você pode salvar, em
disco, formulários, módulos e módulos de classe. Pode, também, fazer a opera-
ção inversa com o comando Arquivo/Importar Arquivo. Os arquivos correspon-
dentes a formulários têm a extensão FRM; os de módulo, a extensão BAS (de
Basic); e os de classe, a extensão CLS. Cada arquivo FRM se faz acompanhar de
outro arquivo com o mesmo nome e extensão FRX. Este contém informações
binárias (não textuais) do formulário. Portanto, para transportar um formulá-
rio, você precisa levar os dois arquivos, FRM e FRX. Mas, na hora de importar,
basta apontar para o FRM – o outro é carregado, automaticamente.

A ajuda pop-up e outras ajudas


O ambiente de programação do Visual Basic representa hoje o que há de mais
amistoso para o desenvolvedor. Um de seus pontos de destaque é a ajuda
pop-up, que literalmente salta aos olhos. Quando por exemplo, você vai decla-
rar uma variável, basta escrever Dim Valor As... e uma caixa com todas as possi-
bilidades da variável aparece na tela.
Do mesmo modo, quando você vai chamar uma função ou sub – inclusive
aquelas que você mesmo criou em seu programa –, o VBA mostra uma informa-
ção com todos os parâmetros pedidos pelo procedimento.
Mas o usuário não precisa se restringir ao auxílio que não é solicitado. Há
também formas explícitas de pedir ajuda. Se você tem dúvida sobre um objeto,
uma propriedade ou um método, clique em cima do nome dele com o botão di-
reito do mouse. Surge um menu de contexto com uma série de opções.
60
F I G U R A 5 . 7 Ajuda pop-up durante a digitação

F I G U R A 5 . 8 Outra forma de ajuda: os parâmetros de uma


função

F I G U R A 5 . 9 Menu de contexto

Escolha Listar Propriedades e Métodos, e a janela pop-up aparecerá. Nes-


sas condições, praticamente não há como errar. Com essa lista à disposição, fica
difícil você fazer referência a um método ou propriedade inexistente. Outras al-
ternativas úteis são Informações Rápidas, Listar Constantes e Informações do
Parâmetro.
Destaque especial merece a opção Pesquisador de Objeto, que abre a janela
de mesmo nome e lhe permite pesquisar objetos, métodos e propriedades. Para
pesquisar, digite a expressão desejada na segunda caixa de combinação, no can-
to superior esquerdo da janela, e acione Enter. Pronto: você tem aí uma referên-
cia completa do objeto procurado, do projeto em que você está trabalhando e de
todas as bibliotecas disponíveis no ambiente. 61
F I G U R A 5 . 1 0 Propriedades e métodos

F I G U R A 5 . 1 1 O Pesquisador de Objeto: referência completa


sobre o ambiente

Segurança no VBA
Uma das diferenças entre as versões 2000 e 97 do Office está na forma como são
tratados os documentos que contêm macros. No 97, ao abrir um documento
desse tipo no Word ou no Excel, o usuário recebe um aviso de que aquele arqui-
vo pode conter vírus. No 2000, há três níveis de proteção: baixo, médio e alto.
Com o nível baixo – absolutamente não recomendado –, seu processador de tex-
to deixa a porta escancarada para a entrada de vírus, especialmente se você não
estiver usando um antivírus.
O nível médio de proteção é, praticamente, obrigatório se você quiser ex-
perimentar com os aplicativos do CD que acompanha este livro. Esse nível esta-
belece um comportamento idêntico ao da versão 97. Ou seja, o Word vai avisar
que o arquivo pode conter vírus e você tem a opção de confirmar ou não a ativa-
ção das macros. Quando a segurança está colocada no grau mais alto, o progra-
ma, simplesmente, desativa as macros contidas no documento e não dá nenhum
aviso.
62
Outro aspecto de segurança está ligado à proteção do código escrito em
VBA. Mas este é válido para as duas versões. Se você produziu um programa ge-
nial e não quer que ninguém venha bisbilhotar o seu código, proteja-o. No VBA,
selecione o projeto desejado e acione Ferramentas/Propriedades de <nome do
projeto>. Ou então clique com o botão direito na pasta do projeto e escolha a
mesma opção no menu de contexto. Agora, na tela de propriedades, traga para
o primeiro plano a orelha Proteção. Nela, marque a caixa Bloquear Projeto para
Exibição, depois digite e confirme a senha. A partir desse momento, ao tentar
abrir o projeto, o Word exigirá a digitação da senha.

F I G U R A 5 . 1 2 Tela para proteção do código com senha

Muito bem, seu código está a salvo de terríveis espiões e sabotadores. Mas
cuidado: não cometa a bobagem de esquecer a senha. Nesse caso, o projeto
vai-se tornar secreto até mesmo para próprio autor.

Fontes de estudo
Conhecer uma linguagem de programação significa trabalhar corretamente
com seus tipos de variáveis e instruções. Só que ninguém consegue isso lendo
um livro com a lista completa de comandos e palavras-chave. Uma das for-
mas mais eficazes de aprender é partir de códigos já escritos por outrem.
Analisando rotinas prontas e funcionais, você vê, na prática, como os proce-
dimentos funcionam e pode ter idéias de modificá-los, ajustando-os a seus
próprios projetos. 63
A melhor fonte de consulta a respeito do VBA é a própria Ajuda do produ-
to. Em geral, as instalações típicas do Office não instalam os arquivos de help
para o VBA do Word e dos outros programas da suíte. Portanto, se você pressio-
nar F1 no ambiente do Visual Basic e não obtiver ajuda, volte à instalação do
Office e inclua esse item.
Para escrever este livro, tive de consultar inúmeras vezes o help do VBA no
Word 97 e no 2000. Dá para afirmar que se encontra ali um material bastante
completo sobre o Visual Basic, em termos genéricos, e sobre a programação com
objetos do Word. Além de estar em português, a documentação contida na Aju-
da vem recheada de exemplos – que, como foi dito acima, representam o melhor
impulso para o aprendizado. Outra fonte de aprendizado é o site da Microsoft
dedicado ao desenvolvimento na plataforma Office: http://msdn.microsoft.com/
officedev/default.asp.
Também é válido e recomendável aprender VBA “colando” do Word. Em
dúvida sobre qual objeto usar ou qual a sintaxe adequada, mande o processador
de texto programar e depois copie dele. Como? Grave uma macro: Ferramen-
tas/Macro/Gravar Nova Macro. A isso podemos chamar, literalmente, de apren-
der com quem sabe.
Para não dizer que não falei de fontes impressas, aqui vai uma pequena se-
leção de manuais de programação em VBA. Infelizmente, todos eles estão em in-
glês. Coloquei-os em ordem crescente de profundidade técnica. Os dois primei-
ros têm a vantagem de ser os manuais “oficiais” da linguagem, produzidos pela
própria Microsoft ou sob a supervisão dela.
Os dois outros são leitura bastante avançada. Deborah Kurata é considera-
da a papisa da orientação a objeto no Visual Basic. Seu livro Doing Objects já
tem uma versão mais atual, voltada para o VB 6.0. Por fim, o manual de Ken
Getz e Mike Gilbert é um produto monumental para quem trabalha com VBA
ou com o Visual Basic. Traz centenas de rotinas prontas, feitas com programa-
ção de altíssimo nível. Em muitos casos, também orientada a objeto.

Microsoft Office 97 Visual Basic Programmer’s Guide


Microsoft Press, EUA, 1997

David Shank, Mark Roberts & Tamra Myers


Microsoft Office 2000 Visual Basic Programmer’s Guide
Microsoft Press, EUA, 1999

Deborah Kurata
Doing Objects in Visual Basic 5.0
Ziff-Davis Press, EUA, 1997

Ken Getz & Mike Gilbert


VBA Developer’s Handbook
64 Sybex, EUA, 1997
Não conheço nenhum livro voltado especificamente para o VBA do Word.
As publicações tendem a tratar do Office como um todo – o que faz sentido, já
que dificilmente alguém usa uma aplicação de escritório de forma isolada. Mes-
mo neste livro, em vários projetos trabalhamos com recursos do Access e do
Excel.

Quem disse que o nome não importa?


No capítulo anterior, demos o exemplo de uma macro para abrir a Cal-
culadora do Windows a partir de um botão de comando numa barra de
ferramentas do Word. O nome mais óbvio para essa macro seria Cal-
culadora. No entanto, ela se chama Calcular. Esse nome não foi adota-
do por acaso.
Se você batizar a macro como Calculadora, ela simplesmente não
vai funcionar. A macro usa o objeto Tasks para testar se um aplicativo
com o título Calculadora está ativo no Windows. Se estiver, em vez de
carregar o programa no disco, ela simplesmente traz para o primeiro
plano a instância que já está rodando. Mas se a macro se chama Calcu-
ladora, ela mesma é uma tarefa ativa que tem o nome procurado.
Então, o objeto Tasks é induzido a erro: ele acusa que sim, existe um
programa rodando. Com isso, o próximo passo é tentar trazer a Calcu-
ladora para a frente – e ela não existe.
Mesmo que você chame a macro de AbreCalculadora, o proble-
ma continua porque há uma coincidência de parte dessa expressão
com a outra. Moral da história: atenção com os nomes de macros.

65
PARTE 2
6
O sistema
informa

Um programa que mostra dados sobre


a máquina, o Windows e o Word

Ficha do projeto

Projeto:

Informações do Sistema

O que faz:

Apresenta informações sobre o computador, o sistema


operacional e o Word.

Arquivos e requisitos do projeto:

Formulário frmSystemInfo e código interno.

Conhecimento técnico:

Contato com funções do VBA/Word que fornecem


informações sobre o Word, a máquina e o sistema
operacional.

Nível de programação:

Iniciante
Neste capítulo, nossa meta é construir uma caixa de diálogo que forneça infor-
mações sobre o Word, o sistema operacional e a máquina. Para isso, vamos usar,
fundamentalmente, os serviços do objeto System, disponível no VBA/Word.
Esse objeto pode ser bastante útil no desenvolvimento de aplicativos no Word,
quando é necessário coletar dados como a resolução de vídeo, a versão do siste-
ma operacional ou a situação de periféricos instalados no micro. A seguir, uma
lista com as principais propriedades de System:

PROPRIEDADE DE SYSTEM O QUE FAZ

Application Retorna o nome do aplicativo, no caso o Word.

Country Fornece o país do sistema operacional. Corresponde,


no Word, ao valor da variável interna wdCountry. Em
nosso caso, wdCountry é igual a wdBrazil, ou 55.

FreeDiskSpace Retorna o espaço livre no disco rígido ativo. Esse valor


é fornecido em bytes. Portanto, para facilitar a leitura,
pode ser transformado em quilobytes (KB), se dividido
por 1024; em megabytes (MB), se dividido por
1024x1024; e em gigabytes (GB), quando dividido por
1024x1024x1024.

HorizontalResolution e Informam, respectivamente, a resolução horizontal e a


VerticalResolution resolução vertical, em pixels, usadas no vídeo.

LanguageDesignation Retorna o nome do idioma, tal como é indicado pelo


sistema operacional.

OperatingSystem Informa o nome do sistema operacional. Por exemplo,


“Windows”, “Windows NT” ou “Windows 2000”.

PrivateProfileString Retorna ou define uma string armazenada no Registro


do Windows ou num arquivo INI. Veja exemplo de uso
desta propriedade nos Capítulos 11 a 14 nesta parte
do volume.

ProcessorType Indica o tipo de processador usado na máquina. Por


exemplo, “Pentium”.

Version Retorna o número da versão do sistema operacional.


Não confundir com a propriedade homônima do objeto
Application, que fornece a versão do Word.

Para usar os recursos do objeto System, vamos construir um formulário


(frmSystemInfo) nos moldes da Figura 6.1, mostrada adiante. Trata-se de um
formulário com uma moldura (Frame1), seis etiquetas (labels) dentro dessa mol-
dura (labTipoProcessador, labResVideo, labIdioma e labAplicação). Além dis-
so, há os botões cmdFechar, cmdInfoSistema e cmdPainel.
70
Você deve estar perguntando por que escolhemos usar labels, e não caixas
de texto, para receber as informações do sistema. A razão é simples: trata-se de
controles apenas para exibir os dados ao usuário – que, naturalmente, não pode-
rá modificá-los. Como padrão, as etiquetas são apresentadas com fundo de cor
igual à do formulário. Para facilitar a leitura dos dados, a propriedade BackCo-
lor das seis etiquetas foi mudada para branco. No caso, esse ajuste foi feito sele-
cionando-se o controle e ajustando a cor na linha BackColor da caixa Proprie-
dades. No entanto, também seria possível fazer isso em código, indicando na
sub UserForm_Initialize:

labTipoProcessador.BackColor = vbWhite

A constante vbWhite é um valor interno do Visual Basic e corresponde à


cor branca. Existem também vbGreen, vbYellow, vbBlack, vbBlue etc. Cada
uma das seis labels de dados traz à esquerda outra etiqueta que a identifica: Pro-
cessador, Espaço Livre em Disco, Resolução do Vídeo, Sistema Operacional,
Aplicação e Idioma.

F I G U R A 6 . 1 O formulário frmSystemInfo em construção

Vejamos, agora, como fazer para que o formulário exiba essas proprieda-
des. Na maioria dos casos, a aplicação é direta. Basta atribuir à etiqueta o valor
da propriedade:

labTipoProcessador = “ ” & System.ProcessorType

Observe que usamos um espaço antes do valor da propriedade. O objetivo


é afastar o texto da borda esquerda da etiqueta, assim como ocorre nas caixas de
texto. 71
Para as labels labSistOp e labAplicação, a atribuição dos valores não foi di-
reta. No caso do sistema operacional, a informação é fornecida em dois peda-
ços: o nome do sistema e a versão. Esta última também não é direta. Se o sistema
é “Windows” e a versão é “4.0”, trata-se do Windows 95; se “4.10”, temos en-
tão o Windows 98.
Com a etiqueta labAplicação, o processo é idêntico. Ela é preenchida pela
combinação de duas informações: o nome do programa (“Microsoft Word”) e a
versão. Aqui, há um pequeno detalhe ao qual se deve prestar atenção. Estas duas
propriedades não pertencem ao objeto System, e sim ao objeto Application, que
representa o Word. Outra observação: a propriedade Version, de Application,
retorna o número serial do Word: “8.0”, “8.0a”, “9.0”. Aqui, “forçamos a bar-
ra” para que a série “8.0” venha acompanhada de “(97)”, que é o nome mais co-
mum da versão. Do mesmo modo, “9.0” é transformado em “9.0 (2000)”. Veja
na Figura 6.2 a caixa de diálogo exibindo dados do meu sistema.

F I G U R A 6 . 2 A caixa Informações do Sistema

Faltam, agora, os três botões de comando situados no topo da tela. Sobre


o botão Fechar, claro, não é necessário falar. E o que faz o botão Info do Siste-
ma? Ele usa o método MSInfo, do objeto System, que abre o utilitário Infor-
mações do Sistema, do Windows, oferecendo um painel completo da máqui-
na, do sistema operacional e dos programas instalados. Para isso, basta uma li-
nha de código:

System.MSInfo

O outro botão da caixa de diálogo dá acesso ao Painel de Controle. Aqui, o


recurso utilizado não tem nada a ver com o objeto System, do VBA/Word. Para
72 abrir o Painel de Controle, estamos lançando mão da função intrínseca Shell e
F I G U R A 6 . 3 Utilitário Informações do Sistema, aberto a partir
da caixa de diálogo

do programa Rundll32.exe, do Windows, combinado com a biblioteca


Shell32.dll. Assim, para abrir o Painel de Controle, usamos a seguinte linha de
código:

Shell “rundll32.exe shell32.dll,Control_RunDLL”, _


vbNormalFocus

Adicionando alguns parâmetros a essa forma de chamar o Painel de Con-


trole, pode-se abrir, diretamente, alguns dos utilitários do Painel. Por exemplo,
para o item Adicionar Novo Hardware, usa-se o parâmetro sysdm.cpl @1:

Shell _
“rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl @1", _
vbNormalFocus

Para abrir a janela Propriedades de Vídeo – o equivalente a clicar com o bo-


tão direito no desktop e acionar Propriedades –, basta usar como parâmetro o
nome do arquivo Desk..cpl:

Shell “rundll32.exe shell32.dll,Control_RunDLL desk.cpl”, _


vbNormalFocus

A regra geral, para esses casos, é usar o comando seguido do nome da apli-
cação do Painel de Controle, um arquivo com a extensão CPL.

73
F I G U R A 6 . 4 Painel de Controle: chamado a partir do aplicativo

Para ir mais além


1. Observe se a propriedade System.ProcessorType funciona adequada-
mente em seu sistema. No meu, um Celeron 333, ela fornece “Penti-
um”. No Painel Meu Computador, a informação está correta. Talvez o
sistema do Word não seja tão atualizado quanto o do sistema operacio-
nal (Windows 98 SE).
2. As aplicações do Painel de Controle são arquivos com a extensão CPL
(de Control Panel) que se encontram no diretório de sistema do Win-
dows. Liste-as e tente abri-las com o método mostrado acima.
3. Os comandos para abrir o Painel de Controle e seus aplicativos funcio-
nam também na caixa Executar, do Windows, aberta pelo comando bo-
tão Iniciar/Executar. Lá, você não precisa de Shell. Basta digitar o co-
mando de forma direta. Exemplo:

rundll32.exe shell32.dll,Control_RunDLL intl.cpl

4. A função Shell, do Visual Basic, é usada em vários outros projetos neste


livro. Veja-a, por exemplo, nos capítulos que mostram como tocar ar-
quivos de som a partir do Word. Para entendê-la melhor, consulte a aju-
da do VBA.
5. A propriedade Country (país), do objeto System, não retorna uma
string, mas um número. Se você capturar o valor dela em seu Word, vai
obter o número 55, que corresponde a Brasil. Para testar se o país é Bra-
sil, use a seguinte linha:

74 If System.Country = wdBrazil Then


A constante intrínseca wdBrazil é igual a 55 – aliás, o mesmo código do
sistema de Discagem Direta Internacional, DDI.
6. Em alguns trechos de código citados como exemplos neste capítulo,
aparecem linhas que terminam com o sinal de sublinhado ( _ ). Esse ca-
ractere é usado no Visual Basic para quebrar uma linha lógica muito
comprida em duas ou mais linhas de texto. O objetivo é facilitar a leitu-
ra, na tela ou na página impressa. Para funcionar corretamente, o sinal
de sublinhado deve ter um espaço em branco separando-o do caractere
que o antecede.

Objetos exclusivos
O objeto System, discutido neste capítulo, é um exemplo de recurso di-
ferente de outros existentes no VBA. Se você tomar, por exemplo, o ob-
jeto Application ou o objeto FileSearch, verá que eles se aplicam do
mesmo modo no Word, no Excel, no Access (versão 2000) e em qual-
quer outro programa que incorpore o VBA. No entanto, System funcio-
na apenas no Word. Outro exemplo do mesmo tipo é a coleção Tasks,
que reúne todas as tarefas (programas) ativas no Windows em determi-
nado momento.

75
7
Quantos anos
você tem?

Calcule idades com precisão, baseado


na data atual fornecida pelo micro

Ficha do projeto

Projeto:

Cálculo da Idade

O que faz:

Esta pequena aplicação calcula a idade a partir de dois


pontos de referência: uma data de nascimento, fornecida
pelo usuário, e a data atual, lida no relógio do sistema.

Arquivos e requisitos do projeto:

Formulário frmIdade e código interno.

Conhecimento técnico:

Contato com funções do VBA referentes a data e hora.

Nível de programação:

Iniciante
O objetivo deste capítulo é simples: mostrar como se calcula a idade com
precisão, segundo os padrões de uso comum. Normalmente, a idade das pessoas
é uma função que se mantém constante ao longo de um ano e aumenta um pon-
to na data de aniversário. Por causa dessa característica especial, a determinação
da idade muitas vezes representa um problema para usuários de programas de
escritório.

F I G U R A 7 . 1 O formulário frmIdade

Basicamente, o cálculo da idade consiste numa subtração entre dois anos: o


ano atual menos o ano da data de nascimento. Ou, usando funções do VBA:

intIdade = Year(Now) - Year(DataNasc)

Só que, como sabemos, essa operação fornece resultados quase corretos.


Tudo depende de a data atual situar-se antes ou depois da data de aniversário. Se
a data atual estiver antes do aniversário, você vai afirmar que a pessoa tem por
exemplo 27 anos, mas a idade correta será 26. O código para ajustar o cálculo
fica assim:

intIdade = Year(Now) - Year(DataNasc)

If Month(Now) < Month(DataNasc) Then


intIdade = intIdade - 1
ElseIf Month(Now) = Month(DataNasc) Then
If Day(Now) < Day(DataNasc) Then
intIdade = intIdade - 1
End If
End If

Depois do resultado (inexato) obtido pela subtração dos dois anos, é preci-
so acrescentar um If para garantir a correção do número procurado. Aí, o algo-
77
ritmo aplica o raciocínio a seguir. Se o mês atual é menor que o mês de nasci-
mento, então o valor intIdade, obtido na primeira operação, deve ser subtraído
de 1. No entanto, se o mês de aniversário e os mês atual são iguais, é preciso ve-
rificar se o dia atual situa-se ou não antes do dia de aniversário. Tudo isso está
no If acima. Mas esse código pode ser abreviado para algo assim:

If Now < DateSerial(Year(Now), Month(DataNasc), _


Day(DataNasc)) Then
intIdade = intIdade - 1
End If

Com apenas três linhas, resolve-se tudo. Dito em palavras, o novo algorit-
mo envolve o seguinte: se a data de hoje (Now) é menor que a data formada pelo
dia e mês de nascimento aplicados ao ano atual, então subtrai-se 1 do valor inici-
almente calculado. Sem dúvida, essa última solução é bem mais econômica, em
termos de código. Esta solução engloba, inclusive, os casos raros em que a data
de nascimento é 29/02. Tomado como dia posicional – 29/02 é o 60o dia do ano
–, ele corresponde ao dia 01/03 nos anos não bissextos.

Desenho do formulário
O projeto para calcular idade envolve apenas um formulário, frmIdade. Além de
uma caixa de texto para a digitação da data de nascimento e uma label (rótulo
ou etiqueta, como queira) para a apresentação da idade calculada, merece desta-
que a label labHoje, que indica a data atual, com a legenda: “Hoje é dd/mm/yyyy”.
O objetivo de labHoje é dar ao usuário uma pista visual para que ele possa ter
certeza de que a idade foi calculada corretamente.

Para ir mais além


1. Os cálculos com variáveis de data e hora são, ao mesmo tempo, simples
e cheios de truques. Embora pareçam fáceis, sempre escondem armadi-
lhas que conduzem a erros. Para dominar esse item, faça exercícios de
programação, envolvendo as seguintes funções do VBA:
n Now
n Date
n Time
n Day, Month, Year
n Hour, Minute, Second
n DateSerial
78
n DateValue
n WeekDay (dia da semana)
n Format (aplicado a data e hora)
n DateDiff (subtração de datas)
n DateAdd (adição de datas)
n DatePart (parte da data: ano, mês, dia, semana etc.)
2. Em outros capítulos deste volume, você encontra aplicações de várias
dessas funções. Veja, por exemplo, o próximo capítulo, que trabalha
com o cálculo de datas, e o projeto dedicado ao cálculo de prazos co-
merciais.

Datas na virada do milênio


Quando você digita datas com apenas dois dígitos no ano, os aplicati-
vos do Office 97 e do Office 2000, assim como o Windows 98, interpre-
tam essas datas da seguinte maneira. Se o ano varia entre 00 e 29, en-
tão o século será o XXI: 2000 a 2029. Os anos seguintes – de 30 a 99 –
serão entendidos como pertencentes ao século XX: 1930 a 1999.
Esse procedimento facilita as coisas para quem escreve anos com
dois dígitos. Mas, para eliminar dúvidas na entrada de dados, o melhor
é você ir ao Painel de Controle/Configurações Regionais e definir a
data para o padrão dd/mm/aaaa. Isso não muda nada, mas trará mais
segurança visual. Pelo menos, quando digitar 15/03/05, o programa
mostrará, claramente, que você escreveu 15/03/2005. Esta é uma boa
providência a tomar nestes primeiros anos da passagem para o novo
século.

79
8
Duas datas e
um número

Um programa que calcula datas e prazos


simples

Ficha do projeto

Projeto:

Cálculo de Datas

O que faz:

Calcula datas pela adição ou subtração simples de um


determinado número de dias.

Arquivos e requisitos do projeto:

Formulário frmCalculaDatas e código interno.

Conhecimento técnico:

Operações com funções do VBA referentes a data e hora.

Nível de programação:

Iniciante
Depois de um projeto que calcula idade a partir da data de aniversário,
mostrado no capítulo anterior, vamos agora desenvolver um aplicativo que exe-
cuta operações aritméticas com datas. O Cálculo de Datas é um aplicativo que
trabalha com três variáveis básicas: uma data inicial, um número de dias e uma
data final. Flexível, ele trabalha da seguinte maneira: o usuário digita dois dos
itens e o programa oferece o terceiro como resultado.

F I G U R A 8 . 1 Cálculo com datas: resultado (Data Final) em azul

Para a montagem deste projeto, comecemos com a construção do formulá-


rio, frmCalculaDatas. Ele tem três caixas de texto para a digitação de dados, três
botões de comando e mais duas caixas de texto complementares. As primeiras
caixas de texto são DataInicial (txtDataIni), DataFinal (txtDataFim) e Número
de Dias (txtNumDias). Elas são, na verdade, controles de entrada e saída dos da-
dos, pois qualquer uma pode ser a caixa que apresenta o resultado da operação.
As duas caixas auxiliares são txtNomeDiaI e txtNomeDiaF. Elas simplesmente
exibem o nome do dia da semana das datas inicial e final.
Por fim, vêm os botões de comando. Calcular (cmdCalcular) executa a
operação; Fechar (cmdFechar) encerra o programa; e Limpar (cmdLimpar) apa-
ga o conteúdo de todas as caixas de texto, preparando o programa para outro
cálculo.
Vejamos, agora, o que acontece “embaixo do capô” desse aplicativo. Co-
mecemos do início. Quando o formulário se abre, o valor da caixa txtDataIni é
definido como a data atual. Em seguida, põe-se o foco da ação na próxima cai-
xa, txtNumDias:

txtDataIni = Date
txtNumDias.SetFocus

A primeira linha, acima, está no procedimento UserForm_Initialize. A ou-


tra se encontra em UserForm_Activate. Se o usuário não deseja fazer um cálculo
com a data de hoje, pode voltar ao campo txtDataIni e digitar nova data. De-
pois, ele deve clicar no botão Calcular. Então, o processamento começa. Em pri-
81
meiro lugar, a rotina cmdCalcular_Click verifica o estado de preenchimento das
três caixas de texto principais. Juntas, elas podem assumir oito situações: 2 esta-
dos (cheio, vazio) elevados à terceira potência (3 caixas). Para cobrir essas oito
situações, são definidos seis status, identificados pela variável intStatus, que as-
sume valores de 0 a 5:

0 – Dois campos quaisquer estão em branco


1 – Os três campos estão em branco
2 – Somente txtDataFim está em branco
3 – Somente txtNumDias está em branco
4 – Somente txtDataIni está em branco
5 – Os três campos estão preenchidos

Nos casos 0, 1 e 5, o usuário recebe uma mensagem de erro. Nos demais, o


preenchimento, em princípio, parece correto. Mas é preciso verificar se a data
digitada é realmente uma data válida. Isso se faz com a função intrínseca IsDate
(umaData), que retorna um valor booleano: True ou False. Se os valores digita-
dos passam no teste, então executa-se o cálculo adequado a cada caso.
Se Data Final é o campo em branco, o resultado é determinado com a se-
guinte linha:

txtDataFim = DateValue(txtDataIni) + Val(txtNumDias)

Para a Data Inicial:

txtDataIni = DateValue(txtDataFim) - Val(txtNumDias)

Para o Número de Dias:

txtNumDias = DateValue(txtDataFim) - DateValue(txtDataIni)

Todas essas operações baseiam-se na possibilidade de somar ou subtrair


datas e números de dias, obtendo datas ou dias. Em cada caso, o resultado no
campo-resposta é apresentado em letras de cor azul (vbBlue) e em estilo negrito
(Bold). Isso facilita a visualização: o usuário logo vê que o resultado está em des-
taque. Como se obtém essa cor? Basta chamar a rotina MudaCor, que recebe
como parâmetro um número (1, 2 ou 3) que identifica o campo-resposta.

Private Sub MudaCor(num As Integer)


‘ Muda ForeColor (cor da letra) do campo-resposta
Dim ctl As control
Dim ctlDestaque As control

82
‘ Define qual é o campo-resposta
Select Case num
Case 1: Set ctlDestaque = txtDataIni
Case 2: Set ctlDestaque = txtNumDias
Case 3: Set ctlDestaque = txtDataFim
End Select

‘ Fonte azul, em negrito, no campo-resposta


ctlDestaque.ForeColor = vbBlue
ctlDestaque.Font.Bold = True

‘ Fonte normal nos outros campos


For Each ctl In Me.Controls
If Left$(ctl.Name, 3) = “txt” And _
ctl < > ctlDestaque Then
ctl.ForeColor = vbBlack
ctl.Font.Bold = False
End If
Next ctl

End Sub

Nesta rotina, destacam-se duas variáveis do tipo Control (controle): ctl e


ctlDestaque. Elas representam, respectivamente, um controle qualquer do for-
mulário e o controle correspondente ao campo-resposta. Pelo índice recebido, a
rotina determina qual dos três controles é ctlDestaque. Para isso usa as instru-
ções Select Case e Set. Em seguida, definem-se as cores. As letras, no cam-
po-resposta, assumem a cor azul e o estilo negrito. Nos demais controles, a cor é
o preto (vbBlack) e o estilo, normal (Bold = False). Atenção ao detalhe: para lo-
calizar os controles não destacados, procura-se pelos controles cujos nomes co-
mecem com “txt” (as caixas de texto) e que não sejam iguais a ctlDestaque.
Falta-nos comentar duas rotinas interessantes: txtDataIni_Change e txtDa-
taFim_Change. Esses procedimentos, como os nomes indicam, definem o que o
programa deve fazer quando ocorre uma mudança nas caixas de texto corres-
pondentes. Vejamos o caso de txtDataIni:

Private Sub txtDataIni_Change()


If IsDate(txtDataIni) Then
txtNomeDiaI = Format$(txtDataIni, “ddd”)
Else
txtNomeDiaI = “”
End If
txtNomeDiaI.ForeColor = txtDataIni.ForeColor
txtNomeDiaI.Font.Bold = txtDataIni.Font.Bold
End Sub 83
Enquanto o usuário digita em txtDataIni, essa rotina é acionada a cada
nova tecla. Quando o conjunto de caracteres começa a fazer sentido como data,
a rotina imediatamente escreve o dia da semana correspondente na caixa de tex-
to à direita: txtNomeDiaI. Se o texto digitado não corresponder a uma data,
txtNomeDiaI permanece vazio.
O evento Change da caixa de texto também é disparado quando o próprio
programa escreve nela um resultado. Nesse caso, a caixa de texto é o cam-
po-resposta e suas letras recebem a cor azul. Para que o nome do dia fique da
mesma cor, a propriedade ForeColor de txtDataIni é copiada para txtNomeDi-
aI. Processo idêntico é feito com a propriedade Font.Bold. Assim, enquanto se
digita, os dois controles têm letras pretas. Quando é o programa que escreve, as
letras se tornam azuis. O procedimento associado às mudanças em txtDataFim
é, absolutamente, idêntico.
Quando o usuário aciona o botão Limpar, apaga-se o conteúdo de todas as
caixas de texto. Ao mesmo tempo, todas as letras voltam a ser pretas e em estilo
normal. Isso prepara o programa para iniciar novo cálculo.

Para ir mais além


1. O principal recurso usado neste projeto para calcular datas foi somar
uma data a um número (de dias). Você pode fazer essa mesma operação
com outra função do Visual Basic: DateAdd. A sintaxe de DateAdd é a
seguinte:
DataFinal = DateAdd (intervalo as string, _
número as Double, DataInicial)

Intervalo é uma string que determina a unidade de tempo considerada.


Assim, “d” é dia; “ww”, semana; “m”, mês. O número indica a quanti-
dade de intervalos.
Portanto, para adicionar 65 dias à data 15/02/2000, procede-se da
seguinte maneira:

DataFinal = DateAdd (“d”, 65, #15/02/2000#)

O resultado é DataFinal = 20/04/2000


Observe as cercas (#) em torno do número: elas indicam data.
Você também poderia passar esse valor como texto: “15/02/2000”. O
resultado seria o mesmo.
2. Consulte na ajuda do Visual Basic a sintaxe de duas funções similares a
DateAdd: DateDiff (diferença entre duas datas) e DatePart, que extrai
uma parte (dia, mês ou ano) de uma data.

84
Olho no formato da data
Observe as variações dos formatos de datas em algumas funções do Vi-
sual Basic. Em DateSerial, por exemplo, a ordem dos componentes de
uma data deve ser apresentada da seguinte maneira:

DateSerial (ano, mês, dia)

No entanto, quando se faz referência a uma data dentro de uma


declaração SQL, ela deve ser sempre apresentada no formato
#mm/dd/yyyy#. Por exemplo:

SELECT * FROM tabVendas


WHERE [DataVencimento] > #07/31/2000#

85
9
Seu Word salva
arquivos XMW?

Descubra quais arquivos externos seu


Word sabe ler ou escrever

Ficha do projeto

Projeto:

Tabela de conversores de arquivos disponíveis no Word

O que faz:

Prepara uma tabela, mostrando todos os tipos de arquivos


que seu Word é capaz de abrir e escrever.

Arquivos e requisitos do projeto:

Sub-rotina ConversoresDeArquivos.

Conhecimento técnico:

Manipulação básica da coleção FileConverters (conversores


de arquivos) e suas propriedades.

Nível de programação:

Intermediário
Os conversores de arquivos do Word estão reunidos numa coleção de objetos
chamada FileConverters. Dessa coleção fazem parte tanto os filtros usados pelo
programa para ler, como para escrever arquivos diferentes de seu padrão
(DOC). Alguns arquivos, como os do tipo TXT, podem ser lidos e gravados pelo
Word. Outros têm conversão exclusiva para o lado da leitura ou da gravação.
Há ainda aqueles que não têm nenhum tipo de conversão. Entre esses, encon-
tram-se os arquivos para os quais não existem filtros e também os arquivos cujos
filtros não estão instalados no sistema. Em outras palavras, duas máquinas com
a mesma versão do Word podem ter coleções de conversores diferentes. Isso de-
corre do fato de que os filtros não são todos instalados, automaticamente. A ins-
talação de boa parte deles depende de decisão explícita do usuário.
A coleção FileConverters é um objeto hierarquicamente subordinado ao
objeto Application, ou seja, ao próprio Word. As referências a objetos da cole-
ção são sempre feitas no padrão:

FileConverters(índice)

O índice pode ser uma string identificadora de um tipo de conversor.


Exemplo:

FileConverters(“MSWordMac”).OpenFormat

Pode, também, ser um número que representa a posição do conversor na


coleção. Exemplo:

FileConverters(3).FormatName

Os objetos da coleção FileConverters têm uma série de propriedades, das


quais as mais importantes estão listadas a seguir:

PROPRIEDADE TIPO DE VARIÁVEL O QUE FAZ

CanOpen Booleano Indica se o conversor especificado é capaz


de abrir arquivos.

CanSave Booleano Indica se o conversor foi desenvolvido


para salvar arquivos no formato
especificado.

ClassName String Retorna um nome único que identifica o


conversor de arquivos.
Exemplos: MSWord6, Lotus123.

Extensions String Fornece as extensões de nome de arquivo


associadas ao conversor especificado.
87
PROPRIEDADE TIPO DE VARIÁVEL O QUE FAZ

FormatName String Fornece o nome amigável do conversor. O


FormatName corresponde à expressão
apresentada na caixa de diálogo Salvar
Como, item Salvar Como Tipo.

Name String Retorna o nome do arquivo que contém o


conversor.

OpenFormat Long Número que identifica o tipo de arquivo a


ser aberto.

Parent Objeto Retorna o nome do objeto-pai do conversor


indicado. Esse objeto, no caso, é o Microsoft
Word.

Path String Fornece a pasta na qual está armazenado o


arquivo do conversor especificado.

SaveFormat Long Número que identifica o tipo de arquivo a


salvar.

O objetivo, agora, é usar a coleção FileConverters e algumas das proprie-


dades acima para construir uma tabela que mostre, em detalhes, todos os con-
versores instalados no Word. Para isso, será necessário usar apenas um procedi-
mento, a sub-rotina ConversoresDeArquivos. Ela começa abrindo um novo do-
cumento e definindo a orientação da página para Paisagem. Isso é feito porque
já sabemos que a tabela terá nove colunas, número difícil de acomodar na orien-
tação Retrato:

Documents.Add
ActiveDocument.PageSetup.Orientation = wdOrientLandscape

As nove colunas vão listar as principais propriedades de cada objeto File-


Converter. Elas aparecerão na seguinte ordem: Índice, ClassName, FormatNa-
me, Name, CanSave, SaveFormat, CanOpen, OpenFormat e Extensions. Os tí-
tulos foram mantidos em inglês porque correspondem, exatamente, ao nome
das propriedades.
O próximo passo é dar um título para o documento (“Conversores de
Arquivos Disponíveis”) e definir os títulos de cada campo da tabela. Vamos usar
o método TypeText e inserir os títulos seguidos de uma string de separação. No
exemplo, a string usada é a constante sSep, definida como o caractere #: No fi-
nal, insere-se um parágrafo (a constante vbCrLf):
Selection.TypeText “Índice” & sSep & “ClassName” & sSep & _
“FormatName” & sSep & “Name (Arquivo)” & sSep & _
“CanSave” & sSep & “SaveFormat” & sSep & “CanOpen” & _
88 sSep & “OpenFormat” & sSep & “Extensions” & vbCrLf
Definido o título da tabela e os nomes dos campos, passemos à montagem
do conteúdo das linhas. Para isso, vamos usar um loop para percorrer toda a co-
leção de conversores instalados. Esse loop For/Next vai girar de 1 até o total de
conversores da coleção. Cada linha é montada com a mesma técnica utilizada
para a linha de títulos:

For i = 1 To FileConverters.Count
sSaveFormat = “-”
sOpenFormat = “-”
With FileConverters(i)
If .CanSave Then sSaveFormat = Str(.SaveFormat)
If .CanOpen Then sOpenFormat = Str(.OpenFormat)

Selection.TypeText i & sSep & .ClassName & sSep & _


.FormatName & sSep & .Name & sSep & _
.CanSave & sSep & sSaveFormat & sSep & _
.CanOpen & sSep & sOpenFormat & sSep & _
.Extensions & vbCrLf
End With

A única diferença das linhas do corpo da tabela para a linha de títulos é im-
posta pelas propriedades SaveFormat e OpenFormat. Esses números só existem
quando o conversor é capaz de salvar ou abrir um tipo de arquivo. Se, por exem-
plo, você pedir a propriedade SaveFormat de um conversor que não salva, pro-
voca um erro. Situação idêntica ocorre com OpenFormat. Para evitar o proble-
ma, antes de solicitar o valor dessas propriedades, é obrigatório verificar as pro-
priedades CanSave e CanOpen. No loop, criamos duas variáveis string, sSave-
Format e sOpenFormat, ambas inicialmente com o valor “-”. Então, para cada
objeto FileConverter, consulta-se o valor de CanSave e CanOpen. Se for possí-
vel salvar, sSaveFormat será igual a SaveFormat. Se for possível abrir, sOpen-
Format será igual a OpenFormat. Nas outras situações, as duas strings irão para
a tabela como um traço, indicando que o número não existe para aquele conver-
sor. Quanto às propriedades CanOpen e CanSave, também incluídas na tabela,
o próprio Word encarrega-se de apresentá-las como “Verdadeiro” ou “Falso”.
Fim do loop. Todo o texto está num documento Word. São linhas conten-
do uma série de caracteres #. Falta transformar essa algaravia numa tabela.
Então, seleciona-se todo o documento, menos a linha do título geral, que não
fará parte da tabela. Depois, aplica-se o comando ConvertToTable na região se-
lecionada, indicando o separador (caractere # ) e o número de colunas (9). A úl-
tima linha da rotina
Selection.Cells.AutoFit

força o redimensionamento das colunas. Quando o Word constrói uma tabela,


inicialmente todas as colunas têm a mesma largura. Assim, em algumas delas so-
89
bra espaço e, em outras, as palavras ficam quebradas de forma irregular. O mé-
todo AutoFit tenta ajustar essa situação.
Missão cumprida. Execute a macro e imprima a tabela de conversores. Par-
te dela, com informações de minha máquina e do Word 2000, está mostrada na
Figura 9.1. Outras aplicações, usando dados dessa tabela, aparecerão no próxi-
mo capítulo.

F I G U R A 9 . 1 Visão parcial da tabela gerada pela rotina


Conversores de Arquivos

Atenção: o tipo de arquivo citado no título – XMW – resultou de pura in-


venção. Não sei se existe algum arquivo que use essa extensão esquisita. Eu ape-
nas quis sugerir que o Word pode ser capaz de lidar com arquivos diferentes dos
tradicionais DOC, TXT e RTF.
Conforme você pôde observar, este projeto não está amparado no suporte
visual de um formulário. Seu único ponto visível, antes de deflagrar a prepara-
ção da tabela de conversores, é o pedido de confirmação ao usuário:

F I G U R A 9 . 2 Mensagem antes de construir a tabela


90
Para ir mais além
1. Mesmo com o papel na orientação Paisagem e a ajuda do método Auto-
Fit, as colunas ficam mal distribuídas numa folha A4. Uma alternativa é
modificar as margens do papel. Isso deve ser feito logo no início da roti-
na, mais ou menos no mesmo lugar em que foi definida a orientação Pai-
sagem. Aliás, as margens também são propriedades de PageSetup. Com
margens menores, a tabela terá mais campo para se expandir, oferecen-
do mais espaço para cada coluna.
2. Observe as linhas de código a seguir, retiradas da parte final da sub Con-
versoresDeArquivos (os comentários foram eliminados):
Selection.HomeKey Unit:=wdStory, Extend:=True
Selection.MoveDown Unit:=wdLine, count:=2, Extend:=True
Selection.ConvertToTable Separator:="#", NumColumns:=9
Selection.Cells.AutoFit

O termo Selection não lhe parece muito repetitivo? Pois é, os caras que
fazem o Visual Basic também acharam isso. Então, eles criaram uma for-
ma de evitar essas repetições. Trata-se da instrução With/End With.
Com ela, você pode transformar o trecho de código acima em algo mui-
to mais econômico:
With Selection
.HomeKey Unit:=wdStory, Extend:=True
.MoveDown Unit:=wdLine, count:=2, Extend:=True
.ConvertToTable Separator:="#", NumColumns:=9
.Cells.AutoFit
End With

Legal, não? O nome do objeto fica em cima, junto com With, e seus mé-
todos ou propriedades são referidos, precedidos por um pontinho, no
espaço antes de End With.
3. O método ConvertToTable, mostrado acima, pode ser usado sem os
parâmetros Separator e NumColumns (separador e número de co-
lunas). Para isso, em lugar de usar o separador #, como fizemos neste
projeto, use o caractere Tab (constante vbTab). Desse modo, basta você
aplicar o método ConvertToTable, sem complementos. O Word des-
cobre sozinho qual o separador e qual o número de colunas. Há
exemplos disso em outros projetos deste livro, entre os quais os que es-
tão nos Capítulos 30 e 34.

91
Hora, minuto, segundo
Muitas vezes, no meio de um trabalho de programação, você se depara
com um valor de tempo decorrido em milhares de segundos. Que tal
apresentar esse número no formato hh:mm:ss? Aí está uma função que
faz isso. Basta passar o número e ela devolve uma string formatada.

Function FormataHoras(vHoraSeg As Variant) As String


‘ Recebe um valor em segundos e
‘ devolve-o no formato hh:mm:ss

Dim iHora As Integer


Dim sngHoraResto As Single
Dim iMinuto As Integer
Dim iSegundo As Integer
Dim sTmp As String

iHora = vHoraSeg \ 3600


sngHoraResto = vHoraSeg Mod 3600
iMinuto = (sngHoraResto) \ 60
iSegundo = sngHoraResto Mod 60

sTmp = Format$(iHora, “0#”) & “:”


sTmp = sTmp & Format$(iMinuto, “0#”) & “:”
sTmp = sTmp & Format$(iSegundo, “0#”)
FormataHoras = sTmp

End Function

Da base 60 para a base 10


A próxima macro faz o trabalho inverso da anterior. Recebe um número
no formato hh:mm:ss e devolve um número decimal.

Public Function Hora6010(strHora As Variant) As Single


On Error GoTo Hora6010_Err

Dim x As Integer ‘ variável auxiliar


Dim strHoraAux As String ‘ var. auxiliar
Dim Horas As Integer ‘ graus
Dim Mins As Integer ‘ minutos
Dim Segs As Integer ‘ segundos
Const Sep = “:” ‘ separador (hh:mm:ss)
(Continua)
92
(Continuação)
‘ Valor das horas em formato string
strHora = Format$(strHora, “hh:mm:ss”)
‘ Separa horas
x = InStr(strHora, Sep)
Horas = IIf(x > 0, Val(Left$(strHora, x - 1)), 0)
If Horas > 24 Then
MsgBox Str$(Horas) & “ - Valor incompatível com horas.”
Hora6010 = 0
Exit Function
End If

‘ Separa minutos
strHoraAux = Right$(strHora, Len(strHora) - x)
x = InStr(strHoraAux, Sep)
Mins = IIf(x > 0, Val(Left$(strHoraAux, x - 1)), 0)
If Mins > 60 Then
MsgBox Str$(Mins) & “ - Valor incompatível com minutos.”
Hora6010 = 0
Exit Function
End If

‘ Separa segundos
Segs = IIf(x > 0, Val(Right$(strHoraAux, Len(strHoraAux) - x)), 0)
If Segs > 60 Then
MsgBox Str$(Segs) & “ - Valor incompatível com segundos.”
Hora6010 = 0
Exit Function
End If

‘ Valor final da função


Hora6010 = Horas + (Mins / 60) + (Segs / 3600)

Hora6010_Fim:
Exit Function
Hora6010_Err:
MsgBox Err.Description
Resume Hora6010_Fim
End Function

93
10
Muito além do
velho e conhecido
DOC

Crie um conversor de arquivos do Word


para vários outros tipos de documentos

Ficha do projeto

Projeto:

Conversor de arquivos DOC

O que faz:

Converte arquivos de documentos do Word para uma série


de outros arquivos de texto: DOC do Word 6.0/95; DOC
do Word 2.0; TXT com quebra de linhas; RTF (Rich Text
Format); e documento HTML.

Usuários potenciais:

Este projeto é útil para qualquer usuário que trabalhe com


diferentes tipos de documentos de texto no dia-a-dia do
escritório. O conversor é especialmente útil para empresas
que operam com mais de uma versão do Word – por
exemplo, Word 97 ou 2000, e Word 6.0 ou 95. Outra
utilidade está na conversão em lote de arquivos DOC já
existentes em arquivos HTML para uma intranet ou um site
na Web.
Arquivos e requisitos do projeto:

Formulário frmConverteDOC e código interno.

Conhecimento técnico:

Manipulação básica de dois objetos do Word: a coleção FileConverters (conversores


de arquivos) e o objeto FileSearch (pesquisador de arquivos).

Nível de programação:

Intermediário

O Conversor de Arquivos DOC é um projeto relativamente simples. Contém


apenas um formulário, frmConverteDOC, cujos controles e rotinas associadas dão
conta de tudo que o programa se propõe a fazer. O objetivo do conversor é
transformar lotes de arquivos DOC em outros tipos de arquivos, a saber:

1. DOC do Word 2.0


2. DOC do Word 6.0/95
3. TXT com quebras de linhas
4. RTF (Rich Text Format)
5. HTML

O tipo de arquivo de partida será o da versão do Word com que você traba-
lha – ou seja, 97 ou 2000. No entanto, nada impede que você use o programa,
no Word 2000, por exemplo, com a finalidade de converter arquivos de outras
versões do Word – como a 2.0 – para HTML ou TXT.
O Conversor de Arquivos DOC repousa, tecnicamente, em dois recursos
do VBA, ambos associados a arquivos: a coleção FileConverters e o objeto File-
Search. A coleção FileConverters reúne todos os conversores de arquivos insta-
lados no Word, tanto os de leitura como os de escrita. Como você sabe, o Word
– ou outro aplicativo qualquer – precisa usar módulos de conversão, seja para
abrir e apresentar arquivos de outros programas, seja para salvar arquivos em
formatos externos. O conjunto de conversores disponíveis no Word varia de
máquina para máquina. Depende, em primeiro lugar, da versão do processador
de texto. Depende, ainda, do tipo de instalação que você fez, já que boa parte
dos conversores só é instalada por solicitação do usuário.
O objeto FileSearch, ao contrário, está disponível em qualquer instalação
do Word 97 ou do 2000. Com seus métodos e propriedades, ele facilita o traba-
lho de localizar, contar e classificar arquivos. A aplicação Conversor de Arqui-
vos DOC usa os recursos de FileSearch para encontrar os arquivos do Word, e
os FileConverters para transformá-los em documentos de outro padrão, confor-
me indicação do usuário. 95
Se você tem dois ou três documentos do Word e pretende convertê-los
para TXT ou HTML, então basta abrir o primeiro documento, salvá-lo no for-
mato desejado, fechá-lo e, depois, repetir a operação para os outros arquivos
DOC. Nesse caso, não é necessário ter ou desenvolver uma aplicação como o
Conversor de Arquivos. Agora, considere as seguintes situações:
1. Você tem centenas ou milhares de arquivos para converter; ou
2. Você converte apenas alguns arquivos, mas essa tarefa tende a fazer par-
te de seu dia-a-dia.
Aqui, o uso do conversor se justifica plenamente. De fato, esta aplicação
constitui um exemplo típico de automação de escritórios. Seu objetivo é deixar
a cargo do computador a execução de tarefas repetitivas. Na verdade, o progra-
ma faz a mesma coisa que você faria: abrir os arquivos e salvá-los em outro for-
mato. Mas é preciso ter paciência infinita para repetir essa seqüência de opera-
ções dezenas, centenas de vezes – sem errar. Mas, chega de conversa; vamos à
prática.

A lógica do conversor
O formulário frmConverteDOC, único módulo do conversor, contém os se-
guintes controles fundamentais:
n duas caixas de texto, txtPastaDOC e txtPastaFinal;
n dois botões de comando, cmdProcurarDOC e cmdProcurarFinal;
n uma moldura com cinco botões de opção; e
n botões Converter (cmdConverter) e Fechar (cmdFechar).

Para organizar a conversão dos documentos, entendemos que os arquivos


originais deveriam estar em diretórios diferentes dos arquivos convertidos.
Aliás, isso se torna obrigatório quando os grupos de documentos de origem e
destino são ambos do Word, em diferentes versões.
Na caixa de texto txtPastaDOC, o usuário deve indicar o diretório onde se
encontram os arquivos originais. Na outra caixa, txtPastaFinal, ele deve digitar
a pasta de destino. Os botões cmdProcurarDOC e cmdProcurarFinal oferecem
uma alternativa à digitação dessas duas pastas. Se o usuário clicar neles, vai po-
der navegar pela árvore de diretórios e indicar as duas pastas. O uso dos botões
Procurar, em lugar da digitação é sempre recomendado porque evita erros.
Cada um dos cinco botões de opção corresponde a um dos tipos de arqui-
vos de saída (TXT, RTF, HTML etc.). O padrão de saída é o documento do
Word 6.0/95, que tende a ser a alternativa mais usada. O botão Fechar, fazendo
jus ao nome, encerra a aplicação. E, por fim, o botão Converter dá início ao tra-
96 balho de conversão dos arquivos.
F I G U R A 1 0 . 1 A tela do Conversor: cinco formatos de destino

Quanto ao desenho do formulário, não há segredos. Passemos, então, ao


código. Comecemos pelos dois botões Procurar (cmdProcurarDOC e cmdPro-
curarFinal). O evento Click desses dois objetos tem a mesmíssima estrutura. Ele
chama a caixa de diálogo Cópia, captura o diretório escolhido pelo usuário nes-
sa caixa de diálogo e, por fim, escreve esse diretório na caixa de texto corres-
pondente. No código, essa tarefa é atribuída à função EscolherPasta.
Além de capturar uma string com a pasta indicada pelo usuário, essa fun-
ção executa ainda dois trabalhos secundários, mas fundamentais para evitar erro
no programa. O primeiro deles é a extração de aspas no início e no fim da string.
Quando trabalha com caminhos que contêm espaço entre palavras (exemplo:
“c:\meus documentos”), o Word acrescenta aspas no início e no fim da expres-
são. No entanto, se você tentar usar a informação com as aspas, provocará um
erro. Por isso, a função verifica se existem as aspas – o caractere Chr$(34) – e,
em caso positivo, elimina-as:

If Right$(strPasta, 1) = Chr$(34) Then


strPasta = Mid(strPasta, 2, Len(strPasta) - 2)
End If

A outra pequena tarefa realizada pela função EscolherPasta é eliminar a


barra invertida (\) que pode vir no final do nome de uma pasta, especialmente
no caso de um diretório-raiz, como c:\ ou d:\. Se você não tiver esse cuidado ao
lidar com diretórios, corre o risco de provocar um erro ao fazer concatenações
do tipo:

diretório & “\arquivo”

97
Como a variável diretório já contém a barra, isso resulta em:

diretório\\arquivo

Já vimos como indicar os diretórios. Passemos, agora, para a escolha do


tipo de arquivo final. Quando o usuário clica num dos cinco botões de opção
existentes, define o valor da variável intTipoDocFinal, válida em todas as roti-
nas do formulário. Se, por exemplo, ele escolhe a opção DOC Winword 6.0/95,
dispara o evento Click do botão correspondente:

Private Sub optDoc95_Click()


intTipoDocFinal = DOC_WORD6
End Sub

Inicialmente, a idéia era estabelecer constantes para os valores


DOC_Word6, DOC_WORD2, TXT e os demais. No entanto, para garantir a
compatibilidade do conversor com o Word 97 e o Word 2000, todos esses valo-
res passaram a ser variáveis (inteiros longos). Das cinco alternativas de conver-
são oferecidas pelo programa três têm constantes predefinidas no Word: texto
com quebra de linhas, RTF e HTML. Essas constantes são, respectivamente,
wdFormatTextLineBreaks, wdFormatRTF e wdFormatHTML (este último
apenas no Word 2000). Isso significa que os conversores desses formatos estão
embutidos no Word e são instalados com ele.
No entanto, quando se deseja exportar textos no formato do Word 2.0 ou
do Word 6.0/95, é preciso antes verificar se os conversores estão instalados. Isso
é feito mediante a propriedade CanSave do objeto FileConverters. Se CanSa-
ve=True, o Word pode salvar para um formato indicado. No Conversor de
Arquivos DOC, o teste da possibilidade de conversão é feito no evento User-
Form_Initialize. Para saber se é possível salvar no formato do Word 6.0, por
exemplo, o teste é o seguinte:
If FileConverters(“MSWord6Exp”).CanSave Then
DOC_Word6 = FileConverters(“MSWord6Exp”).SaveFormat
Else
DOC_Word6 = NÃO_EXISTE ‘Conversor não instalado
End If

A string “MSWord6Exp”, que identifica a classe do conversor de arquivos


(propriedade ClassName) para o formato Word 6.0/95, não aparece por mila-
gre. Ela resulta de uma consulta que foi mostrada no projeto anterior (verifi-
que). Essa consulta também revela que a string de identificação do conversor do
Word 2.0 é “MSWordWin2”. Quando o usuário opera com o processador de
texto em modo interativo, não precisa saber de nada disso. Mas o desenvolve-
dor, que vai revolver as entranhas do programa, tem de travar conhecimento
98 com objetos como os FileConverters e suas strings e constantes quase secretas.
Mas vamos em frente. O valor das variáveis DOC_Word6, DOC_Word2,
TXT e afins é definido durante a inicialização do formulário. Como o formato
de destino padrão é o documento do Word 6.0/95, também no evento de inicia-
lização provoca-se um clique na opção correspondente. Portanto, quando o
form se abre, o valor de intTipoDocFinal está associado ao formato de gravação
(propriedade SaveFormat) de arquivos Word 6.0.
Indicados os diretórios de origem e de destino e o tipo de documento final,
o usuário clica no botão Converter (frmConverter). A rotina Click desse botão
faz dois testes importantes. Primeiro, ela checa se as caixas de texto que indicam
os diretórios foram preenchidas. Basta que uma delas esteja vazia para que o
programa seja interrompido. O outro teste consiste em verificar se os dois dire-
tórios indicados de fato existem. Esse passo seria desnecessário se o usuário
sempre indicasse os diretórios, mediante o clique nos botões Procurar. Mas,
como ele também pode digitar, a porta está aberta para o erro. Portanto, se, pelo
menos, um dos diretórios não existir, é preciso – mais uma vez – interromper o
programa. Quem diz se o diretório é verdadeiro ou falso é a função PastaExiste:

Private Function PastaExiste(strPasta As String) As Boolean


’ Testa se o diretório strPasta existe
On Error GoTo PastaExiste_Err

Dim strDirAtual As String


strDirAtual = CurDir$
ChDir strPasta
PastaExiste = True
ChDir strDirAtual

PastaExiste_Fim:
Exit Function
PastaExiste_Err:
PastaExiste = False
Resume PastaExiste_Fim
End Function

A função PastaExiste recebe o nome de uma pasta e responde se essa pasta


existe ou não. Inicialmente, ela guarda o diretório corrente (CurDir$) na variá-
vel dirAtual. Em seguida, tenta passar para o diretório em teste, com a instrução
ChDir. Se tudo correr bem, então a pasta existe e passa a ser o novo diretório
atual. Como é apenas um teste, usa-se outra vez a instrução ChDir para voltar ao
antigo diretório corrente. Se o diretório não existe, ocorre um erro, que é trata-
do na rotina PastaExiste_Err. Lá, a função é declarada falsa.
A função PastaExiste apresenta um interessante algoritmo de programa-
ção. No entanto, você pode substituí-la por outra rotina, PastaExiste2, também
incluída no projeto. PastaExiste vale para qualquer versão do Visual Basic. Pas-
taExiste2 usa recursos mais novos introduzidos pelo VBA: 99
PastaExiste2 = True
strTemp = Dir$(strPasta, vbDirectory)
If Len(strTemp) = 0 Then
PastaExiste2 = False
End If

PastaExiste2 parte da hipótese de que o diretório existe. Depois, usa a fun-


ção Dir$, com a constante vbDirectory, para fazer a verificação. Se Dir$ retorna
uma string vazia, então o diretório não existe e a função é falsa. Se você quiser,
pode resumir ainda mais essa rotina, deixando-a com apenas uma linha:

PastaExiste2 = Dir$(strPasta, vbDirectory) < >“”

Aqui, você indica que a função é igual a Dir$(), que é diferente de uma
string vazia. Se Dir$ confirmar isso, a função será verdadeira. Se, no entanto,
Dir$ for igual a uma string vazia, então PastaExiste2 é falsa. Se você não se sentir
à vontade com essas duas igualdades – no caso, uma igualdade e uma desigualda-
de – encadeadas, teste as duas opções de PastaExiste2 isoladamente e conclua.
Observe: quando se usou a variável strTemp para armazenar o valor da
função Dir$, a verificação foi feita checando se o comprimento dessa string era
zero. No outro caso, o teste procura saber se a string é vazia. Os dois processos
se equivalem. No entanto, segundo os teóricos, o teste do comprimento zero é
mais rápido.
Agora, a reta final. Se os diretórios existem, a rotina cmdConverter_Click
chama o procedimento ConverteDOC que, de fato, cuida da conversão dos ar-
quivos. Entra em ação o objeto FileSearch. Sua propriedade LookIn é ajustada
para procurar no diretório de origem. Já a propriedade FileName é ajustada
para a string “*.doc”, a fim de localizar todos os arquivos do Word no diretório.
Se nenhum arquivo for encontrado, encerra-se o procedimento. Caso contrário,
o programa entra num loop For/Next para determinar, em cada passo, o nome
de um arquivo. Este é aberto, salvo na pasta de destino com o mesmo nome
(muda apenas a extensão, se necessário) e, depois, fechado. O loop continua, até
o último arquivo.
O presente projeto é interessante para você conhecer os procedimentos
usados pelo Word na conversão de um tipo de arquivo em outro. No entanto, se
você usa o Word 2000, essa versão do programa já traz um aplicativo chamado
Assistente de Conversão em Lote, que permite converter arquivos do Word
para vários outros formatos, e vice-versa. Para abrir esse assistente, acione
Arquivo/Novo e, na janela Novo, dê um duplo clique na opção Assistente de
Conversão em Lote. O programa vai guiar você, passo a passo, na conversão dos
arquivos desejados. Além da interface, organizada na forma de assistente, uma
das vantagens dessa aplicação sobre nosso conversor é que ele opera em duas di-
reções: de, e para arquivos DOC do Word 2000.
100
F I G U R A 1 0 . 2 Assistente de Conversão: de DOC (Word 2000)
para outros formatos, e vice-versa

Para ir mais além


1. Além dos cinco tipos de conversões previstos no Conversor de Arquivos
DOC, você pode incluir outros, ampliando a abrangência do programa.
Para isso, use as informações discutidas no capítulo anterior.
2. Modifique o Conversor de arquivos DOC para que ele apresente ao
usuário uma caixa de listagem com os arquivos do Word, existentes no
diretório de origem. Assim, em lugar de converter todos os arquivos
existentes nesse diretório, o programa converteria apenas aqueles esco-
lhidos pelo usuário.
3. Outra ampliação possível é permitir que o programa aceite outros forma-
tos de arquivo na entrada do processo, e não somente na saída. Uma su-
gestão para a escolha do formato de entrada seria agregar ao formulário
outra moldura, com botões de opções. Outra seria adotar a solução em-
pregada pelo Assistente de Conversão do Word 2000 – caixas de combi-
nação para os formatos de entrada e de saída. Lembre-se de interromper
o fluxo do programa se o formato de entrada for igual ao de saída.
4. Durante a conversão, você vai ver o Word abrindo, salvando e fechando
cada arquivo encontrado no diretório de origem. Se você achar mais
conveniente fazer essa operação de forma mais discreta, retire as aspas
de comentário das seguintes linhas, que vêm antes e imediatamente de-
pois do trecho de código que representa o loop de conversão:
‘Application.WindowState = wdWindowStateMinimize
‘Application.WindowState = wdWindowStateMaximize
101
A primeira linha minimiza a tela do Word. Assim, a operação ocorre de
forma semi-oculta. Terminada a conversão, a outra linha retorna o pro-
grama ao modo de tela cheia.
5. Observe a declaração da função EscolherPasta. Na lista dos parâmetros
que deve receber, ela traz um elemento novo: um parâmetro opcional:
Private Function EscolherPasta(Optional strDir As String = “c:\”) As String

O que é isso? Quando um parâmetro é declarado como Optional, isso


significa que ele não precisa ser incluído na chamada da função. No caso
acima, a chamada pode ser feita de duas maneiras. Exemplo 1:

txtPastaDoc = EscolherPasta()

Nesse caso, a caixa de diálogo é exibida mostrando o diretório “c:\”, in-


dicado como padrão. Ou seja, se a chamada não inclui um diretório, a
caixa de diálogo mostra a pasta c:\. A outra alternativa força a exibição
da pasta desejada:

txtPastaDoc = EscolherPasta(“c:\meus documentos”)

Janela imediata
Admita que você quer usar a janela Imediata (ou Verificação Imediata)
para testar a função PastaExiste, que faz parte do projeto Conversor de
Arquivos DOC. Então você digita na janela Imediata:

? PastaExiste(“c:\meus documentos”)

O Word avisa que aquela função não existe. Como? Ela está ali
mesmo, à sua frente! Calma: acontece que PastaExiste é declarada
como uma função do tipo Private – quer dizer, só atua no âmbito do for-
mulário a que pertence. Portanto, ela não pode ser vista “de fora”. A
saída é “passar para dentro”, localizando a função no objeto que a
contém, o formulário. Assim:

? frmConverteDOC.PastaExiste(“c:\meus documentos”)

Agora a função responde:

Verdadeiro

Esse procedimento vale tanto para os módulos de formulários –


caso de frmConverteDoc – quanto para os módulos de puro código.
102
Formato HTML
Se você precisa criar aplicações compatíveis com mais de uma versão
do Word – por extensão, mais de uma versão do VBA –, cuidado com os
detalhes. Um exemplo: tanto o Word 97 como o 2000 convertem arqui-
vos para o formato HTML. Só que, quando a versão mais nova foi lan-
çada, o padrão HTML (leia-se Internet) já se tornara muito mais impor-
tante. Por isso, nos conversores de arquivos, o formato HTML já tem
uma constante intrínseca: wdFormatHTML (que é igual a 8). Só que
essa constante só existe no Word 2000. Portanto, não pode ser usada
se você quer que sua aplicação também rode na versão anterior. No lu-
gar de wdFormatHTML, use 8.

103
11
Na tabuada
do 1

Crie documentos com numeração seqüencial


automática

Ficha do projeto
Projeto:
Memorando Numerado Simples e Memorando Numerado
Interno
O que faz:
Abre um modelo de documento e numera-o, conforme uma
seqüência controlada. O projeto Memorando Numerado Interno
é idêntico ao primeiro. A única diferença é que incorpora a
lógica de numeração no próprio modelo de documento.
Arquivos e requisitos do projeto:
Para o Memorando Numerado Simples:
– Módulo modMemoNumerado e rotinas internas.
– Modelo Memonum0.dot
Para o Memorando Numerado Interno:
– Modelo Memonum1.dot e código interno.

Conhecimento técnico:
Criação e leitura de arquivos INI. Controle do documento
de dentro ou de fora do modelo que o contém.

Nível de programação:

Iniciante
Em numerosas atividades do dia-a-dia dos escritórios, sempre se necessita gerar
documentos com numeração seqüencial. São memorandos, cartas, ofícios, rela-
tórios e outros documentos que precisam ser marcados com números do tipo
001/00, 002/00, 003/00, e assim por diante.
Você certamente gostaria de ter uma ferramenta em seu Word que garan-
tisse a seqüência dos números sem que você precisasse anotá-los para controle.
Não é difícil desenvolver essa ferramenta. Para simplificar, vamos trabalhar com
a idéia do memorando. Lógico, o que se disser aqui em relação ao memorando
valerá também para carta, ofício, relatório, recibo ou qualquer outro documen-
to que requeira numeração seqüencial.
Raciocinemos. O que é necessário? Primeiro, um modelo – o documen-
to-padrão para seus memorandos. Esse modelo deve ter um espaço para o nú-
mero do documento. Mas como saber qual foi o número do último memorando
emitido, a fim de dar ao próximo o número seqüencial correto?
Aqui entra um pequeno macete. Há várias formas de fazer isso, mas todas
passam por guardar o número num registro permanente. E o melhor lugar, no
caso, é um arquivo no disco. No Word, a forma mais fácil de guardar um número
é usar um arquivo INI. Com essa idéia, esbocemos as vigas mestras do projeto:
1. Temos um modelo de memorando, ao qual deve ser anexado, automati-
camente, o número do documento.
2. Cada número utilizado será armazenado num arquivo INI. Isso implica
que, no memorando seguinte, esse número deverá ser lido, acrescenta-
do de uma unidade e estampado no novo documento. E outra vez arma-
zenado etc. etc. Isso lembra a escola primária antiga, quando a criançada
recitava em coro a “tabuada do 2”: “2 vezes 1, dois; 2 vezes 2, quatro”...
Passemos ao código. O primeiro passo é criar um novo módulo, ao qual
chamaremos de modMemoNumerado. Esse módulo conterá todas as rotinas
necessárias ao projeto. No módulo, vamos trabalhar com a rotina principal, que
receberá o nome de Sub MemoNumerado Simples. Observe o detalhe: precisa-
remos, mais tarde, executar essa rotina de fora desse módulo. Por isso, essa sub
deve ser marcada como um procedimento público. Assim sendo, deve ser decla-
rada da seguinte forma:

Public Sub MemoNumeradoSimples()

Sigamos, passo a passo, as ações desse procedimento. Em primeiro lugar,


ele define o diretório onde será gravado o documento final. Define, também, o
arquivo que contém o modelo de memorando, e o arquivo INI que armazena o
último número seqüencial utilizado.
sDocSubDir = “c:\solucoes\memos”
sArqModelo = “c:\solucoes\memonum0.dot”
sArqIni = “c:\solucoes\dados\memo.ini”
105
Em seguida, a rotina lê o ano atual no relógio do sistema. Esse valor deverá
compor parte da data na numeração do documento.

sAnoAtual = CStr(Year(Now))

Segue-se um teste de existência do arquivo INI, usando a função Arquivo-


Existe, outra rotina do módulo modMemoNumerado. ArquivoExiste simples-
mente responde se Memo.ini existe ou não. Em caso negativo – que pode cor-
responder, por exemplo, à primeira vez que a rotina é executada –, recorre-se à
sub ZeraContagem, que cria Memo.ini, e anota ali o primeiro número de docu-
mento: 0. Na primeira consulta ao arquivo, o número se tornará 0 + 1. Veja o
código completo de ZeraContagem:

Private Sub ZeraContagem(strAno As String, strIni As String)


‘ Grava o ano atual, zera a contagem
System.PrivateProfileString(strIni, “Contador”, “Ano”) = strAno
System.PrivateProfileString(strIni, “Contador”, “MemoNum”) = “0"
End Sub

ZeraContagem recebe, como string, o ano lido no relógio do PC e o cami-


nho completo do arquivo INI. Com esses elementos, usa a propriedade Priva-
teProfileString, do objeto System, para criar o arquivo Memo.ini e inserir nele
uma seção chamada Contador, a qual tem duas entradas: Ano e MemoNum.
Memo.ini, um arquivo texto, fica inicialmente com o seguinte conteúdo:

[Contador]
Ano=2000
MemoNum=0

Continuemos. E o que acontece se o arquivo INI existe? Nesse caso, a roti-


na recorre, ela mesma, à propriedade PrivateProfileString, desta vez para ler o
valor armazenado. Lido o valor, entra em ação outro teste. Se o ano lido no re-
lógio do micro for maior que o registrado no arquivo INI, então iniciou-se um
ano novo desde a última vez que a rotina foi utilizada. Se temos um ano novo,
então é necessário recorrer outra vez aos serviços de ZeraContagem: o número
do memorando volta a zero e o ano é atualizado no arquivo. E se o ano do reló-
gio for menor que o já registrado no INI? Nesse caso, ou o relógio do PC andou
para trás ou o arquivo INI foi adulterado. Então, a rotina avisa ao usuário que
aconteceu algo estranho – e pára.
Passados os testes, a rotina segue em frente. Agora, ela já tem todos os da-
dos e pode abrir um documento novo, baseado no modelo do memorando:

Documents.Add Template:=sArqModelo

106
No lugar em que deverá entrar o número seqüencial, o modelo traz a ex-
pressão NúmeroDoDocumento, que deverá ser substituída pelo valor adequa-
do. A rotina lê o valor no arquivo INI, soma 1 e compõe o texto que, no fim, re-
sulta em algo como:

Memorando 036/00

Agora, usa-se o objeto Selection.Find para encontrar, no documento, a ex-


pressão NúmeroDoDocumento e substituí-la por “Memorando 036/00”.
Então, monta-se um nome para o arquivo, também baseado no número do do-
cumento. O nome do arquivo será:

mm036-00.doc

Naturalmente, como o Word suporta nomes longos desde a versão 95,


você não precisa forçar a mão para manter o nome do arquivo com apenas oito
caracteres. Antes de salvar o arquivo, outro teste: por acaso já existe algum ar-
quivo com esse nome? Em caso negativo, salva-se o arquivo, e o memorando,
pré-numerado, já está pronto para receber o texto. No entanto, se o arquivo
existe, a operação de salvamento é cancelada.
Trata-se de um procedimento de segurança. Sem ele, você correria o risco
de sobregravar um documento existente (e já expedido) com outro, novo. Esse
erro só seria possível se alguém modificasse, manualmente, o número registrado
no arquivo INI. De todo modo, o programa não permite a perda de documen-
tos. Tanto que, nesse caso, o arquivo não é salvo e o número a ele atribuído tam-
bém não vai para o registro no arquivo INI.
Para evitar que alguém – ou você mesmo – modifique o arquivo INI, o ideal
é guardá-lo num diretório de pouco trânsito, como a pasta de modelos do
Word. Fuja do diretório do Windows ou de Meus Documentos. Aqui, para
manter juntos todos os dados referentes a projetos do livro, ele é armazenado
em c:\solucoes\dados.
O módulo modMemoNumerado pode residir em seu modelo Normal.dot
ou em outro arquivo DOT qualquer. Para executar a rotina MemoNumerado-
Simples, é necessário chamá-la a partir da janela de macros (Ferramentas/Ma-
cro/Macros/Executar), ou então instalar numa barra de ferramenta um botão
que a dispare.

Memorando numerado interno


Este projeto é absolutamente idêntico ao anterior: abre um documento baseado
num modelo específico e numera-o. Armazena o número num arquivo INI para
leitura posterior, durante a emissão do próximo documento. O único ponto
destoante entre os dois projetos é a sua estrutura.
107
F I G U R A 1 1 . 1 O memorado, pré-numerado, pronto para
receber um texto final

O projeto Memorando Numerado Simples envolve dois itens: o modelo


Memonum0.dot, que contém a matriz para os documentos, e o módulo mod-
MemoNumerado. Este último, contido em outro modelo – que pode ser o Nor-
mal ou outro qualquer –, engloba toda a lógica do programa. Memonum0.dot
serve apenas de suporte para o design do documento. Portanto, você pode criar
novo modelo com esse nome, reservando nele um lugar para a palavra-chave
(NúmeroDoDocumento) que será localizada e substituída pelo número do do-
cumento.
Este projeto, Memorando Numerado Interno, contém o mesmo código
de programação e a mesma lógica de numeração dos documentos. Tem tam-
bém um modelo, Memonum1.dot. A diferença fundamental é que o código –
uma cópia do módulo modMemoNumerado –, está embutido no próprio mo-
delo. Em outras palavras, a “cara” do documento e o esquema de automação
residem no próprio documento. Aí, em vez de estar num módulo, o programa
fica no próprio módulo ThisDocument, existente em qualquer documento ou
modelo. Agora você deve ter percebido o porquê da palavra “interno” no
nome do projeto.
As diferenças de funcionamento determinadas por essas duas abordagens –
a lógica dentro ou fora do modelo – estão mostradas na tabela a seguir.

108
MEMO NUMERADO MEMO NUMERADO
ITEM SIMPLES INTERNO

Papel do modelo Serve apenas de suporte ao Fornece o formato do


formato básico do documento. documento e também a
A lógica de automação está lógica de automação.
fora.

Reação do modelo diante Abre um documento baseado Abre um documento


de um duplo clique no em Memonum0.dot, mas não baseado em
Windows Explorer ocorre a numeração Memonum1.dot e executa
automática. a numeração automática.

Percepção do usuário, Idêntica Idêntica


se a solução for disparada
a partir de um botão na
barra de ferramentas

Espaço ocupado em disco Apenas o tamanho normal do O tamanho normal do


pelo documento final documento documento mais o
tamanho do código
embutido

Como você pode ver pelo quadro acima, há vantagens e prejuízos em


reunir toda a solução dentro de um modelo ou deixá-la em compartimentos
separados – documento de um lado e código do outro. A principal vantagem
da separação está mostrada na última linha do quadro acima: o modelo que
contém apenas o documento ocupa menos espaço em disco. Se, por exemplo,
o código embutido acrescenta 10 KB em cada documento, ao final de cem
memorandos (ou cartas, ofícios etc.) você já terá perdido cerca de 1 MB de
espaço. Em contrapartida, reunir tudo num mesmo arquivo é mais prático e
interessante.
Para evitar o desperdício, tenha em conta este pequeno truque. Sempre
que possível, use a lógica embutida no modelo. Mas, se for necessário gerar um
documento genérico – não baseado no modelo –, aplique essa mesma lógica so-
bre um documento derivado do modelo normal. Isso pode ser resolvido pelo se-
guinte trecho de código:

Dim strModelo As String


strModelo = NormalTemplate
Documents.Add Template:=strTemplate

Se você tentar incluir o valor NormalTemplate diretamente na linha Docu-


ments..., não vai funcionar. Na sintaxe do método Add, para Documents, o va-
lor esperado deve ser do tipo string, o que está garantido pela declaração da va-
riável strModelo. Agora, observe: obviamente, este truque não se aplica ao caso
do modelo Memonum1.dot. Serve, no entanto, para casos em que o programa 109
faz uma pesquisa e gera um documento a partir de uma página totalmente em
branco – o que não é o caso de nossos memorandos.
Outra conclusão que se pode extrair dessa discussão é a seguinte. Se o do-
cumento vai ser produzido em escala, considere a possibilidade de separar mo-
delo e programa. No extremo oposto, se a aplicação não gera documento, mas
apenas executa um cálculo ou consulta informações, coloque-a toda dentro de
um modelo. Naturalmente, essa conclusão não deve ser encarada como um dog-
ma religioso – é apenas um princípio, bem genérico, para orientar sua decisão.
Daqui partimos para outro ponto, igualmente importante. Quando o pro-
grama e o modelo são separados, onde deve ser armazenado o programa?
Se o programa está no modelo Normal, ou em qualquer outro modelo glo-
bal, ele se torna disponível no Word em todos os momentos. Esse aspecto é o
lado positivo. Em compensação, se você armazena todas as aplicações – módu-
los e formulários – no modelo Normal.dot, transformará seu Word numa imen-
sa carroça. Porque ele estará sempre carregando na memória o peso extra des-
ses objetos.
Como regra geral, você pode adotar alguns critérios. Dê preferência a co-
locar no Normal.dot os pequenos programas de uso muito freqüente. Aplica-
ções muito grandes ou de uso esporádico podem residir em modelos próprios.
Elas só serão trazidas para a memória quando estiverem em uso.

Para ir mais além


1. Se, por acaso, você decidir utilizar esta solução para numerar documen-
tos e está começando no meio do ano, com – digamos – 45 documentos
já emitidos, rode o programa uma vez e coloque 45 como o número re-
gistrado em Memo.ini.
2. Em lugar de usar um arquivo INI, poderíamos ter registrado as informa-
ções no Registro do Windows. Contudo, achamos desaconselhável. Pri-
meiro, porque experimentações com o Registro podem resultar em de-
sastre. Depois, até por causa da necessidade de facilitar a manipulação
expressa no item 1, acima.
3. Nos capítulos seguintes, você verá como aumentar o nível de automa-
ção no preenchimento de documentos. Observe que, neste capítulo, por
exemplo, as macros poderiam envolver o nome do remetente e do desti-
natário do memorando.
4. Se quiser, você pode modificar o programa para que o documento seja
numerado com um ano de quatro dígitos. Em lugar de “Memorando
036/00”, você pode querer “Memorando 036/2000”.
5. O arquivo Memonum0.dot foi criado sob a inspiração de um modelo de
memorandos que acompanha o Word. No original, o campo Data era
110 preenchido automaticamente, graças a um campo de data no formato
“25 de fevereiro de 2000”. Esse campo, no entanto, apresentava um
problema. Auto-atualizável, ele sempre exibia a data em que você abris-
se o documento. Assim, o memorando não guardava a data de sua emis-
são. Para corrigir isso, apagamos o campo e forçamos a inserção da data
no lugar dele, via código. Para isso, na construção do modelo, marca-
mos a posição onde estava o campo com um indicador (Inserir/Indica-
dor) chamado DataDoDocumento. O trecho de código que garante a
inserção da data é o seguinte:

strData = Day(Now) & “ de ” & _


Format$(Now, “mmmm”) & “ de ” & Year(Now)
Selection.GoTo What:=wdGoToBookmark, _
Name:="DataDoDocumento"
Selection.TypeText strData

O código localiza o indicador (bookmark) com o método Selection.


GoTo e, com o cursor posicionado nele, insere a data, contida na variá-
vel strData.
6. No código embutido em Memonum1.dot há duas linhas comentadas.
São elas:

’ Documents.Add Template:=sArqModelo
’ ActiveWindow.View.Type = wdPageView

A primeira abre um novo documento baseado no modelo (Memo-


num1.dot). A outra exibe a janela do Word no formato Layout de Pági-
na. Elas são linhas válidas no projeto Memorando Numerado Simples.
No entanto, geram erro se forem deixadas ativas no presente projeto.
Por quê?
7. Observe um detalhe: todos os procedimentos embutidos em Memo-
num1.dot são do tipo Private. A razão é simples: eles são disparados
quando se abre um novo documento baseado no modelo. Nesse mo-
mento, o procedimento New_Document, entra em ação, chamando a
sub MemoNumeradoInterno. Tudo ocorre dentro do próprio docu-
mento. Não há, portanto, necessidade de algum objeto ficar acessível
para fora do módulo.

111
Versões diferentes, claras ou ocultas
Se você desenvolver para um público que vai usar seu produto em pla-
taformas diferentes, tome cuidado com as “pegadinhas” impostas pe-
los ambientes de programação. Isso vale para as diferentes versões do
Word. No VBA do Word 2000, para obter a data atual no formato “25
de setembro de 2000”, você pode usar:

strData = Format (Now, “d \de mmmm \de yyyy”)

Se você colocar as partículas “de”sem as barras que as precedem,


obtém algo assim:

25 25e setembro 25e 2000

Isso ocorre porque o interpretador entende a primeira letra do


“de” como um sinal de dia, na data. A barra invertida modifica o valor
da letra. Ou seja, a letra, ali, tem o valor de letra, mesmo. Descobri por
acaso, tentando assimilar o Format aos padrões das expressões regula-
res, já existentes no VBScript. Deu certo – e gostei. Esse foi o lado bom.
Só depois é que percebi a má notícia: isso só funciona no VBA do Office
2000. No 97, o caminho tem de ser outro, um pouco menos simpático:

strData = Day (Now) & “ de ” & _


Format$(Now, “mmmm”) & “ de ” & Year(Now)

Portanto, cuidado com esses detalhes. Aliás, às vezes nem é ne-


cessário haver duas versões diferentes do programa. Dois Words da
mesma versão, com uma DLL mais recente numa das máquinas, po-
dem produzir informações díspares. Se você desenvolveu uma aplica-
ção no Word 2000, não se arrisque a pôr a mão no fogo jurando que
ela funciona no Word 97.

Atualização de modelos
A partir de qualquer documento baseado num modelo, você pode abrir
o código embutido nesse modelo. Aí, o que for atualizado no documen-
to, também o será no modelo. Isso vale apenas para o VBA: formulários
e módulos de programação. Para atualizar o texto ou o layout do docu-
mento (texto, tabelas etc.) contido no modelo, é necessário abrir o pró-
prio modelo – ou seja, o arquivo DOT.

112
12
De um em um,
para vários
documentos

Crie documentos com numeração


seqüencial automática

Ficha do projeto
Projeto:

Numera automaticamente e controla a emissão de


diferentes documentos: memorandos, cartas, ofícios,
relatórios etc.

O que faz:

Abre um modelo de documento e numera-o, conforme


uma seqüência controlada.

Arquivos e requisitos do projeto:

Formulário frmDocsNumerados e rotinas internas.


Arquivos DOT com os modelos de cada documento.
Arquivo Docs.ini.

Conhecimento técnico:

Criação e leitura de arquivos INI

Nível de programação:

Iniciante
Este capítulo constitui um prolongamento lógico dos dois anteriores. Naqueles,
você viu como programar uma aplicação que numera automaticamente um tipo
de documento: memorando, carta, ofício, requerimento etc. Neste, vamos dar
um passo à frente, expandindo a solução, para que ela controle, ao mesmo tem-
po, diferentes tipos de documentos.
Para que o usuário diga à aplicação com qual documento deseja trabalhar,
é necessário oferecer a ele um painel de escolha. Portanto, ao contrário da solu-
ção anterior, precisamos criar um formulário (frmDocsNumerados) com as op-
ções de documentos. No exemplo deste projeto, usamos cinco tipos de docu-
mentos: memorandos, carta tipo 1, carta tipo 2, ofício e relatório. Essencial-
mente, portanto, o formulário (frmDocsNumerados) contém uma moldura com
cinco botões de opção (OptionButton1 a OptionButton5) e dois botões de co-
mando: cmdOK e cmdCancelar.
Para operar o aplicativo, o usuário escolhe um tipo de documento e aciona
o botão OK. A ação básica deste projeto é executada pela rotina associada a esse
botão. A primeira tarefa da rotina cmdOK_Click consiste em determinar qual
foi o botão de opção escolhido pelo usuário:

For i = 1 To 5
If Controls(“OptionButton” & i).Value = True Then
n = i
Exit For
End If
Next i

F I G U R A 1 2 . 1 O formulário frmDocsNumerados

Conforme o índice do botão escolhido (1 a 5), define-se qual modelo de


documento deverá ser usado. Naturalmente, para cada opção existente no pro-
grama você precisa ter um modelo. A caracterização do tipo de documento que
será usado no processamento posterior é feita mediante a instrução Select Case:
114
Select Case n
Case 1 ‘ memorando
strDocDir = “c:\solucoes\memos\”
strArqModelo = “c:\solucoes\memonum1.dot”
strChave = “MemoNum”
strTipoDoc = “Memorando ”
strArqPrefixo = “mm”
Case 2
(...)

Para cada valor de n, atribuem-se diferentes valores a cinco variáveis:

1. strDocDir – Diretório onde serão gravados os documentos do tipo n. Se


você quiser organizar bem os documentos, uma boa idéia é criar um
subdiretório para cada tipo de documento.
2. strArqModelo – Caminho completo do arquivo com o modelo do tipo
de documento.
3. strChave – Nome da chave que controla a numeração do documento no
arquivo INI. Como há, no exemplo, cinco tipos de documentos, deve
haver igual número de chaves no arquivo INI.
4. strTipoDoc – Expressão que indica o tipo de documento: “Memoran-
do”, “carta” etc.
5. strArqPrefixo – Prefixo associado ao tipo de documento que servirá para
identificar os arquivos. Para memorandos, “mm”; para cartas, “cr”,
“ct”; para ofícios, “of”.
Concluídas essas definições, o restante do processamento é similar ao já
visto nos dois projetos anteriores. A principal diferença está em dois
pontos. Primeiro, a necessidade de criar um modelo para cada tipo de
documento desejado. Depois, essa multiplicidade de documentos se re-
flete também no arquivo Docs.ini, que tem o seguinte perfil:
[Contador]
Ano=2000
MemoNum=0
Carta1Num=0
Carta2Num=0
OficNum=0
RelatNum=0

Na virada do ano, o programa recorre à rotina ZeraContagem, que


atualiza o ano e zera os números de todos os documentos.

115
Para ir mais além
1. No exemplo mostrado neste projeto, todos os documentos usam o mes-
mo modelo. Além disso, todos os arquivos são armazenados no mesmo
diretório. Para transformar este aplicativo num projeto utilizável, você
precisa criar os modelos e ajustar a eles as opções do formulário.
2. Com pequenas adaptações, você pode ajustar o projeto para controlar
menos – ou mais – de cinco opções de documentos. Basta mexer no for-
mulário e incluir (ou subtrair) um ou mais Cases na instrução Select
Case.

Diretório mutante
O VBA/Word é, sem dúvida, uma ferramenta excelente para a automa-
ção de escritórios. Isso não significa que seja um produto isento de im-
perfeições. Aqui está uma delas. A propriedade DefaultFilePath, do ob-
jeto Options, dá acesso a uma série de definições do Word. Exemplo:

Options.DefaultFilePath(wdDocumentsPath)

A linha acima fornece o diretório-padrão no qual o Word guarda


os documentos. Mas cuidado: não confie na informação fornecida por
essa propriedade – ela é mutante. Ao contrário do diretório mostrado
em Ferramentas/Opções/Arquivos, que é fixo, esse diretório é, na ver-
dade, o diretório corrente, que pode ser obtido por vários outros cami-
nhos. Um deles é a função CurDir, do Visual Basic. Outro é dado pela
propriedade DefautFilePath, com o parâmetro wdCurrentFolderPath:

Options.DefaultFilePath(wdCurrentFolderPath)

Cabe, então, a pergunta: se wdCurrentFolderPath fornece o dire-


tório corrente, por que wdDocumentsPath não retorna o valor, firme,
do diretório-padrão para gravar documentos? O resultado desse com-
portamento inconsistente é que, via Options, não há como obter esse
diretório de forma confiável. Em minha opinião, wdDocumentsPath de-
veria informar um diretório fixo – aquele mostrado na caixa de diálogo
Opções – e wdCurrentFolderPath forneceria o diretório corrente, como
já faz hoje. Fique atento.

116
13
Palavras que
valem dinheiro

Duas soluções para escrever, automaticamente,


valores monetários por extenso

Ficha do projeto
Projeto:
Macro EscreveExtenso e aplicativo Valor por Extenso.
O que faz:
A macro EscreveExtenso converte números em valores por
extenso, em reais. Valor por Extenso presta o mesmo
serviço, mas abre uma caixa de diálogo na qual o usuário
pode escolher a apresentação do extenso em outras
moedas, além do real.
Arquivos e requisitos do projeto:
Biblioteca Extens32.dll, que fornece os números por
extenso.
Procedimento EscreveExtenso.
Formulário frmExtenso.

Conhecimento técnico:

Movimentação do cursor num documento Word e


manipulação de strings.

Nível de programação:
Intermediário
No dia-a-dia dos escritórios comerciais, se existe uma tarefa maçante é escrever
valores monetários por extenso. Além de exigir atenção do operador, impõe-lhe
a digitação de longas fileiras de palavras para descrever os números. É exata-
mente por causa dessa trabalheira que qualquer mecanismo para escrever valo-
res por extenso constitui um recurso bem-vindo para quem os enfrenta no coti-
diano.
O projeto deste capítulo apresenta duas soluções para esse problema. A
primeira é uma macro específica para o Word, enquanto a outra, com a altera-
ção de apenas uma linha de código, pode ser usada em qualquer outro programa
que suporte a linguagem VBA.

A macro EscreveExtenso
A macro EscreveExtenso foi o primeiro programa de algum interesse que escre-
vi no VBA/Word, logo após o lançamento do Office 97. Na verdade, ela consis-
tia na “tradução” de outra macro, criada ainda nos tempos do Word 6.0. O que
faz esse código?
O acesso à macro é feito através de um botão de comando instalado numa
barra de ferramentas. Para o usuário, as coisas funcionam da seguinte maneira.
Ele vai redigindo o documento e, num dado instante, surge a necessidade de es-
crever um valor por extenso. Então, ele digita o valor, por exemplo, R$ 1.389,67
– e clica no botão de comando. A macro responde, transformando o trecho do
texto em algo assim:

R$ 1.389,67 (um mil, trezentos e oitenta e nove reais e sessenta e sete centavos)

O usuário, agradecido, continua a redação. O projeto de EscreveExtenso


envolve duas partes: um procedimento escrito em VBA, no ambiente do
Word, e uma biblioteca externa, o arquivo Extens32.dll, que é na verdade
quem faz o trabalho pesado de converter números em palavras. A idéia do pro-
jeto e a macro em VBA são minhas, mas a DLL foi elaborada pelo analista de
sistemas Antonio Augusto Ferreira, exímio desbravador das obscuridades da
linguagem C++.
Vamos, agora, conhecer o funcionamento interno da macro. Como
EscreveExtenso vai usar os serviços da biblioteca Extens32.dll, o primeiro
passo consiste em declarar a função extenso, residente nessa DLL. Essa de-
claração deve ser feita num módulo (não pode ser num formulário), da se-
guinte maneira:

Public Declare Function Extenso Lib “Extens32.dll” _


Alias “extenso” (ByVal Valor As String, _
ByVal Retorno As String) As Integer

118
Essencialmente, a macro executa três operações:
n ler o número;
n enviá-lo à DLL, que devolve o valor por extenso; e
n escrever esse valor no documento.

A parte mais interessante – e específica do Word – é a primeira. Quando a


macro é chamada pelo usuário, o cursor está à direita do número que ele acabou
de digitar. Para reconhecer o número, ela desloca o cursor da direita para a es-
querda até encontrar o primeiro caractere. Nesse momento, liga o modo de se-
leção (ExtendMode) e continua o deslocamento para a esquerda, agora em bus-
ca de um espaço vazio. Esse espaço é o sinal de que o número começa ali. Como
o número está selecionado, armazena-se o seu valor numa variável e o cursor é
devolvido para o lado direito do número.
O espaço vazio, como se pode perceber, é fundamental. Se ele não existir,
o cursor seguirá em marcha à ré, indefinidamente. O usuário precisa observar
essa regra. Todo esse trabalho para capturar o número é feito no seguinte trecho
do código:

Selection.MoveLeft Unit:=wdCharacter, count:=1, _


Extend:=wdExtend
While Selection.Text = “ ”
If (Selection.Type = wdSelectionIP) And _
(Selection.Start = 0) Then Exit Sub
Selection.ExtendMode = False
Selection.MoveLeft Unit:=wdCharacter, count:=1, _
Extend:=wdMove
Wend

Selection.MoveRight Unit:=wdCharacter, count:=1, _


Extend:=wdMove
Selection.ExtendMode = True
With Selection.Find
.Forward = False
.Wrap = wdFindStop
.Execute FindText:=" “
End With

strValor = Selection.Text
Selection.ExtendMode = False
Selection.MoveRight Unit:=wdCharacter, count:=1, _
Extend:=wdMove

119
Daí para a frente, os procedimentos são mais simples. O valor strValor é
enviado à função Extenso, na DLL, e esta devolve as palavras correspondentes,
por meio da variável strRetorno (o método é meio tortuoso, mas tem de ser as-
sim, porque funções da API do Windows não retornam texto de forma direta).

strRetorno = String$(512, 32) ‘512 espaços


x = extenso(strValor, strRetorno)
strTmp = “ (” & Trim$(strRetorno) & “)”

O valor direto fornecido pela função é um número inteiro que indica o to-
tal de caracteres das palavras do extenso. Como strRetorno, por padrão, tem
512 caracteres, basta pegar os x primeiros – o resto está em branco. No trecho
acima, essa tarefa de eliminação de espaços vazios é feita pela função Trim$. Por
fim, a terceira parte: as palavras são colocadas entre parênteses e inseridas no
texto pelo método Selection.TypeText.
Toda essa trabalheira é necessária porque não há uma forma rápida de
identificar o número no texto. Isso não ocorreria, por exemplo, no Excel, por-
que os valores estão contidos em células, que são locais bem determinados. É
por isso que o código da macro tem um jeito de poucos amigos. Mas, se conside-
rarmos apenas a parte do extenso, a coisa é simples e rápida. Eis aqui uma fun-
ção de extenso que faz o mesmo papel, sem a localização do número:

Function ValorExtenso (strValor As String) As String


Dim strRetorno As String
Dim x As Integer, strTmp As String

strRetorno = String$(512, 32) ‘512 espaços


x = Extenso(strValor, strRetorno)
strTmp = Trim$(strRetorno)
If x > 0 And strTmp <> “ real” Then
ValorExtenso = strTmp
End If
End Function

Toda a função está aí. E dessa forma pode ser usada no Excel, no Access,
no PowerPoint etc. E até mesmo no Word – desde que se adote outra forma de
capturar o número.
Outra forma de resolver a questão seria com uma caixa de diálogo (for-
mulário). Em lugar de escrever o número no texto, o usuário o escreveria nessa
caixa e acionaria OK. O formulário faria a comunicação com a DLL e se encar-
regaria de “digitar”, no texto, o valor retornado. O projeto Valor por Extenso
baseia-se exatamente nessa segunda possibilidade.

120
O aplicativo Valor por Extenso
Valor por Extenso amplia as possibilidades de EscreveExtenso. O projeto se
propõe a escrever extenso e, além disso, permitir que o usuário escolha uma mo-
eda – além do real.
Valor por Extenso tem um único formulário, frmExtenso, com os seguin-
tes controles: uma caixa de texto para a digitação do número (txtValor), os clás-
sicos botões OK e Cancelar, e uma moldura, Moeda, com quatro botões de op-
ção (opt1 a opt4). Estes últimos correspondem às moedas: real, dólar, franco e
iene. Neste projeto, o número por extenso fornecido pela DLL (em reais) é mo-
dificado para ajustar-se à moeda escolhida.

F I G U R A 1 3 . 1 O formulário: moedas diferentes

Para identificar a moeda escolhida, o programa conta com a ajuda da variá-


vel m_intMoeda, com validade geral no formulário. No evento de inicialização,
o valor dessa variável é definido como 1, correspondente ao padrão, que é real.
No evento Click de cada botão de opção, m_intMoeda assume novo valor: 2
para dólar, 3 para franco e 4 para iene.
A ação começa quando o usuário clica no botão OK. Se a caixa txtValor es-
tiver preenchida, o programa segue em frente. Uma instrução Select Case distri-
bui o trabalho conforme a moeda escolhida:

Select Case m_intMoeda


Case 1 ‘ real
s = “R$ ”
strTmp = ExtensoMoedas(strValor, “real”, “reais”)
Case 2 ‘ dólar
s = “US$ ”
strTmp = ExtensoMoedas(strValor, “dólar”, “dólares”)
Case 3 ‘ franco
s = “F ”
strTmp = ExtensoMoedas(strValor, “franco”, “francos”)
Case 4 ‘ iene
s = “¥ ”
121
strTmp = ExtensoMoedas(strValor, “iene”, “ienes”)
End Select

Selection.TypeText s & strValor & “ (” & strTmp & “)”

Quem entra em cena, agora, é a função ExtensoMoedas, que recebe o va-


lor e os nomes da moeda no singular e no plural. O que faz essa rotina? Ela cha-
ma outra função, ValorExtenso, já mostrada acima, para obter a string forneci-
da pela DLL. Essa string em ExtensoMoedas, é chamada de ValorComReal, que
só serve se a moeda é o real. Para qualquer outra, a string tem de ser modificada.
A estratégia para fazer a alteração é a seguinte. Com a função InStr, desco-
bre-se na string onde está a palavra “real” ou “reais”. A partir dessa posição e do
comprimento dessas duas palavras, divide-se a string em duas partes, uma antes
e outra depois da denominação da moeda. Por fim, recompõem-se as partes, co-
locando no meio o nome da nova moeda:

ExtensoMoedas = sLeft & sMoeda & sRight

No Word 2000, essa rotina seria bem mais simples e menos trabalhosa,
graças a uma nova função, Replace, compatível com o Visual Basic 6.0 (o VBA
97 é compatível com o VB 5.0). Com Replace, basta mandar trocar uma palavra
pela outra:
ExtensoMoedas = Replace (ValorComReal, “reais”, “dólares”)

Entretanto, no projeto, você vai encontrar a forma mais complicada, para


garantir a compatibilidade com o Word 97.
Voltando ao código. Depois de receber o valor de ExtensoMoedas, a roti-
na ligada ao clique no botão OK coloca-a entre parênteses, antecede-a com o
símbolo da moeda e insere no texto:
Nesse caso, portanto, o usuário só precisa escrever “a quantia de”, chamar
a caixa de diálogo, digitar o valor e escolher a moeda (se for o caso).
Tarefa cumprida.

Para ir mais além


1. A macro EscreveExtenso lida com o objeto Selection um dos mais re-
correntes na programação em Word. Analise direitinho como foi fei-
ta a captura do número. É importante entender o uso do modo de se-
leção.
2. Embora estenda as possibilidades da macro EscreveExtenso, o projeto
Valor por Extenso também tem seus problemas. Um deles é que algumas
moedas são “femininas”, como a libra e a lira. Nesses casos, a string que
vem da DLL não vai fazer a concordância de gênero, como em “uma
122
lira”, “duas libras”, “trezentas rúpias”. Outra limitação é que todos os
valores divisionários são centavos.
3. Agora, um limite da própria DLL. A biblioteca foi construída para tra-
balhar com números no formato usado no Brasil: 12.345,67. Ou seja, o
separador de milhares é o ponto e o separador de decimais, a vírgula.
4. Faça uma experiência: antes de clicar no botão OK, acione Tab para fazer
o foco sair da caixa de texto txtValor. Isso lhe mostrará o verdadeiro nú-
mero enviado à DLL. Verdadeiro porque o aplicativo, antes de enviar o
número, ajusta-o para o padrão brasileiro de escrever valores monetários.
5. Mesmo com esses limites em mente, você pode ampliar o programa, in-
cluindo novas moedas. Basta aumentar o número de botões de opção e
fazer os ajustes correspondentes.

Nome do documento no rodapé


Esta macro é bastante útil: escreve o nome do documento e o número
da página no canto direito do rodapé, em letra pequena, corpo 9.

Sub InsereNomeNoRodape()
With ActiveWindow
.View.Type = wdPageView
.ActivePane.View.SeekView = wdSeekCurrentPageFooter
With Selection
.Font.Size = 9
.Fields.Add Range:=Selection.Range, _
Type:=wdFieldEmpty, Text:= _
“FILENAME ” & “ - Pág. ” & “PAGE ”, _
PreserveFormatting:=True
.TypeText Text:=" - Pág. “
.Fields.Add Range:=Selection.Range, _
Type:=wdFieldEmpty, Text:= _
“PAGE ”, PreserveFormatting:=True
.ParagraphFormat.Alignment = wdAlignParagraphRight
End With
.ActivePane.View.SeekView = wdSeekMainDocument
End With
End Sub

Se você preferir o cabeçalho em vez de rodapé, troque a constan-


te wdSeekCurrentPageFooter por wdSeekCurrentPageHeader. Você
também pode mudar o tamanho da letra, alinhar o parágrafo à es-
querda, definir um nome de fonte. Esteja à vontade.
123
14
Documentos
à la carte

Torne, realmente, automática a emissão


de memorandos e outros papéis

Ficha do projeto

Projeto:

Memorando Numerado 2

O que faz:

Esta aplicação automatiza a emissão de memorandos.


Preenche todo o cabeçalho, numera e salva o documento.

Arquivos e requisitos do projeto:

Memonum2.dot, modelo que contém a base do


memorando.
Formulário frmMemorandos e código interno.

Conhecimento técnico:

Programação com indicadores (bookmarks) e o objeto


Selection.Find. Escrita e recuperação de informações em
arquivos INI.

Nível de programação:

Iniciante
Em dois capítulos anteriores, mostramos como automatizar o controle de docu-
mentos numerados. Naquelas soluções, no entanto, o único item de automação
estava na numeração do documento. Agora, vamos dar um passo à frente, inclu-
indo outras variáveis no processo de preenchimento automático. Para facilitar a
comparação, vamos usar como modelo o mesmo documento básico, um memo-
rando. Além do número, esse documento tem cinco campos cujo preenchimen-
to pode ser automatizado:

Nome do destinatário
Nome do remetente
Assunto do memorando
Data
Outros destinatários (pessoas a quem será enviada uma cópia
do memorando)

Para ajustar o modelo do documento a essa nova situação, vamos transfor-


mar todos esses campos, que antes estavam destinados à digitação direta, em pa-
lavras-chave que devem ser substituídas pelas variáveis correspondentes. Assim,
em lugar dos campos, teremos quatro palavras-chave: NomeDoDestinatário,
NomeDoRemetente, AssuntoDoMemorando e ListaDeOutrosDestinatários.
No campo Data, em vez de usar a técnica de substituição, vamos trabalhar com
um indicador — ou seja, um marcador de posição invisível, inserido no texto.
Na hora do preenchimento, basta deslocar o cursor para essa posição e lá in-
cluir, via código, a data corrente. Na elaboração do documento, o indicador,
chamado DataDoDocumento, é inserido mediante o comando Inserir/Indica-
dor. O modelo modificado de memorando deve ser salvo com o nome de Me-
monum2.dot.
Quando se analisa o “funcionamento” desse memorando, percebe-se que
essas cinco variáveis apresentam natureza distinta. A data pode ser fornecida
pelo sistema. O assunto do memorando deve ser digitado em cada caso. Deve
haver um espaço fixo para armazenar o nome do remetente, porque este certa-
mente não mudará a cada documento. Ao mesmo tempo, é preciso oferecer ao
usuário a oportunidade de organizar uma lista de nomes, na qual ele possa esco-
lher o destinatário principal e os destinatários secundários do documento. Tudo
indica que precisamos de um formulário para abrigar esses itens. O operador
fará todas as definições nesse formulário e, em seguida, dará um comando para
que a aplicação se encarregue de preencher os cinco campos automatizáveis. Ao
usuário restará, apenas, escrever o corpo do memorando.

Construção do formulário
Vamos criar um formulário chamado frmMemorandos. Esse objeto terá os se-
guintes controles principais:
125
n um controle multipage (Multipage1) com duas orelhas (Page1 e Page2);
n dois botões de comando, OK (cmdOK) e Cancelar (cmdCancelar);
n rótulos Próximo Memo (labMemoNúmero) e PróximoArquivo (lab-
Arquivo).

F I G U R A 1 4 . 1 O formulário, destacando a orelha Destinatários


(Page1)

As duas orelhas de Multipage1 também incorporam objetos. Em Page1


(rótulo: Destinatários), existem os seguintes controles:
n caixa de combinação Para (cboPara), com a lista para a escolha do desti-
natário principal;
n labTotalNomes, sem rótulo, para indicar o total de nomes disponíveis
na caixa Para;
n caixa de listagem Com Cópia Para (lstComCópia), para abrigar a lista
dos demais destinatários;
n caixa de texto Assunto (txtAssunto).
Em Page2 (rótulo: Configuração), encontram-se os seguintes controles:
n caixa de texto Remetente (txtRemetente);
n botão de comando Salvar (cmdSalvarNome);
n botões de comando Editar Lista (cmdEditarLista) e Atualizar Lista
126
(cmdAtualizarLista);
F I G U R A 1 4 . 2 Os objetos da orelha Configuração (Page2)

n rótulo labExplica;
n rótulos labListaMemo, labMemoIni; labModelo; e labDirDocs.

Os controles não citados – como algumas molduras e rótulos – desempe-


nham papel neutro no projeto, e figuram apenas como elementos de indicação
ou de realce visual. Assim como nos projetos anteriores, neste também vamos
precisar de um arquivo INI (Memo.ini) para armazenar o contador de números
dos documentos e alguns itens de configuração. O conteúdo total de Memo.ini
será algo como o seguinte:

[Contador]
Ano=2000
MemoNum=32
Remetente=Arthur Rimbaud

Precisaremos, também, de um arquivo texto, Listamemo.txt, no qual ficará


guardada a lista dos destinatários. Esse arquivo poderia fazer parte de um banco
de dados. No entanto, normalmente, a lista de pessoas a quem se envia memo-
randos não passa de umas poucas dezenas de nomes. Por isso, um arquivo texto
resolve bem a questão, com muito menos trabalho.

O código
Passemos ao código. A primeira tarefa, ao inicializar o formulário, será ler o ar-
quivo Listamemo.txt e transportar para a caixa de combinação cboPara todos os
nomes de destinatários cadastrados. Para essa tarefa é convocada a rotina Preen- 127
cheCombo. Esta, depois de incluir os nomes na lista de cboPara, exibe o total
deles na etiqueta labTotalNomes.
Outra tarefa executada durante a inicialização do formulário é ler o arqui-
vo Memo.ini e, com base nas informações registradas nele, definir o número do
próximo memorando a ser emitido e o nome do arquivo que o conterá. Se, por
exemplo, o número no arquivo INI é 32, o número do memorando será 032/00
– fórmula: número/ano – e o arquivo assumirá o nome mm032-00.doc.

F I G U R A 1 4 . 3 O formulário, logo após a inicialização

Outra informação lida no arquivo INI deve ser o nome do remetente, que é
transferido para a caixa de texto txtRemetente, na orelha Configuração (Page2).
Após a inicialização, nenhuma informação é exibida nas caixas Para e Com
Cópia Para e somente a primeira delas contém uma lista de nomes. A pessoa que
emite o memorando deve escolher o destinatário na lista da caixa Para. Ao fazer
isso, ele provoca a execução da rotina cboPara_Click, que copia a lista de cboPa-
ra para cboComCopia. Todos os itens são copiados, menos um – aquele que foi
selecionado como destinatário principal. Isso evita que uma mesma pessoa seja
incluída como receptor primário e secundário de um memorando. A exclusão
do nome já escolhido em cboPara é garantida pelo seguinte trecho de código:

intX = cboPara.ListIndex ‘ Pega o num. do item selecionado


lstComCopia.Clear
For i = 0 To cboPara.ListCount - 1
‘Copia todos os itens, menos o selecionado em cboPara
If i <> intX Then lstComCopia.AddItem cboPara.List(i)
Next i
Primeiro, pega-se o índice do item selecionado (intX), que corresponde ao
128 valor da propriedade ListIndex de cboPara. Em seguida, percorre-se com um
loop todos os itens de cboPara, copiando-os para lstComCopia. Exclui-se ape-
nas aquele cujo índice seja igual ao do valor escolhido em cboPara.
A operação fundamental da aplicação ocorre a partir do momento em que
o usuário clica no botão OK. Em primeiro lugar, a rotina cmdOK_Click chama
a função TestaPreenchimento para saber se todos os itens fundamentais foram
preenchidos: destinatário, assunto e remetente. A escolha de itens na caixa de
listagem lstComCopia é opcional. Vale observar que esta última tem a proprie-
dade MultiSelect ajustada para fmMultiSelectMulti (=1). Essa definição permi-
te que cada clique num item o selecione automaticamente. Em sentido inverso,
um clique num item já escolhido o “desseleciona”.
Se todos os preenchimentos estão corretos, passa-se à outra fase. Oculta-se
o formulário e cria-se um documento novo, baseado no modelo Memo-
num2.dot. Chegamos ao momento de preencher os campos automatizáveis do
memorando. Primeiro, vamos posicionar o cursor no indicador DataDoDocu-
mento e, lá, inserir a data:

strData = Day(Now) & “ de ” & _


Format$(Now, “mmmm”) & “ de ” & Year(Now)
Selection.GoTo What:=wdGoToBookmark, Name:="DataDoDocumento"
Selection.TypeText strData

Depois, é preciso determinar se o usuário escolheu um ou mais nomes


como destinatários de cópias do memorando. A propriedade Selected do objeto
lstComCopia indica quais itens estão selecionados. Portanto, com um loop que
percorre todos os itens, fica fácil acumular uma string com todos os nomes sele-
cionados, separando-os com ponto-e-vírgula.
A próxima etapa consiste em definir MatrizTexto, uma matriz de duas di-
mensões – uma para o valor da variável indicado pelo usuário e a outra para a
palavra-chave que deve ser substituída no documento. Feito isso, usa-se nosso já
conhecido objeto Selection.Find para executar a operação de busca e substitui-
ção. As tarefas finais são salvar o arquivo com um nome já definido desde a aber-
tura do formulário e armazenar, no arquivo INI, o número usado no documento
atual.
Além da operação básica, este projeto envolve outros aspectos que estão
todos na orelha Configuração. Quando o usuário clica no botão Salvar Nome,
dispara uma rotina que salva no arquivo INI o nome digitado na caixa de texto
txtRemetente. O botão cmdEditarLista abre o Bloco de Notas (Notepad.exe) e
carrega o arquivo Listamemo.txt, que contém, na lista de destinatários, um
nome em cada linha. O usuário pode incluir, apagar ou editar nomes.
Para que as mudanças introduzidas na lista tenham efeito imediato no
aplicativo, é necessário que ele, após a edição, clique no botão Atualizar Lista.
Este invoca, outra vez, a rotina PreencheCombo que limpa a caixa de combi-
nação e a caixa de lista com os nomes de destinatários, e renova o conteúdo da
primeira. 129
F I G U R A 1 4 . 4 A lista de destinatários

Na área de declarações do formulário, são definidos como constantes do


tipo String os valores dos arquivos e diretórios envolvidos no programa:

sDIR_LISTAMEMO Diretório do arquivo Listamemo.txt, que


contém o cadastro de destinatários.

sDIR_MEMOINI Diretório do arquivo Memo.ini, que


armazena as configurações do programa.

sDIR_SALVAMEMO Diretório-padrão em que os novos


memorandos devem ser salvos.

sDIR_MODELO Diretório onde fica o modelo que serve de


base para os memorandos (no exemplo,
Memonum2.dot).

Para que o programa funcione corretamente com outros diretórios, modi-


fique essas constantes. Os valores definidos por elas estão mostrados no painel
Arquivos e Diretórios da orelha Configuração.

Para ir mais além


1. Torne o gerador de memorandos mais amigável para o usuário, armaze-
nando, no arquivo INI, os diretórios que estão definidos como constan-
tes. Para isso, é preciso eliminar as definições de constante e ler as infor-
mações no INI como variáveis. Isso exigirá uma contrapartida: deverá
130
haver um lugar para o usuário indicar novos diretórios. Você pode, por
F I G U R A 1 4 . 5 O resultado final: resta apenas escrever o texto
principal do documento

exemplo, criar uma terceira orelha no objeto Multipage apenas para a


configuração de Arquivos e Diretórios. Outra opção é incluir pequenos
botões ao lado dos rótulos que exibem os arquivos e diretórios. Esses
botões abririam uma caixa de diálogo para o usuário escolher, em cada
caso, o novo diretório.
2. O gerador de memorandos não permite que você envie memorandos
com cópia para um número muito grande de destinatários. Isso porque
ele usa a técnica de acumular os nomes numa string e depois inserir essa
string no documento. Você pode contornar essa limitação inserindo os
nomes um a um no documento. Experimente.

Caixa sempre aberta


Uma desvantagem das caixas de combinação é que exigem, pelo me-
nos, dois cliques para a escolha de uma opção: o primeiro abre a lista,
e o outro seleciona uma alternativa. Se você achar adequado, pode
economizar um clique para o usuário, fazendo o seguinte. Na rotina
correspondente ao evento em que o controle recebe o foco (Enter),
aplique o método DropDown. Exemplo, para uma caixa chamada
cboTratamento:

Private Sub cboTratamento_Enter()


cboTratamento.DropDown
End Sub
131
15
Para não repetir
o repetido

Ensine o Word a contar e marcar palavras


já usadas dentro de um documento

Ficha do projeto
Projeto:

Contador de Expressões

O que faz:

Conta o número de vezes que uma palavra ou expressão


aparece num texto do Word. Opcionalmente, marca as
expressões encontradas.

Usuários potenciais:

Escritores, revisores e qualquer pessoa preocupada com o


excesso de repetições de palavras ou expressões.

Arquivos e requisitos do projeto:

Formulário frmContaExpressao e código interno.

Conhecimento técnico:

Operações com o objeto de busca do Word (Selection.Find)


do VBA, além da manipulação de arquivos texto.

Nível de programação:

Intermediário
Se você quisesse saber quantas vezes aparece uma determinada palavra ou ex-
pressão num texto do Word 97 ou do 2000, qual comando usaria? Antes que
você perca tempo vasculhando menus e barras de ferramentas, aí vai a resposta:
nenhum. Não existe no Word um recurso para contar palavras dessa forma.
Mas, com uma pequena ajuda de nosso amigo VBA, podemos adicionar esse co-
mando ao processador de texto. É disso que trata o projeto atual.
Pensemos um pouco. Precisamos de um dispositivo que percorra um docu-
mento de alto a baixo e, durante essa varredura, identifique uma palavra, ou se-
qüência de palavras, e conte quantas vezes ela aparece. No final, esse recurso
deve informar: a expressão foi encontrada X vezes.
Por onde começar? A opção Editar/Localizar (ou Selection.Find, no VBA)
desenvolve uma tarefa bem próxima. Você fornece uma palavra, ela varre o tex-
to e seleciona a primeira ocorrência. Com o comando Localizar Próxima, nova
ocorrência é selecionada – e assim por diante, até o final do documento. Pode-
mos partir dessa característica já existente e modificá-la para atingir nosso pro-
pósito. Observe que o comando Localizar, ao encontrar uma palavra, pára. Pre-
cisamos que ele siga em frente e, além disso, conte o número de ocorrências en-
contradas. Com essas idéias em mente, armemos a estrutura de nossa solução.
É preciso oferecer ao usuário uma caixa de diálogo na qual ele indique qual
palavra deve ser procurada. Vamos usar um formulário (frmContaExpressao)
que contém, basicamente: uma caixa de texto, para a digitação da expressão a
ser buscada e contada; um botão de comando, Contar (cmdContar), que dispara
a ação; e outro, Cancelar (cmdCancelar), que encerra o aplicativo.
Com os elementos acima, podemos montar a interface de um programa
para contar o número de vezes que uma palavra ou expressão aparece num tex-
to. Mas que tal incluir outras funções nesse aplicativo? Com um pouco mais de
esforço, ele poderá executar também as seguintes tarefas adicionais:
n Localizar somente palavras ou expressões inteiras. Ou seja, quando a ex-
pressão desejada é “para”, só vale a palavra correspondente. Expressões
como “paralelas” e “comparar” não serão contadas.
n Coincidir maiúscula e minúscula – Nesse caso, a busca leva em conta o
tipo de letra. Se o argumento é “lua”, “Lua” (com L maiúsculo) não será
considerada.
n Marcar palavra encontrada – Com essa opção, a expressão encontrada
será destacada com um pincel marcador, em todas as suas ocorrências.
n Desmarcar palavra encontrada – Operação inversa da anterior.
Estas duas últimas opções são úteis para quem escreve ou revisa textos.
Ao reler um documento que acabou de escrever, a pessoa nota que repetiu
muitas vezes uma determinada palavra. Então, usa a opção Marcar. Assim, a
expressão fica destacada no texto, dando-lhe a oportunidade de empregar si-
nônimos ou mudar a estrutura de alguns trechos para eliminar as repetições,
principalmente as muito próximas. No final, a palavra permanece destacada 133
em alguns lugares. Usa-se a outra opção, Desmarcar Palavra Encontrada, para
desfazer os destaques.
No processo de revisão, é possível que o usuário busque mais de uma vez a
mesma expressão. Isso traz à mente uma idéia: manter uma espécie de histórico
das expressões procuradas anteriormente. Dessa forma, ele pode reaproveitar
palavras já digitadas.
Com essas novas características, o formulário que apenas esboçamos mais
acima precisa ser revisado. Em lugar de uma caixa de texto para receber a pala-
vra procurada, vamos usar uma caixa de combinação (cboExpressão). Essa cai-
xa, além da função de receber o texto digitado, armazenará a lista das últimas
palavras procuradas. Haverá também quatro caixas de verificação para as op-
ções de busca: Encontrar Palavra Inteira (chkPalavraInteira); Coincidir Maiús-
cula/Minúscula (chkCoincidirLetra); Marcar Palavra Encontrada (chkMarcar);
e Desmarcar Palavra Encontrada (chkDesmarcar). Por último, há o botão Lim-
par Histórico, que elimina a lista de palavras procuradas anteriormente exibidas
na caixa cboExpressão.
Portanto, nosso aplicativo vai encontrar e contar palavras, localizá-las, se-
gundo critérios de busca, e manter um histórico das últimas expressões procura-
das. Para isso, o formulário de suporte terá o aspecto exibido na Figura 15.1.

F I G U R A 1 5 . 1 Contador de expressões: com busca e histórico

O desenho do formulário, em si, não apresenta nenhuma dificuldade. Pas-


semos ao código. O fundamental de todo o funcionamento do aplicativo vai
acontecer quando o usuário clicar no botão Contar. Vamos pensar, portanto, na
rotina associada ao acionamento desse botão.

O mecanismo de busca e contagem


A rotina de localização e contagem de expressões pode ser delineada nos seguin-
tes passos:
134
1. Para começar, uma providência administrativa. Se o usuário clicar no
botão Contar sem ter digitado nada na caixa de texto, usa-se um Exit
Sub para encerrar, aí mesmo, a execução do código. O comando Locali-
zar só é capaz de operar usando, como argumento de busca, uma variá-
vel do tipo String – que aceita, no máximo, 255 caracteres. Então, apro-
veitamos a mesma seqüência de Ifs para verificar essa limitação e avisar
o usuário. Detalhe sutil: esse bloco é também um recurso disfarçado de
tratar erros, já que evita a procura de um valor vazio ou de tamanho su-
perior ao limite máximo.
2. Para garantir que a contagem varrerá o texto completamente, vamos
mover o cursor para o início do documento:
Selection.MoveStart Unit:=wdStory

3. Iniciemos o processo de busca, definindo alguns parâmetros importantes:


Selection.Find.Text = sExpressão
Selection.Find.Forward = True

Essas linhas indicam que: a) o texto a ser procurado é sExpressão, string


que corresponde ao que foi digitado na caixa combinação do formulá-
rio; e b) o processo deve ser feito do início para o fim do documento.
4. Por enquanto, ainda não começamos a operação de busca. Ela só é ativa-
da, de fato, depois do comando
Selection.Find.Execute

Como já vimos, o comando Localizar apenas encontra a expressão pro-


curada e pára. Portanto, a linha de código acima põe em ação o mecanis-
mo de busca uma única vez. Mas será que ele encontrou alguma coisa?
Se encontrou, a propriedade Found (encontrado), do objeto Selecti-
on.Find é verdadeira. O trecho completo fica sendo o seguinte:
Selection.Find.Execute
While Selection.Find.Found = True
n = n + 1
Selection.Find.Execute
Wend

5. A primeira linha, já vimos, executa a primeira busca. Em seguida, vem


um loop do tipo While/Wend. Se uma palavra foi encontrada, o fluxo do
programa entra no loop e soma 1 ao valor de n, um número inteiro, an-
tes zerado. A busca é executada mais uma vez. De novo, pela ação do
loop, testa-se se a expressão foi encontrada e acumula-se mais 1 no con-
tador n. O processo se repete até o final do documento.

135
6. Agora, uma caixa de mensagem apresenta o resultado do trabalho com
uma frase do tipo: “A expressão ‘pôr-do-sol’ foi encontrada 5 vezes.”
Com esses seis passos, descrevemos o funcionamento do mecanismo de
busca e contagem de palavras usado no projeto. Mas – você deve ter notado –
não falamos nas opções de busca. Como fica a localização das expressões se o
usuário escolher uma ou mais dessas opções?
Voltemos ao código. As alternativas Encontrar Palavra Inteira e Coin-
cidir Maiúscula/ Minúscula estão previstas no objeto Find, respectivamente,
com as propriedades MatchWholeWord e MatchCase. Como as duas assumem
valores booleanos (True/False), basta transferir para elas, na hora da busca, o va-
lor da caixa de verificação correspondente no formulário:

With Selection.Find
.MatchCase = chkCoincidirLetra.Value
.MatchWholeWord = chkPalavraInteira.Value

Falta, agora, a questão marcar/desmarcar palavra encontrada. Ela se resol-


ve no loop While/Wend, já citado acima. Veja como:

While Selection.Find.Found = True


If chkMarcar = True Then
Selection.Range.HighlightColorIndex = wdBrightGreen
ElseIf chkDesmarcar = True Then
Selection.Range.HighlightColorIndex = wdWhite
End If
n = n + 1
Selection.Find.Execute
Wend

Sempre que uma palavra é encontrada, verifica-se o valor da caixa chkMar-


car. Se é verdadeiro, aplica-se à expressão (que está selecionada) a cor ver-
de-claro, correspondente à constante intrínseca do Word wdBrightGreen. Se, ao
contrário, o usuário escolheu a caixa Desmarcar, aplica-se à seleção a cor branca
(wdWhite). Se nem uma caixa nem a outra estão ativadas, a rotina faz apenas a lo-
calização e a contagem das expressões repetidas. Para que as opções Marcar/Des-
marcar não firam a lógica, as rotinas chkMarcar_AfterUpdate e chkDesmar-
car_AfterUpdate garantem que se uma estiver ativa, a outra não deve estar.

Histórico de busca
Até aqui, resolvemos tudo o que se refere à localização, opções de busca e conta-
gem. Resta-nos, ainda pendente, o histórico de palavras procuradas. Para man-
ter os argumentos de busca entre um e outro acionamento do Contador de
136 Expressões, temos de armazenar em algum lugar esses argumentos.
A forma mais simples de fazer isso é recorrer a um arquivo texto. Cada bus-
ca acrescenta nova palavra à lista existente na caixa cboExpressão. Quando o
aplicativo se fecha, o conteúdo dessa lista deve ser transferido para o arquivo. E
cada vez que o programa for aberto, a lista do arquivo deve ser copiada para
cboExpressão.
Vamos ao código. A acumulação da última palavra na caixa de combinação
é automática, desde que a caixa tenha como propriedade Style o valor
fmStyleDropDownCombo (=0), que é o padrão. Então, uma parte do problema
se resolve sozinha. A outra, armazenar a lista num arquivo, deve ser executada
no fechamento do formulário.
Escolhemos o evento UserForm_QueryClose e, nele, fazemos a seguinte
operação. Decidimos que o histórico de palavras procuradas não deveria ter
mais que vinte expressões. Trata-se de um número razoável, acima do qual não
faz muito sentido armazenar palavras. Por causa disso, verificamos quantos
itens existem na lista de cboExpressão. Se mais de vinte, trabalhamos somente
com os vinte primeiros, que são gravados, cada um, como uma linha de um ar-
quivo texto.
Esse arquivo se chama Historia.plv e é gravado no diretório de modelos do
Word – que varia conforme a versão do programa. Poderíamos tê-lo chamado
Historia.txt, mas achamos que a estranha extensão PLV (de palavra) e o diretó-
rio de modelos deixam o histórico mais a salvo de apagamentos involuntários.
Um detalhe: a cada fechamento, o arquivo é apagado e recriado com o novo
conteúdo da caixa de combinação.
Portanto, fechado o formulário, as informações da caixa de combinação
cboExpressão ficam armazenadas no arquivo Historia.plv. Agora, vejamos o
que acontece quando se abre o formulário. A primeira ação da rotina User-
Form_Initialize é verificar se o arquivo de histórico existe. Em caso positivo, ele
é lido, linha a linha, para a caixa cboExpressão. Caso contrário, a caixa fica va-
zia: não existe histórico, o qual será criado no próximo fechamento do formulá-
rio, se o usuário tiver realizado alguma busca.
O botão Limpar Histórico, simplesmente, emprega o método Clear para
limpar a caixa cboExpressão:

cboExpressão.Clear

Com a caixa vazia, a rotina de fechamento do form elimina o arquivo exis-


tente, e não tem o que salvar. Assim, na próxima abertura do formulário, a caixa
cboExpressão continuará vazia.
Fim de projeto.

Para ir mais além


1. O Contador de Expressões centra sua atividade na busca de termos.
Você pode ampliá-lo, incluindo a opção de substituir a expressão en- 137
contrada por outra. Isso exigirá algum esforço de design, a fim de exibir
o espaço para a nova expressão quando o usuário escolher Substituir.
Uma fonte de inspiração pode ser a própria caixa de diálogo Locali-
zar/Substituir do Word.
2. Se achar conveniente, substitua o número máximo de expressões arma-
zenadas no histórico (20). Basta trocar, na rotina UserForm_QueryClo-
se, o valor da constante cnsMAX_PAL.

Objetos azul-piscina
Ao criar formulários com muitos campos de texto, você pode adicionar
um efeito visual para dar ao usuário uma indicação de onde se encon-
tra o foco. O truque consiste em trocar a cor de fundo do controle,
quando ele recebe o foco, e retorná-la ao padrão, branco, quando a
ação passa a outro objeto. A operação é simples. Crie duas subs, uma
chamada FundoCor e outra FundoBranco:

Private Sub FundoCor()


ActiveControl.BackColor = RGB(192, 255, 255)
End Sub

Private Sub FundoBranco()


ActiveControl.BackColor = wdColorWhite
End Sub

A cor RGB, acima, é o azul-piscina. Aos meus olhos, é a mais


agradável para a leitura. Mas você pode escolher outra qualquer. No
evento Enter do controle (correspondente ao GotFocus do Visual Basic),
chame FundoCor. No evento Exit (LostFocus, no VB), chame Fundo-
Branco. Aviso prévio: não funciona se o objeto estiver dentro de uma
moldura.

138
16
Todas as fontes,
na tela e no
papel

Um aplicativo para visualizar e imprimir


as fontes instaladas no sistema

Ficha do projeto
Projeto:

Lista de Fontes

O que faz:

Relaciona, numa caixa de diálogo, todas as fontes


instaladas no sistema e exibe amostras de cada uma delas,
em diferentes tamanhos e estilos. Permite, ainda, imprimir
um catálogo personalizado das fontes instaladas.

Arquivos e requisitos do projeto:

Formulário frmFontes e código interno.


Formulário frmFontesCatálogo e código interno.

Conhecimento técnico:

Trabalho com coleções de objetos e matrizes. Rotina de


classificação.

Nível de programação:

Intermediário
Neste projeto, o objetivo básico é criar um mostruário de fontes. Com ele,
o usuário poderá visualizar todos os recursos de letras disponíveis em seu siste-
ma e experimentar, interativamente, tamanhos e estilos. Poderá ainda, se quiser,
imprimir um catálogo das fontes, exibindo-as no tamanho que achar mais con-
veniente às suas necessidades.
Para levar à frente esta idéia, precisamos construir um formulário
(frmFontes) com o seguinte conjunto de controles ativos:

a) uma caixa de listagem (lstFontes), que receberá a lista com os nomes das
fontes instaladas no sistema;
b) uma caixa de texto (txtAmostra), destinada a exibir a visualização de
qualquer fonte escolhida na caixa lstFontes;
c) dois botões de comando, cmdMais e cmdMenos – o primeiro para au-
mentar, e o outro para reduzir o tamanho da fonte visualizada na caixa
de texto.
d) dois botões de comutação (toggle buttons, que o VBA em português cha-
ma de botões de ativação), tmdItálico e tmdNegrito, que aplicarão os es-
tilos itálico e negrito ao texto exibido em txtAmostra;
e) um botão de comando Aplicar (cmdAplicar), para transferir a um texto
selecionado num documento a formatação de fonte mostrada na caixa
txtAmostra;
f) uma caixa de texto comum (txtTamanho), que exibirá o tamanho da
fonte, em pontos, e também aceitará a digitação de valores por parte do
usuário;
g) um botão Fechar (cmdFechar), para encerrar a aplicação;
h) um rótulo, labNumFontes, que indicará ao usuário o total de fontes lis-
tadas;
i) um botão Catálogo (cmdCatálogo), porta de acesso a outro formulário,
a partir do qual se poderá imprimir um mostruário de fontes; e
j) duas etiquetas auxiliares, uma para identificar a caixa com a lista de fon-
tes e a outra para a caixa texto, com a amostra de texto.
Para que você possa fazer uma idéia concreta de seu trabalho final, veja na
Figura 16.1 como ficará essa caixa de diálogo.

Não há dificuldade no traçado desses objetos. Destaco, apenas, que a caixa


txtAmostra deve ter a propriedade MultiLine ajustada para True. Se isso não for
feito, não será possível visualizar o texto em mais de uma linha. No mais, o tra-
balho essencial consiste em manter o equilíbrio e o alinhamento dos objetos –
coisa que se aprende e se aperfeiçoa com a experiência.
140
F I G U R A 1 6 . 1 Visualização do projeto concluído

Muito bem: está pronta a interface do aplicativo. Mas, por enquanto, ele é
como um aparelho de som que tem apenas o gabinete. Não há, dentro dele, ne-
nhum circuito que o faça funcionar. Nossa próxima tarefa é, justamente, adicio-
nar os circuitos – ou seja, o código de programação.
Comecemos pela caixa de listagem lstFontes. Ela deve entrar em funciona-
mento tão logo o formulário seja exibido. É preciso, portanto, traçar para ela al-
gum circuito que a preencha com o rol das fontes instaladas no sistema. O local
mais adequado para colocar os fios necessários é a rotina UserForm_Inialize,
que é uma das primeiras a ser executadas quando se abre um formulário. Para
preencher a caixa de listagem, bastaria percorrer a coleção de fontes instaladas.
Assim:

Dim fName
For Each fName In FontNames
lstFontes.AddItem fName
Next fName
lstFontes.ListIndex = 0

A primeira linha declara a variável fName, um objeto. Depois, um loop


For/Next varre a coleção FontNames e, com o método AddItem, vai-se adicio-
nando, um a um, os nomes das fontes à caixa de listagem. Por fim, coloca-se a
barra de seleção no primeiro item da lista (ListIndex = 0). Pronto, a caixa está
preenchida com todos os nomes das fontes existentes no sistema.
Mas há um problema: se você fizer como mostrado acima, obterá os nomes
de fontes desordenados, não em ordem alfabética, o que dificulta a localização.
Se estivéssemos trabalhando com a linguagem Visual Basic, bastaria ligar pro-
priedade Sorted (classificada) da caixa de lista. Infelizmente, não existe tal re-
curso nas caixas de lista do VBA. Então, se quisermos organizar os nomes das
fontes em ordem alfa, será necessário fazer isso “no braço”.
141
O primeiro passo é criar uma matriz, sFontes, com tantos elementos quan-
tos sejam os nomes de fontes da coleção FontNames:

Dim i As Integer
Dim fCount As Integer
fCount = FontNames.Count
ReDim sFontes(fCount) As String

‘ Preenche matriz com os nomes, desordenados


For i = 1 To fCount
sFontes(i) = FontNames(i)
Next i

‘ Ordena os nomes de fontes


OrdemAlfa sFontes(), 1, fCount

‘ Preenche a caixa lstFontes


For i = 1 To fCount
lstFontes.AddItem sFontes(i)
Next i

Em seguida, lançamos mão do procedimento chamado OrdemAlfa, que re-


cebe toda a matriz sFontes e a classifica em ordem alfabética. Por fim, varremos
a matriz e preenchemos a caixa de listagem com os nomes das fontes. A rotina
OrdemAlfa usa um algoritmo de classificação conhecido como Bubble Sort, o
“método da bolha”. A etiqueta labNumFontes, como vimos, deve exibir o nú-
mero de fontes listadas. Para isso, basta recorrer à propriedade ListCount da cai-
xa de listagem:

labNumFontes = lstFontes.ListCount

Uma alternativa, para não usar o procedimento OrdemAlfa, é recorrer ao


método SortArray, do WordBasic, a linguagem de macros do Word que foi subs-
tituída pelo Visual Basic. No caso, em lugar de chamar OrdemAlfa, usaríamos:

WordBasic.SortArray sFontes()

Funciona perfeitamente, no Word 97 e no 2000. O problema dessa alter-


nativa é que a Microsoft não estimula o uso do WordBasic. Isso porque, numa
próxima versão do Word, o objeto WordBasic pode desaparecer. Então, de uma
hora para outra, seu programa, baseado nele, passaria a não funcionar.
Ainda na rotina UserForm_Initialize, é interessante preencher a caixa de
texto txtAmostra, para que o usuário visualize a primeira fonte da lista logo na
abertura do formulário. Aqui é simples: projetamos nessa caixa de texto o alfa-
142 beto completo, em maiúsculas e minúsculas, mais os dez algarismos. Quando a
primeira fonte for selecionada, o quadro de amostra exibirá suas letras confor-
me essa fonte. O tamanho inicial é fixado em 8 pontos. Assim, a caixa txtTama-
nho exibe o número 8.
Para os botões de comutação tmdItálico e tmdNegrito, definiu-se que sua
propriedade TripleState é falsa. Essa propriedade permite que esses objetos te-
nham três estados: verdadeiro, falso e nulo (ou seja, sem valor). Em nosso caso,
interessa que eles tenham apenas um comportamento binário: negrito (sim ou
não) e itálico (sim ou não).
Até aqui, preenchemos a lista de fontes e a caixa de texto. Mas, quando o
usuário clicar numa opção de lstFontes, é necessário que essa opção seja aplica-
da à caixa txtAmostra. Para isso, basta incluir uma linha na rotina lstFon-
tes_Click:

txtAmostra.Font.Name = lstFontes.Value

Isso estabelece uma vinculação entre a listagem e a amostra. Agora, avance-


mos para os controles que ficam logo abaixo da caixa txtAmostra. O botão
tmdItálico liga ou desliga o estilo itálico nas letras do quadro de amostra. Ao rece-
ber um clique, ele permanece pressionado (posição ligado) ou retorna ao normal
(desligado). Apenas uma linha na rotina tmdItálico_Click resolve essa questão:

Private Sub tmdItálico_Click()


txtAmostra.Font.Italic = tmdItálico.Value
End Sub

Linha idêntica é usada para responder ao evento Click do botão tmdNegri-


to. Em seguida, vêm os botões cmdMais e cmdMenos. O primeiro adiciona 1
ponto ao tamanho da letra exibida em txtAmostra; o outro subtrai um ponto.
Vejamos o exemplo de cmdMais:

txtAmostra.Font.Size = txtAmostra.Font.Size + 1

Fácil, não? Sim, mas não basta. Naturalmente, não será possível aumentar
(ou diminuir), indefinidamente, o tamanho da letra. Há, então, os limites – que,
em nosso caso, foram definidos em 6, o inferior, e 128, o superior. Isso significa
que, se o usuário tentar extrapolar essas balizas, o programa não deve permitir.
Por isso, antes de somar (ou subtrair, no caso de cmdMenos) um ponto ao ta-
manho da fonte, é preciso verificar se o novo número não cairá na zona proibi-
da. Além disso, o número exibido em txtTamanho também deve ser atualizado.
O código completo associado ao evento Click do botão cmdMais fica assim:

If Not TamanhoAceitável(MAIS) Then Exit Sub


txtAmostra.Font.Size = txtAmostra.Font.Size + 1
txtTamanho = CInt(txtAmostra.Font.Size)
143
A constante MAIS (=1) é enviada a uma função, TamanhoAceitável, que
responde se o novo número está ou não dentro do campo permitido. Em caso
negativo, a rotina é abortada (Exit Sub), evitando que o valor da fonte extrapole
os limites definidos. Para o botão cmdMenos, a rotina é similar: troca-se o mais
pelo menos e envia-se à função TamanhoAceitável a constante MENOS (=2).
Agora, vamos à caixa de texto txtTamanho. Além de receber o número
atribuído ao tamanho da fonte, ela também aceita digitação. Para reduzir a pos-
sibilidade de erros, vamos proibir que o usuário digite nela qualquer coisa que
não seja número. Para isso, usamos o seguinte código no evento txtTama-
nho_KeyPress:

Select Case KeyAscii


Case 8, 48 To 57
‘OK
Case Else ‘ anula a digitação
KeyAscii = 0
End Select

Com as linhas acima, a caixa aceita somente as teclas de código KeyAscii


igual a 8 (retrocesso) ou de 48 a 57 (0 a 9). Todo o resto é anulado. Mas isso ain-
da não impede que o usuário digite números inaceitáveis: 1000, 5500, 99999. É
preciso, portanto, evitar que o erro aconteça. Vamos controlar o que foi digita-
do por meio do evento Exit, que ocorre quando a caixa de texto perde o foco. A
rotina txtTamanho_Exit ganha o seguinte código:

Dim intTam As Integer


intTam = Val(txtTamanho)
If intTam > 128 Or intTam < 6 Then
MsgBox “Tamanho de fonte muito grande ou muito pequeno.”, vbOKOnly, “Fontes”
‘ retorna o valor anterior
txtTamanho = Int(txtAmostra.Font.Size)
Exit Sub
End If
‘ modifica o tamanho
txtAmostra.Font.Size = intTam

Se o valor ultrapassa os limites estabelecidos, o número em txtTamanho é


redefinido com o tamanho da fonte ainda ativo na caixa txtAmostra. Caso con-
trário, a fonte em txtAmostra assume o tamanho digitado.
Em frente, para o botão Aplicar. Esse controle transfere a formatação exis-
tente na caixa de texto txtAmostra para uma área selecionada ou todo um docu-
mento. Ao ser acionado, ele apresenta uma caixa de diálogo avisando ao usuário
a operação que será feita:

144
F I G U R A 1 6 . 2 Mensagem aberta pelo botão Aplicar

Se a resposta for sim, o seguinte código é executado, copiando todas as ca-


racterísticas da fonte em txtAmostra para o trecho selecionado no documento.

With Selection.Font
.Name = txtAmostra.Font.Name
.Italic = txtAmostra.Font.Italic
.Bold = txtAmostra.Font.Bold
.Size = txtAmostra.Font.Size
End With

Application.ScreenRefresh

Observe a última linha acima. O papel dela é forçar a atualização do texto


no documento. Sem ela, a formatação ocorre, mas você só vai vê-la depois de fe-
char o formulário da aplicação Lista de Fontes.
A primeira parte do projeto está concluída. Você pode ver, na tela, todas as
fontes instaladas no seu micro, em diferentes tamanhos e estilos. Resta somente
o botão Catálogo. Ele abre outro formulário, a partir do qual se poderá impri-
mir uma amostra das fontes existentes no computador. Isso será resolvido no
bloco, a seguir.

Catálogo de fontes
Nesta parte do projeto, vamos construir um pequeno aplicativo que permita ao
usuário comandar a impressão de um catálogo com amostras de todas as fontes
existentes em seu computador. Para isso, precisamos desenhar outro formulário,
frmFontesCatálogo. Um clique no botão Catálogo (formulário frmFontes) abre
esse novo formulário. Na verdade, frmFontesCatálogo funciona como um proje-
to independente. Simples, este novo projeto só oferece como opção a possibilida-
de de escolha do tamanho da letra que será usada na confecção do catálogo.
Primeiro, tracemos o formulário frmFontesCatálogo. Trata-se de um pe-
queno form com uma caixa de combinação (cboTamanho) que oferece tama-
nhos de fontes de 8 a 36 pontos. Além dela, há apenas os botões Criar Catálogo
(cmdOK) e Cancelar (cmdCancelar). 145
F I G U R A 1 6 . 3 O formulário frmFontesCatálogo

Na rotina UserForm_Initialize encontra-se o processo de inicialização da


caixa cboTamanho. Ela é preenchida com números de 8 a 36, sendo que o valor
14 é assentado como padrão. A criação do catálogo fica a cargo da rotina Catá-
logoDeFontes, que recebe, como parâmetro, o tamanho da fonte escolhido na
caixa Tamanho. Vejamos como trabalha essa rotina.
Em primeiro lugar, ela abre novo documento para receber o catálogo. Esse
procedimento constitui também uma precaução contra erros. Evita, por exem-
plo, que a rotina escreva em outro documento. Em seguida, ela escreve um títu-
lo para o documento, no qual é indicado o tamanho da fonte escolhido pelo
usuário:
Por fim, num loop, são percorridos todos os nomes de fontes disponíveis no
sistema. À medida que surge novo nome, o texto básico (todas as letras, maiúscu-
las e minúsculas do alfabeto) vai assumindo essa fonte, com o tamanho indicado.
O resultado é um documento como o mostrado na Figura 16.4.

F I G U R A 1 6 . 4 O catálogo: pronto para ser impresso


146
Para completar o projeto, vamos definir o código do botão Criar Catálogo
(cmdOK). Primeiro, ele oculta o formulário. Depois, chama o procedimento
CatálogoDeFontes, passando o valor escolhido pelo usuário na caixa cboTama-
nho. Por fim, fecha o formulário. Por que esconder o formulário? Para que a ro-
tina CatálogoDeFontes funcione, o form precisa estar ativo. Então, ele é oculta-
do e só se fecha depois da criação do catálogo. A rotina completa do botão é:

Private Sub cmdOK_Click()


Me.Hide
CatálogoDeFontes cboTamanho
Unload Me
End Sub

Este projeto resultou da união de dois aplicativos separados, um para exi-


bir as fontes na tela e o outro para produzir um catálogo imprimível. Assim, o
botão Catálogo passou a ser o eixo de ligação entre os dois formulários. Mas, se
você analisar direito, vai notar que o formulário frmFontesCatálogo tem apenas
um item que o justifica: a caixa de combinação na qual o usuário deve escolher o
tamanho da fonte. Por causa disso, decidi retrabalhar o layout do formulário
principal, frmFontes, e eliminar o segundo formulário. O resultado visual está
na figura a seguir.

F I G U R A 1 6 . 5 O projeto, reestruturado para um único


formulário

O que mudou? Todas as funções de frmFontesCatálogo foram absorvidas por


frmFontes. Para o usuário, é bem mais cômodo, já que tudo está na mesma tela.
Aliás, o programador também ganha, porque se livra da necessidade de bolar arti-
manhas para coordenar o fechamento dos dois formulários. O projeto, refeito, está
disponível no disco que acompanha este volume, no modelo ListFont2.dot. 147
Por fim, vale discutir um aspecto interessante, relacionado ao encerramen-
to dos aplicativos VBA. Projetos contidos dentro de um modelo são abertos,
obrigatoriamente, com a apresentação de um documento baseado nesse mode-
lo.Quando se trata de uma aplicação que se esgota em si mesma – ou seja, não
gera documentos –, ao fechar o formulário, pode-se fechar também o documen-
to ativo. Assim, todos os traços do programa são varridos da memória.
Em casos como o deste Catálogo de Fontes, a coisa é um pouco mais com-
plicada. Quando se produz um catálogo para impressão, é recomendável que o
programa seja encerrado e o documento-catálogo se torne o documento ativo.
Ao mesmo tempo, para limpar completamente o programa da memória, deve-se
fechar o documento que lhe serve de suporte (no caso de um projeto residente
num modelo diferente do Normal). Aqui você tem de tomar cuidado para fe-
char o documento certo.
Um roteiro para isso é o seguinte. Assim que o programa entrar em ação,
capture o nome do documento que o contém. Declare uma variável com valida-
de em todo o formulário e armazene nela o nome desse documento. O melhor
lugar para fazer isso é a rotina UserForm_Initialize:

sNomeDocOriginal = ActiveDocument.Name

Se, por exemplo,você vai emitir um catálogo, outro documento entra em


cena. Logo que ele for criado (Documents.Add), capture também o nome dele,
que será o novo documento ativo:

sNomeDocCatálogo = ActiveDocument.Name

No final da montagem do catálogo, feche o form com a instrução Unload.


Por fim, no evento QueryUnload, acrescente as seguintes linhas:
If sNomeDocCatálogo < > “” Then
Documents(sNomeDocCatálogo).Activate
Documents(sNomeDocOriginal).Activate
End If

Documents(sNomeDocOriginal).Close wdDoNotSaveChanges

Se não há um documento com o catálogo, fecha-se o documento-suporte


(última linha acima). Se, ao contrário, houve emissão do catálogo, coloca-se o
documento correspondente em primeiro plano. Em seguida, esse mesmo plano
é ocupado pelo documento original, depois fechado. Isso garante que o catálogo
fique visível para o usuário.

Para ir mais além


1. Experimente o preenchimento da caixa de listagem lstFontes sem usar o
148
recurso de ordenação alfabética. Observe como a abertura do formulá-
rio fica bem mais rápida. A maior parte do tempo consumido nessa ope-
ração deve-se à classificação alfabética. Se seu micro tem poucas fontes
instaladas, você nem vai notar a diferença.
2. A rotina OrdemAlfa pode ser usada em qualquer outro programa para
organizar os elementos de uma matriz, em ordem alfabética. Ela deve
receber a matriz, além dos índices do primeiro e do último elemento da
matriz.
3. Você pode usar a rotina OrdemAlfa ou o método SortArray, do Word-
Basic, para ordenar, alfabeticamente, os nomes das fontes no catálogo
para impressão. Em lugar de listar as fontes via coleção FontNames, crie
uma matriz com elas, classifique a matriz, e passe para o documento os
nomes da fonte a partir dos elementos da matriz. Essa solução está pron-
ta na segunda versão do projeto, com apenas um formulário.
4. Algumas fontes não são exibidas corretamente na caixa txtAmostra.
Entre elas estão Wingdings, Webdings, Marlett e Symbol – todas elas fon-
tes figurativas. Curiosamente, se você predefinir a fonte para esses no-
mes, funciona. Todavia, se elas forem definidas com o programa já ro-
dando, as imagens recusam-se a aparecer. Creio que temos aí um peque-
no bug. Fiz um teste com caixas de texto do Visual Basic 6.0 e o funciona-
mento foi normal com essas fontes. O mesmo problema existe com o ob-
jeto Label (rótulo). Esse comportamento estranho pode ser constatado
tanto no Office 97 como no Office 2000, em português ou no original,

Fontes demais
Alguns programas gráficos, como o CorelDraw, vêm acompanhados de
milhares de fontes. Não caia na tentação de instalar todas. Mesmo re-
vistas e outras publicações profissionais não usam mais que um punha-
do de fontes. Instalar um número excessivo de conjuntos de letras não
traz nenhum benefício concreto. Ao contrário, consome recursos do sis-
tema. Se for necessário, use um gerenciador de fontes. Trata-se de um
tipo de programa que mantém as fontes instaladas, mas inativas.
Assim, elas não desperdiçam recursos do sistema. Aliás, o próprio Win-
dows tem um limite de fontes, que fica em torno de 1000.

em inglês. É o tipo do bug que passa batido, versão após versão.

149
17
Um projeto
cheio de estilo

Organize catálogos de todos os estilos


disponíveis no Word

Ficha do projeto

Projeto:

Catálogo de Estilos

O que faz:

Apresenta, numa caixa de diálogo ou num documento,


os nomes e características dos estilos disponíveis no
Word.

Arquivos e requisitos do projeto:

Formulário frmEstilos e código interno.

Conhecimento técnico:

Manipulação das coleções de estilos do Word.

Nível de programação:

Intermediário
As coleções de objetos do Word – e de outros aplicativos do Office – constituem
uma chave mestra para a programação de aplicativos nessa plataforma. Itens da
interface do programa (como barras de ferramentas, botões e comandos de
menu) formam coleções. Partes do documento (parágrafos, tabelas, fontes) tam-
bém estão reunidas, cada tipo em sua própria coleção. Os conversores de arqui-
vos disponíveis no ambiente são outra coleção. Então, não é preciso adivinhar:
os estilos embutidos no sistema, ao lado dos estilos criados pelo usuário, tam-
bém formam uma coleção.
Neste projeto, nosso intuito é elaborar um aplicativo que permita ao usuá-
rio visualizar uma lista com a descrição de todos os estilos disponíveis e, se qui-
ser, produzir um documento-catálogo com os nomes e descrições dos estilos.
Esse documento pode ser armazenado ou impresso, conforme a necessidade.
O aplicativo baseia-se num formulário (título: Lista de Estilos; nome:
frmEstilos) bem simples. Inclui apenas uma caixa de listagem (lstEstilos) e três
botões de comando: Aplicar (cmdAplicar), Catálogo (cmdCatálogo) e Cancelar
(cmdCancelar).

F I G U R A 1 7 . 1 O formulário: estilos residentes e personalizados

No desenho do formulário não há nada de excepcional. Passemos, então,


ao código. Mas, antes de tudo, é importante fazer duas observações. A primeira:
no Word, há dois tipos de estilos – os personalizados, que são criados pelo usuá-
rio, e os residentes, que vêm de fábrica, no programa. A outra observação é que
os estilos personalizados variam de documento para documento.
Os estilos personalizados podem ser armazenados em diferentes modelos.
Assim, quando você pede que o Word liste esses estilos do usuário, ele vai apre-
sentar uma relação dos estilos existentes no documento ativo. Nossa aplicação,
portanto, apresentará uma listagem dos estilos personalizados (se houver algum
no documento ativo) e dos estilos residentes.
151
Para gerar a lista de estilos, a principal rotina do projeto é a sub User-
Form_Initialize. Ela contém todos os ingredientes necessários para o que o for-
mulário Lista de Estilos já se apresente, exibindo a lista completa dos estilos.
A grande vantagem das coleções de objetos do Office está na facilidade de
listá-los e, com isso, tomar uma série de iniciativas de programação. O centro da
rotina de inicialização do formulário está em dois loops. O primeiro percorre o
conjunto de estilos personalizados, ou melhor, não-residentes. O segundo, lista
os estilos residentes. O arcabouço desses loops é o seguinte:

For Each est In ActiveDocument.Styles


If Not est.BuiltIn Then
(...)

For Each est In ActiveDocument.Styles


If est.BuiltIn Then
(...)

Fica claro que a propriedade BuiltIn (embutido) indica o estilo residente.


O resto são caracterizações dos itens que definem um estilo: nome da fonte, ta-
manho, estilo (negrito, itálico), parágrafo (recuo à esquerda, recuo à direita, es-
paço entre linhas), alinhamento do parágrafo (à esquerda, à direita, centrado)
etc. Cada um desses itens é acrescentado, com o método AddItem, à caixa de lis-
tagem lstEstilos. Acima deles, naturalmente, figura o nome do estilo (proprieda-
de NameLocal).
O botão Aplicar transfere o estilo indicado na caixa lstEstilos para uma se-
leção qualquer do documento ativo. Em outras palavras, você pode usar esta
aplicação para definir estilos no documento em que está trabalhando. No entan-
to, a caixa de lista lstEstilos contém, além de estilos, títulos e elementos de estilo
como Fonte, Recuo de parágrafo etc. Para identificar exatamente nessa caixa o
que é um estilo, usamos o seguinte truque:

Dim sEstilo As String


sEstilo = lstEstilos.Value
If Left$(sEstilo, 3) <> “--” And _
Left$(sEstilo, 3) <> Space(3) Then
Selection.Style = sEstilo
End If

O botão Catálogo chama a rotina CatálogoDeEstilos, cujo código é idênti-


co ao de UserForm_Initialize. A diferença básica está no lugar em que a lista de
estilos é apresentada. Ao abrir o formulário, a lista é mostrada na caixa lstEsti-
los. Agora, a mesma lista vai para um novo documento do Word (e daí, se o lei-
tor quiser, para a impressora). Portanto, em lugar do método AddItem, usamos
agora TypeText para escrever linhas de informações num documento Word.
Por exemplo:
152
With Selection
.TypeText “ Fonte: ” & est.Font.Name & “ ” & _
est.Font.Size & vbCrLf
.TypeText “ Negrito: ” & IIf(est.Font.Bold = True, _
“Sim”, “Não”) & vbCrLf
.TypeText “ Itálico: ” & IIf(est.Font.Italic = True, _
“Sim”, “Não”) & vbCrLf
(...)

Estas linhas produzem algo como:

Fonte: Times New Roman 10


Negrito: Não
Itálico: Sim

Observe que estas linhas de código terminam sempre com a constante


vbCrLf. Essa constante equivale à combinação das teclas Enter (Cr, ou carriage
return) e Linefeed (alimentador de linha). Juntas, elas definem, no Windows,
um novo parágrafo. Você poderia também usar, em lugar da constante, outro
método do Word:

Selection.TypeParagraph

O documento produzido pelo pressionamento do botão Catálogo é dividi-


do em duas partes. A primeira, com os estilos personalizados, se houver. E a ou-
tra com os estilos residentes. O layout do catálogo é mostrado na Figura 17.2.

F I G U R A 1 7 . 2 Um catálogo, destacando a parte dos estilos


personalizados 153
Para ir mais além
1. Um detalhe interessante. Assim como os estilos, as barras de ferramen-
tas também têm a propriedade NameLocal (em português). Só que as
barras têm ainda a propriedade Name (em inglês), que não existe para
os estilos.
2. As medidas nos documentos do Word são dadas em pontos. Este é o padrão.
Então, para mostrar dimensões em centímetros, você precisa fazer sempre a
transformação de unidades. Neste projeto, há exemplos dessa transformação
nas rotinas UserForm_Initialize e CatálogoDeEstilos. Um exemplo:
PointsToCentimeters(est.ParagraphFormat.LeftIndent) & “ cm”

Existem também funções para executar outras transformações de medi-


das: PointsToInches (de pontos para polegadas); PointsToLines (de
pontos para linhas); PointsToMilimeters (de pontos para milímetros);
PointsToPicas (de pontos para paicas); PointsToPixels (de pontos para
pixels). As operações inversas também estão disponíveis: MilimetersTo-
Points, LinesToPoints, CentimetersToPoints.
3. Neste projeto, estão cobertas apenas as formatações de estilo mais óbvi-
as – aquelas que se referem a parágrafos e fontes. No entanto, as forma-
tações de estilo envolvem ainda outros itens de que não se pode esque-
cer: tabulação, borda, idioma, moldura e numeração.

Yo no creo en fantasmas, pero...


Muitas vezes quem desenvolve em ambiente Windows se vê assombra-
do por fantasmas digitais. Eles aparecem, por exemplo, quando um co-
mando trivial, sobre o qual não há dúvida possível, começa a se com-
portar de forma esquisita. Eis um exemplo que aconteceu comigo. Du-
rante a produção deste livro, eu precisava usar a função Now para ob-
ter o nome do mês corrente. Fiz o seguinte:
Format$(Now, “mmmm”)

Pois bem, a expressão acima fornecia “janeiro”— só que o mês


atual era outubro. Testei-a na janela Imediata, no VBA/Word, e a es-
quisitice continuava. Como alternativa, passei para a expressão equi-
valente, Format$(Date, “mmmm”), que fornecia uma resposta correta.
Voltei para Now, e nada.
A solução foi simples e desconcertante: salvar todos os documen-
tos e reiniciar o computador. Aí tudo voltou a se comportar como espe-
rado. Conclusão: você pode não acreditar em fantasmas, mas eles exis-
tem — inclusive os digitais. Para livrar-se deles, zerar tudo e recomeçar
talvez seja a saída. Dê um boot no fantasma.
154
18
No paraíso das
secretárias

Um programa que demonstra recursos


do VBA aplicados a tabelas do Word

Ficha do projeto

Projeto:

VBA com tabelas

O que faz:

Demonstra recursos do VBA aplicados às tabelas do


Word.

Arquivos e requisitos do projeto:

Modelo Tabelas.dot, que inclui documento e formulário


VBA com código interno.

Conhecimento técnico:

Funções do VBA para criar, modificar, apagar e formatar


tabelas.

Nível de programação:

Iniciante
As tabelas, a meu ver, formam um capítulo à parte no Word. Quando tive a
oportunidade de experimentá-las, pela primeira vez, no Word 2.0, pensei comi-
go: é o paraíso das secretárias! Claro, as tabelas são um recurso fantástico para
qualquer usuário. Pensei, imediatamente, nas secretárias porque sabia o quanto
era penoso para elas datilografar (epa, aí está uma palavra do século passado!)
documentos que incluíam tabelas. Sabia também que, mesmo nos processadores
de texto para DOS, construir uma tabela requeria engenho, arte – e muita pa-
ciência.
Este capítulo apresenta uma coleção de itens que demonstram algumas das
possibilidades do VBA aplicado a tabelas do Word. São dez pequenos exercícios
que envolvem as principais operações com tabelas. O projeto está todo contido
no modelo Tabelas.dot, o qual contém um documento com duas tabelas e, inter-
namente, um formulário VBA com código.
O documento é simples. Exibe uma tabela de quatro linhas e quatro colunas,
e outra de seis linhas e três colunas. Essas tabelas dão suporte aos exercícios em
VBA que serão implementados no projeto. O desenho do formulário (frmTabe-
las) também não apresenta mistérios. Trata-se de um formulário com uma moldu-
ra abrigando dez botões de opção (opt1 a opt10), um para cada operação de-
monstrada. Além disso, há dois botões de comando: OK (cmdOK), que dispara a
operação selecionada, e Cancelar (cmdCancelar), que fecha a aplicação.

F I G U R A 1 8 . 1 O formulário: dez exercícios com tabelas

O eixo da aplicação é o código associado ao evento clique do botão OK.


Ali encontra-se uma instrução Select Case que distribui a ação para diferen-
tes rotinas. Vamos percorrer as dez operações, comentando os detalhes prin-
cipais.

156
F I G U R A 1 8 . 2 O documento embutido no modelo: duas tabelas
simples

1. Multiplicar uma célula de Tab 1 por uma célula de Tab 2


Nesse caso, a operação é feita na sub MultiplicarCélulas, mas estriba-se na fun-
ção PegaValorCélula. MultiplicarCélulas pede os valores à função e, em segui-
da, calcula o produto:

v1 = PegaValorCélula(1, 3, 2)
v2 = PegaValorCélula(2, 1, 2)
v = v1 * v2

Portanto, o esforço fundamental é realizado pela função PegaValorCélula.


Esta tem o seguinte cabeçalho:

Private Function PegaValorCélula(nTab As Integer, _


nLin As Integer, nCol As Integer) As Variant

Os três parâmetros que ela recebe são exatamente os itens que localizam a
célula desejada. Primeiro, nTab, o índice da tabela. Depois, o número da linha
(nLin) e o número da coluna (nCol). A rigor, a localização da célula demandaria
mais uma informação: o nome ou o índice do documento. Sim, porque você
pode ter vários documentos abertos, cada qual contendo uma ou mais tabelas.
No entanto, para simplificar, trabalharemos aqui sempre com o documento ati-
vo. Não há perigo de erro: como você vai notar, o próprio acesso ao formulário
garante que o documento ativo seja o que nos interessa.
No Word, cada tabela inserida num documento ganha um número seqüen-
cial, a partir de 1. Essa numeração envolve uma pegadinha. Se um documento 157
contém três tabelas, seus índices são 1, 2 e 3. Se você eliminar a tabela 2 e voltar
a fazer referência ao índice 3, provocará um erro. Por quê? Simplesmente por-
que o índice 3 deixou de existir. A ex-tabela 3 tem agora o índice 2. Portanto, fi-
que esperto.
Mas voltemos à função PegaValorCélula. Suas linhas ativas são as seguin-
tes:

Dim varValor As Variant


varValor = _
ActiveDocument.Tables(nTab).Cell(nLin, nCol).Range.Text
varValor = Left$(varValor, Len(varValor) - 2)
PegaValorCélula = varValor

A segunda linha captura o valor da célula indicada. Na seguinte, são retira-


dos dois caracteres do final desse valor. Isso é feito porque o conteúdo de cada
célula contém dois caracteres, além dos visíveis: o caractere 13 (correspondente
ao Enter, ou vbCr) e o 7, que não tem representação externa. Juntos, eles indi-
cam o final de uma célula. Quando o Word está configurado para exibir todos
os caracteres, inclusive os ocultos, esses caracteres são representados na tabela
por um pequeno círculo com quatro raios, como você pode ver na Figura 18.2.

F I G U R A 1 8 . 3 Cada célula tem um caractere especial

Observe que a função PegaValorCélula retorna um valor do tipo variant.


Como a intenção era usar valores mistos (texto ou números), decidimos traba-
lhar com esse tipo de variável. Nada impede, no entanto, que você faça a função
fornecer um resultado do tipo string, que depois, se for o caso, deve ser conver-
tido para um formato numérico adequado.

2. Capturar e exibir uma linha de tabela


A operação 2 consiste em ler as informações de uma linha de tabela e exibi-las
numa caixa de mensagem. Aqui, a rotina responsável pelo trabalho básico é a
função GetLinha. Ela recebe o índice da tabela (nTab) e o número da linha. Sua
missão é ler, um a um, os valores das células dessa linha. Como primeira ação,
GetLinha verifica o número total de colunas, usando o método Count:
iTotColunas = ActiveDocument.Tables(nTab).Columns.Count
158
Em seguida, faz um loop do tipo For/Next, com o contador variando de 1
ao total de colunas, já calculado. Assim, ao ler cada célula, acumula seus valores
numa string, separando-os com uma vírgula. O resultado final da função é essa
string.

3. Capturar e exibir uma coluna de tabela


Esta operação é bastante similar à anterior. Basta fazer as adaptações necessárias.
Onde lá se lia coluna, aqui se deve ler linha, e vice-versa. A base é a função GetCo-
luna, cuja estrutura é idêntica à de GetLinha. Há apenas uma diferença sutil.
Como já vimos, o valor de cada célula é sempre expurgado de seus dois últimos
caracteres, Chr(13) e Chr(7). Em GetColuna, somente o último caractere é retira-
do. Mantém-se o outro, porque ele determina uma quebra de linha. Como a in-
tenção é mostrar uma coluna, o resultado, na caixa de mensagem, fica assim:

F I G U R A 1 8 . 4 Coluna da tabela

4. Selecionar a coluna 1 da tabela 2


A solução, neste caso, é direta. Basta usar o método Select:

ActiveDocument.Tables(2).Columns(1).Select

159
5. Apagar a coluna 4 da tabela 1
Para apagar linhas ou colunas, usa-se o método Delete – aliás, o mesmo método
utilizado em numerosas situações em que é preciso eliminar objetos:
ActiveDocument.Tables(nTab).Columns(nCol).Delete

6. Formatar a coluna 1 da tabela 1


Para esta operação, entra em cena o procedimento FormatarColuna, que execu-
ta as seguintes configurações:
n define como verde a cor de fundo da coluna;
n muda a fonte para negrito e itálico;
n muda a cor da fonte para azul.

7. Apagar a tabela 2 inteira


Mais uma vez, o método usado é Delete, e a aplicação é direta. Sendo nTab o ín-
dice da tabela, basta indicar:

ActiveDocument.Tables(nTab).Delete

8. Trocar o valor de Tab2 (2, 2) para 22


Neste caso, basta selecionar a célula desejada – (2, 2) na tabela 2 – e inserir nela
o novo valor: 22. A inserção é feita com o método TypeText. Assim:

ActiveDocument.Tables(2).Cell(2, 2).Select
Selection.TypeText “22"

Outra forma de obter o mesmo resultado seria usar a propriedade Text do


objeto Range:

ActiveDocument.Tables(2).Cell(2,2).Range.Text= “22"

Essa segunda alternativa é também mais econômica, porque dispensa a se-


leção prévia da célula. Como você vê, diferentes caminhos conduzem ao mesmo
objetivo. Situações assim são comuns no VBA.

9. Classificar a tabela 2 pela coluna 1


Um dos recursos disponíveis para o trabalho com tabelas é a possibilidade de
classificação segundo vários campos. O método responsável por isso é Sort.
160
Abaixo, você o vê, aplicado à tabela 2, num comando definido por parâmetros
nomeados:

ActiveDocument.Tables(2).Sort _
ExcludeHeader:=False, FieldNumber:=1, _
sortFieldType:=wdSortFieldAlphanumeric, _
SortOrder:=wdSortOrderAscending

O que significam esses parâmetros?


n ExcludeHeader (excluir cabeçalho) indica se a primeira linha da tabela
deve ou não entrar no processo de classificação.
n FieldNumber é número da coluna que servirá de base para a classifica-
ção.
n SortFieldType indica o tipo de coluna a ser ordenada. O valor wdSort-
FieldAlphanumeric aplica-se, corretamente, a números ou texto.
n SortOrder, a ordem de classificação deve ser crescente ou decrescente.

10. Adicionar uma tabela 3x7 ao documento


Até aqui, já fizemos vários exercícios com a eliminação de partes de uma tabela
ou de uma tabela inteira. Façamos, agora, o contrário: criar uma tabela. Para
isso, vamos recorrer à função AdicionarTabela. Esta recebe os parâmetros nLins
e nCols, inteiros, que indicam, respectivamente, o número de linhas e colunas
da tabela a ser criada. O método usado para inserir uma tabela é Add, que pede
como referência uma área de ação (range). Por isso, antes de recorrer a esse co-
mando, é necessário definir essa área. Na função, ela correponde ao documento
inteiro, o que é mostrado por:

Dim Intervalo As Range


Set Intervalo = ActiveDocument.Content

Agora, usamos o método Collapse, que recolhe um intervalo ou seleção


para a posição inicial ou final. No caso, o que nos interessa é incluir a tabela no
final do documento:

Intervalo.Collapse Direction:=wdCollapseEnd

Podemos, então, inserir a tabela:

ActiveDocument.Tables.Add Range:=Intervalo, _
NumRows:=nLins, NumColumns:=nCols
Application.ScreenRefresh
161
Observe que o valor do parâmetro Range é o próprio intervalo, antes de-
finido. A última linha acima força a atualização da tela do Word para que o
usuário veja, imediatamente, a tabela recém-criada. Sem ela, a tabela será cria-
da corretamente, mas talvez não seja exibida logo. Para o caso de dúvida, atua-
liza-se a tela.
Há dezenas de outras possibilidades de trabalho com tabelas. Ao longo
do tempo, e com o surgimento das necessidades, você vai descobri-las. Em
caso de dúvida, recorra sempre ao help do VBA. Outra forma bastante produ-
tiva de pesquisar é gravar uma macro (Ferramentas/Macro/Gravar Nova Ma-
cro) com as operações que você deseja realizar em código. O próprio Word en-
sina o que fazer.

Para ir mais além


1. Um bom exercício é descobrir, por exemplo, como selecionar duas ou
mais linhas ou colunas contíguas numa tabela. Uma pista: selecione a li-
nha (ou coluna) e depois aplique o método MoveDown ou MoveRight
para estender a seleção às linhas ou colunas vizinhas.
2. Dê uma boa olhada nos comandos de formatação de tabelas. Por exem-
plo, como definir as cores das bordas.
3. Dica: durante a gravação de macros, não é possível selecionar linhas ou
colunas de uma tabela com o mouse. Faça essas operações com o teclado.

162
Para colorir as tabelas
Você está elaborando uma tabela e quer destacá-la, adicionando uma
cor de fundo. No modo interativo, é simples. Basta selecionar a área
desejada, acionar Formatar/Bordas e Sombreamento e escolher a cor
na orelha Sombreamento. E no VBA, como se faz isso? Primeiro é pre-
ciso selecionar a parte da tabela que deve ser pintada. A sintaxe você já
viu neste capítulo. Por exemplo, para selecionar a linha 3 da tabela 2,
no documento 1:

Documents(1).Tables(2).Rows(3).Select

Para atribuir a cor de fundo, recorre-se à propriedade Back-


groundPatternColor do objeto Selection.Shading. Se você escrever

Selection.Shading.BackgroundPatternColor =

o VBA abrirá a ajuda pop-up com dezenas de cores à disposição. Há


inclusive os meios-tons de cinza, cujas constantes são fáceis de me-
morizar: wdColorGray05,wdColorGray10 etc. Para ser melhor, falta
apenas que, ao lado da constante, o VBA exiba uma amostra visual da
cor.

F I G U R A 1 8 . 5 Constantes de cores

Não confunda a propriedade BackgroundPatternColor com Back-


groundPatternColorIndex. A primeira, que usamos acima, corresponde
ao padrão RGB: 16,7 milhões de cores. A outra, o Index, oferece menos
de duas dezenas de tonalidades. Há apenas uma notícia ruim: Back-
groundPatternColor só está disponível no Word 2000. Se você usa o
97, terá de se contentar com as poucas cores de BackgroundPat-
ternIndex.

163
19
O Word também
toca música!

Uma aplicação para executar arquivos


MP3, WAV e MID

Ficha do projeto

Projeto:

Som no Word 1

O que faz:

Organiza uma lista de arquivos de som nos formatos MP3,


WAV e MID e permite executá-los, individualmente, usando
o acessório Media Player, do Windows.

Arquivos e requisitos do projeto:

Formulário frmSom e código interno.

Conhecimento técnico:

Manipulação básica de um objeto do VBA (o objeto


FileSearch, que localiza arquivos no disco), e da função
Shell, tradicional do Basic, que executa outros programas
externos ao projeto.

Nível de programação:

Iniciante
Neste projeto, Som no Word 1, vamos apresentar a primeira parte de uma série
de três que envolvem a manipulação de recursos sonoros. Nossa intenção, aqui,
é bem simples: criar uma caixa de diálogo do Word que organize uma lista de ar-
quivos de som e permita que esses arquivos sejam executados.
Para tal propósito, a caixa de diálogo – em nosso caso, o formulário
frmSom – deverá conter apenas três controles fundamentais: uma caixa de lista
(lstArquivos), um botão para tocar as músicas (cmdExecutar) e um botão de saí-
da (cmdCancelar).

F I G U R A 1 9 . 1 Som no Word: para tocar arquivos de música

Não há, portanto, nenhum segredo no desenho do formulário. A imagem


do alto-falante que você vê na Figura 19.1 tem apenas função decorativa. Passe-
mos, então, ao código. Em primeiro lugar, é preciso organizar a lista dos arqui-
vos. Quando o usuário abrir o formulário, ela já deve estar pronta. Por isso, o
código que cria a lista e a coloca na caixa lstArquivos faz parte da rotina User-
Form_Initialize, que é a primeira a ser executada em qualquer formulário.
Essa rotina começa por definir um diretório básico, strNomeDir, no qual o
programa irá procurar os arquivos de som. Esse diretório é c:\windows\media.
A variável strNomeDir é declarada como geral para todo o formulário. Fazemos
isso porque vamos precisar do valor dela em mais de uma rotina.
Para localizar os arquivos, usamos os serviços do objeto FileSearch, aqui
representado com o nome de Busca. Na verdade, para usar os termos técnicos,
FileSearch é uma classe de objetos e Busca, uma instância dessa classe. Essa ins-
tância se define da seguinte maneira:
Dim Busca As FileSearch
Set Busca = Application.FileSearch

A partir daí, passa-se a trabalhar somente com o objeto Busca, que tem a
vantagem do nome mais curto e mais amigável. Naturalmente, você não precisa-
ria usar esse nome: poderia tratar diretamente com Application.FileSearch.
Muito bem: agora, precisamos definir algumas propriedades do objeto Busca. 165
With Busca
.NewSearch
.LookIn = strNomeDir
.SearchSubFolders = False
.FileName = “*.wav;*.mid;*.mp3"
.Execute
(...)
End With

Veja o que quer dizer cada uma dessas propriedades:

LookIn Recebe o nome do diretório em que os arquivos devem


ser procurados.

FileName Armazena as extensões dos tipos de arquivos que devem


ser localizados, no caso “*.wav;*.mid;*.mp3”.

SearchSubFolders True ou False. Define se o objeto de busca deve procurar


arquivos em subpastas do diretório indicado.

O método NewSearch avisa ao objeto Busca que deve fazer uma nova pes-
quisa com as condições (propriedades) indicadas. Já o método Execute, como o
nome indica, dá o sinal de largada para que a busca seja levada a efeito.
No final da rotina vem um If. Se a pesquisa encontrou algum arquivo (Bus-
ca.FoundFiles.Count > 0), então organiza-se a lista. Caso contrário, o progra-
ma emite um aviso ao usuário. Obviamente, o que nos interessa é a situação em
que a contagem de arquivos é maior que zero. Aí, como todos os arquivos de
som pertencem ao mesmo diretório, vamos listá-los sem o caminho de localiza-
ção, somente com os nomes. Para isso, como já sabemos o comprimento do
nome do diretório mais a barra invertida(lenStrNomeDir), ficamos apenas com
o nome “líquido” do arquivo, que é adicionado como um item da caixa de lista-
gem:

For i = 1 To .FoundFiles.Count
lstArquivos.AddItem Right$(.FoundFiles(i), _
Len(.FoundFiles(i)) - lenStrNomeDir)
Next i

Pronto. A lista de arquivos – WAV, MP3 ou MID – está na caixa lstArqui-


vos. Agora, falta garantir que o usuário escolha um arquivo e possa tocá-lo, cli-
cando no botão Executar. Isso é resolvido na rotina cmdExecutar_Click, que
determina o que o programa deve fazer quando o usuário clicar nesse botão.
Agora chegamos à função Shell. Essa velha conhecida dos programadores Ba-
sic serve para chamar um executável externo. Aqui, ela é usada da seguinte forma:
166
Private Sub cmdExecutar_Click()
Dim strArq As String
‘ caminho completo do arquivo: dir + arquivo
strArq = strNomeDir & “\” & lstArquivos.Value

‘ A linha abaixo trabalha com o Media Player


‘ Vale para arquivos WAV, MID, MP3 (som) e AVI (vídeo);
Shell “c:\windows\mplayer.exe ” & _
“/play /close ” & strArq, vbHide
End Sub

Para que o programa possa encontrar o arquivo corretamente, é necessário


apresentá-lo com o caminho completo. Então, faz-se agora a operação inversa
daquela executada na rotina UserForm_Initialize: junta-se caminho e nome de
arquivo na variável strArq. Em seguida, passa-se esse nome de arquivo à função
Shell, que obedece ao seguinte esquema:

Shell “executável parâmetros arquivo”, estilo_da_janela

Em nosso caso, o executável é mplayer.exe, localizado no diretório c:\win-


dows. Os parâmetros – específicos para o programa Media Player – são /play
/close. Por fim, vem o nome do arquivo. Os parâmetros indicam que o programa
deve tocar o arquivo (play) e fechar-se (close) após a execução. O estilo da jane-
la, que é opcional, define se o executável deverá aparecer numa janela maximi-
zada, minimizada, normal ou oculta. No exemplo, escolhemos a opção oculta
(vbHide). O arquivo de som será tocado de forma independente pelo Media
Player.
Se você não usar a opção vbHide (e usar, em vez dela, vbNormalFocus, por
exemplo), o Media Player vai abrir sua janela, normalmente, e mostrar na barra
de título o arquivo em execução:

F I G U R A 1 9 . 2 Media Player com opção de janela normal

Projeto concluído. Uma observação: para garantir o estilo Windows, cha-


me a rotina cmdExecutar_Click a partir da rotina do evento lstArquivos_Dbl-
Click. Isso significa que, se o usuário der um duplo clique numa linha da caixa
de lista, o arquivo correspondente será tocado. 167
Para ir mais além
1. Como todos os arquivos de som envolvidos neste projeto localizam-se
num mesmo diretório, trabalhamos apenas com o “nome líquido”do ar-
quivo. No entanto, o objeto FileSearch tem condições de localizar ar-
quivos em qualquer diretório. Se você trabalhar com o nome completo
(caminho + nome) do arquivo, pode listar todos os arquivos WAV,
MID e MP3 do disco rígido. Para isso, defina as seguintes propriedades
de FileSearch:
.LookIn = “c:”
.SearchSubFolders = True

2. Experimente com os parâmetros do Media Player. Use, por exemplo,


somente o parâmetro /play e observe o que acontece.
3. O Media Player (mplayer.exe, localizado no diretório do Windows) só
toca um arquivo de cada vez. Não há uma forma simples de fazê-lo tocar
uma seqüência de arquivos musicais. Veja no próximo capítulo uma so-
lução para isso.

VBA em vez do Explorer


Se você precisa criar grande número de diretórios com numeração se-
qüencial (por exemplo, “Capítulo 01”, “Capítulo 02” etc.), use o se-
guinte programa VBA:
Sub CriarDiretórios()
‘ Cria diretórios numerados
Dim i As Integer
Dim strCap As String
Dim strDir As String
strDir = “c:\meus documentos\Livro Final\”

For i = 1 To 30
MkDir strDir & “Capítulo ” & Format (i, “0#")
Next i

MsgBox “Trabalho concluído.”


End Sub

Esta dica resultou de minha experiência prática na produção deste


livro. Em situações assim, é muito mais rápido usar o VBA que criar,
manualmente, trinta pastas de arquivos com o Windows Explorer.

168
20
Os objetos
comandam o
ritmo

Faça a programação com objetos soar


como música aos seus ouvidos

Ficha do projeto

Projeto:

Som no Word 2

O que faz:

O programa gera um arquivo-texto M3U, padrão MP3,


com a lista de todos os arquivos MP3, MID e WAV. Depois,
usa um programa qualquer que suporte esse padrão para
executar a seqüência de músicas. Aqui, essas
características são apresentadas em duas visões: segundo
a programação tradicional e com base na programação
orientada a objeto.

Arquivos e requisitos do projeto:

Módulo modSomWord2 (programação clássica)


Formulário frmSoundPlay e módulo de classe SoundPlayer
(programação orientada a objeto)
Conhecimento técnico:

Manipulação básica de um objeto do VBA (o objeto FileSearch, que localiza arquivos


no disco) e da função Shell, tradicional do Basic, que executa outros programas
externos ao projeto.
Criação de uma classe de objetos, com definição de seus métodos e propriedades.

Nível de programação:

Intermediário

Você certamente terminou o capítulo anterior com uma pequena frustração: o


projeto só permite tocar um arquivo de som de cada vez. Mas – por que não? –
sua intenção é executar uma seqüência de músicas, bem no estilo dos MP3 pla-
yers, como o WinAmp, o RealJukebox e o MusicMatch Jukebox e – surpresa! –
o Windows Media Player. Isso também pode ser feito a partir do Word ou de
qualquer outro aplicativo que trabalhe com o Visual Basic. Veja como.

A solução tradicional
Para centrar os esforços nas questões fundamentais, desta vez não vamos criar
um formulário. Tudo se resolverá apenas com uma sub-rotina chamada ListaAr-
quivosDeSom. No início, o código é idêntico ao da rotina UserForm_Initialize,
discutido no capítulo anterior. Basicamente, usa-se o objeto FileSearch para lo-
calizar, num dado diretório – aqui, strDirSom –, arquivos MP3, WAV e MID.
A partir daí, as tarefas são as seguintes. Vamos criar, no diretório strDir-
Som, um arquivo de texto cujo conteúdo é a lista dos arquivos MP3, WAV e
MID encontrados. Esse arquivo deve ter a extensão M3U, usada no padrão
MP3 para armazenar listas de músicas (playlists). A estrutura de um documento
M3U é muito simples e pode ser feita até à mão. Basta abrir o Bloco de Notas e
escrever, em cada linha, o nome de um arquivo musical. O programa MP3 pla-
yer toca as músicas na ordem indicada na lista. Observe que, para tornar as coi-
sas mais simples, estamos admitindo que todas as músicas estão no mesmo dire-
tório. Assim, ao salvar o arquivo M3U também nesse diretório, cada linha dele
não precisa ter mais que o “nome líquido” do arquivo. Se a lista envolver arqui-
vos de diferentes diretórios, então será necessário incluir o caminho completo
do arquivo.
Vejamos o principal trecho da rotina:

iArq = FreeFile
Open strDirSom & “\” & “Listasom.m3u” For Output As #iArq
For i = 1 To .FoundFiles.Count
‘ Isola nome do arquivo, sem diretório
170
strNomeArq = Right$(.FoundFiles(i), _
Len(.FoundFiles(i)) - (intLenArq + 1))
‘ Letras minúsculas
strNomeArq = LCase$(strNomeArq)
Print #iArq, strNomeArq
Next i
Close #iArq

Shell strPlayer & “ ” & strDirSom & “\” & _


“listasom.m3u”, vbMinimizedNoFocus

Primeiro, abre-se um arquivo chamado Listasom.m3u, no qual serão escri-


tos os nomes dos arquivos de áudio. Em seguida, com um loop For/Next, per-
corre-se todos os nomes de arquivos encontrados. Um a um, eles vão sendo es-
critos no arquivo, com a linha

Print #iArq, strNomeArq

Concluída a listagem, fecha-se o arquivo. Agora, com a função Shell, cha-


ma-se o player, e passa-se a lista para ele. Imediatamente, o programa começa a
tocar a primeira música da lista. Você pode usar qualquer programa que suporte
os três tipos de arquivos musicais usados neste projeto. Observe que aqui, dife-
rentemente do que fizemos no capítulo anterior, usamos Windows Media Pla-
yer 2 (mplayer2.exe). Trata-se de um programa mais novo que o Media Player
tradicional do Windows. A primeira versão, que ainda vem em todas as instala-
ções do Windows 95/98, toca arquivos MP3, mas não sabe ler a lista de músicas
num arquivo M3U.

F I G U R A 2 0 . 1 Windows Media Player 2: executando um MP3

No exemplo, utilizamos o Media Player 2, tendo em vista que quase todo


usuário de Windows deve tê-lo instalado. Ele tem pelo menos uma desvanta-
gem: toca toda a seqüência de músicas mas não exibe a lista, o que qualquer
MP3 player faz. Além disso, os arquivos MP3 têm um espaço para o armazena-
mento do nome da música, artista, título do disco, ano etc. O Media Player 2
não exibe essas informações. Se você não tem nenhum desses programas, to-
dos eles são freeware ou shareware e podem ser obtidos na Internet. Eis os en-
dereços: 171
PROGRAMA FABRICANTE ENDEREÇO WEB

Windows Media Player 2 Microsoft www.windowsmedia.com

RealJukebox RealNetworks www.real.com

MusicMatch Jukebox MusicMatch www.musicmatch.com

WinAmp NullSoft www.winamp.com

Midisoft Internet Media Player Midisoft www.midisoft.com

Ao experimentar com a rotina ListaArquivos, não se esqueça de personali-


zá-la, indicando:
a) um diretório em sua máquina que contenha arquivos de áudio. Isso cor-
responde à definição da variável strDirSom:

strDirSom = “c:\mp3"

b) o endereço completo de um programa capaz de tocar esses arquivos ori-


entado por uma lista M3U. Nesse caso, ajuste o valor de strPlayer:

strPlayer = _
“c:\arquivos de programas\windows media player\mplayer2.exe”

F I G U R A 2 0 . 2 WinAmp: MP3 player com lista de arquivos


172
Para executar a rotina ListaArquivos, abra, em seu Word, o ambiente de
desenvolvimento do Visual Basic e, na janela Imediata, digite:

ListaArquivosDeSom

O resultado soará aos seus ouvidos.

Com orientação a objeto


Este bloco é última parte de uma seqüência que mostra como executar arquivos
de som WAV, MID e MP3 a partir do Word. Nesta parte nosso objetivo é bem
claro: vamos repetir o que foi feito antes, só que, desta vez, empregando recur-
sos de orientação a objeto.
Quando se fala em objeto, logo nos vêm à mente coisas com que lidamos
no dia-a-dia: carro, caneta, computador, relógio. De fato, todos esses são exem-
plos de objetos. Mas, em programação, é necessário fazer uma caracterização
um pouco mais precisa. Observe que esses exemplos correspondem, na verdade,
a categorias genéricas de objetos. Caneta é um objeto qualquer que desempenha
as funções de caneta. Idem para carro, computador, relógio.
Mas a minha caneta, esta que uso já faz alguns meses, é um caso particular
da categoria genérica caneta. Primeiro, ela tem um dono, que sou eu. Depois,
tem marca, modelo, cor externa, é de metal ou de plástico, escreve fino ou gros-
so, em preto, azul, vermelho, pode ser tinteiro ou esferográfica, pode ter aspec-
to de nova ou estar bastante arranhada... Enfim, um objeto concreto como esta
caneta que tenho agora na mão reúne uma série de características próprias – ou
seja, propriedades.
Nos dois parágrafos acima, mostramos num exemplo sucinto as idéias de
classe e objeto. A classe é uma representação abstrata. O objeto pertence à clas-
se, mas passa a ser uma entidade concreta. Dito de outra forma, a classe é uma
descrição ou a idéia genérica do objeto. Um exemplo simples. Ao projetar as ca-
sas para um conjunto habitacional do tipo Cohab, o arquiteto desenha uma uni-
dade padrão.
Com base nesse desenho, serão construídas centenas, milhares de casas
idênticas. Todas elas podem ter as mesmas características. Mas pelo menos uma
propriedade permitirá o reconhecimento individual de cada uma delas: o ende-
reço.
Para facilitar as coisas, normalmente não se faz essa distinção entre classe e
objeto: ambos são considerados objetos. Mas em programação é importante sa-
ber que um objeto é uma instância de uma classe. Se, no exemplo do arquiteto,
ele estivesse trabalhando com programação, poderíamos dizer que cada casa po-
pular é uma instância do projeto.
Ao lado de propriedades, como cor e tamanho, os objetos também execu-
tam ou sofrem ações. A casa, por exemplo, pode sofrer a operação de pintura. O
173
carro pode executar ações como mover-se, parar, dobrar à direita. Em progra-
mação, essas ações se chamam métodos.
Embora vistos sem nenhuma profundidade teórica, esses conceitos míni-
mos – classe, objeto, propriedades e métodos – serão a base sobre a qual vamos
desenvolver nosso exercício de orientação a objeto.
No Visual Basic – e praticamente em todas as linguagens modernas –, as pro-
priedades e os métodos de um objeto são apresentados com a seguinte sintaxe:

Objeto.Propriedade
Objeto.Método

Intuitivamente você já sabe disso. Considere, por exemplo, uma caixa de


texto txtNome e uma caixa de imagem imgFoto. São objetos de classe diferen-
tes, mas compartilham algumas propriedades como as que definem tamanho e
posição:

txtNome.Left = 75
txtNome.Top = 100
imgFoto.Width = 300
imgFoto.Height = 210
imgFoto.BackColor = vbYellow

Agora, vejamos alguns exemplos de ação (métodos) aplicados a esses dois


objetos. Um método óbvio é o que transfere o objeto de lugar: Move.

txtNome.Move 100, 150

Os dois números indicam as novas coordenadas Left e Top para as quais a


caixa de texto deve se deslocar. Normalmente, a propriedade é representada
por um substantivo ou um adjetivo (Height, altura; BackColor, cor de fundo;
Enabled, ativo), enquanto o método envolve um verbo: Move, Delete, Close
(mover, apagar, fechar). Algumas ações – assim como os verbos – não precisam
de complemento. Exemplo:

txtNome.SetFocus

O método SetFocus não pede nenhum complemento. Aplicado à caixa de


texto txtNome, ele transfere o foco para esse objeto. No entanto, o método
Move exige, por natureza, a informação de parâmetros. Mover para onde? Nes-
se caso, é preciso informar, no mínimo, as novas coordenadas do objeto. Mas o
ambiente de trabalho do VBA facilita bastante as coisas. Assim que você escreve
txtNome.Move e dá um espaço, uma etiqueta pop-up surge na tela,indicando os
parâmetros que o método exige:
174
F I G U R A 2 0 . 3 Etiqueta com ajuda sobre a sintaxe do método

SoundPlayer: criação de uma classe de objetos


Muito bem. Feita esta breve introdução ao mundo dos objetos, passemos à prá-
tica. Nosso objetivo, agora dito em termos de orientação a objetos, é criar uma
classe que nos permita tocar arquivos de áudio a partir do Word (ou de outro
aplicativo que dê suporte ao VBA). Reanalisemos o problema. Quais são os ele-
mentos envolvidos?
n O diretório com arquivos de áudio
n O programa que será usado para tocar esses arquivos (player)
n O nome do arquivo M3U com a lista de músicas

Além disso, quais ações devem ser executadas?

n Criar a lista de arquivos MP3, WAV e MID


n Passar essa lista ao programa (player)
Tudo indica que os objetos de nossa classe terão três propriedades e dois
métodos. Vamos em frente. Criaremos uma classe chamada SoundPlayer. Nela,
implementaremos as propriedades FileDir, Player e FileName, e os métodos
CreateList e Play. Se você não gostar dos nomes, use outros, como Pasta, Toca-
dor, NomeDoArquivo, CriarLista e Tocar – ou outros que lhe pareçam mais
convenientes. Preferimos nomes em inglês porque isso permite usar proprieda-
des como FileName, que já são comuns para outros objetos.
No ambiente de trabalho do Visual Basic, acione o comando Inserir/Mó-
dulo de Classe. O VBA cria um módulo chamado Classe1 (ou Classe2, se já exis-
tir outro com o nome Classe1) dentro da pasta Módulos de Classe. Na janela
Propriedades, mude o nome Classe1 para SoundPlayer. Agora, entremos no có-
digo da classe.
Na forma como a orientação a objeto foi implementada no Visual Basic,
cada propriedade ou cada método corresponde a pelo menos uma rotina no in-
terior da classe. Comecemos pelas propriedades. Cada uma delas exige a decla-
ração de uma variável, válida apenas no âmbito do módulo de classe. Para o mó-
dulo SoundPlayer, temos três variáveis:

Dim m_strPlayer As String ‘ propriedade Player


Dim m_strFileName As String ‘ propriedade FileName
Dim m_strFileDir As String ‘ propriedade FileDir 175
Observe que o usuário terá condições de definir o valor dessas proprieda-
des e também consultar o valor ativo delas. Portanto, é necessário que a classe
possua mecanismos para definir e para fornecer esses valores. A definição do va-
lor de uma propriedade é feita com uma rotina Property Let, seguida do nome
da propriedade. Exemplo:

Property Let FileName(strFileName As String)


‘ Define o nome do arquivo m3u
m_strFileName = strFileName
End Property

Esta rotina recebe o nome do arquivo (strFileName) e armazena-o na va-


riável local m_strFileName. O valor m_strFileName passa a corresponder à pro-
priedade FileName de qualquer objeto pertencente à classe. Recapitulando:
para definir uma propriedade, são necessários dois passos. O primeiro é decla-
rar, no módulo de classe, uma variável interna a esse módulo. O outro consiste
em criar uma rotina Property Let <nome da propriedade>, na qual aquela va-
riável interna assume um valor externo, enviado por um programa que esteja
usando os serviços da classe.
Naturalmente, esse programa também pode querer consultar o valor atual
da propriedade. Para permitir isso, é preciso criar, na classe, uma rotina Pro-
perty Get <nome da propriedade>. A rotina Property Get é, por assim dizer, o
inverso de Property Let:

Property Get FileName() As String


‘ Fornece o nome do arquivo m3u
FileName = m_strFileName
End Property

Agora, a propriedade FileName, que se expõe para fora do módulo de clas-


se, assume o valor da variável interna mstrFileName. Assim, se o programa per-
guntar, a classe responderá com o valor da propriedade. Nem sempre é possível
ou necessário haver uma rotina Let e outra Get. Afinal, existem propriedades
que só podem ser lidas – não admitem atribuição de valor. Você não pode, por
exemplo, modificar o valor do sistema operacional ou do processador da má-
quina. Se essas variáveis fizessem parte de uma classe, teriam apenas a rotina
Property Get.
Muito bem, você já viu como criar as rotinas referentes a cada proprieda-
de. Avancemos, agora, para as rotinas associadas aos dois métodos de nosso pro-
jeto: CreateList e Play. Como esses métodos podem ser chamados a partir de
procedimentos fora do módulo de classe, então as rotinas correspondentes de-
vem começar com a palavra-chave Public. Conseqüentemente, procedimentos
auxiliares, internos à classe, devem ser marcados com a palavra-chave Private.
Um exemplo de rotina auxiliar interna à classe é a sub TrataErros. Chamada por
176
outros procedimentos internos, ela cuida apenas de exibir uma mensagem quan-
do ocorre um erro.
Analisemos a rotina CreateList. Sua tarefa essencial é criar o arquivo M3U
que contém a lista de arquivos de som. Essa rotina, na verdade, é uma variação
do que já vimos neste capítulo, no formato de programação tradicional. Chamo
a atenção apenas para uma novidade: em mais de um ponto do código aparece a
palavra-chave Me. Ela é uma forma de referência implícita à própria classe.
Quando se usa Me.FileDir, refere-se ao valor da propriedade FileDir. Lembre-se
de que Me também é usada nos formulários. A instrução Unload Me, por exem-
plo, retira da memória o formulário dentro do qual ela é usada. Na classe
SoundPlayer, em lugar de Me.FileDir, também seria correto utilizar a variável
interna m_strFileDir.
Passemos ao outro método, Play. Ele é mais simples que CreateList. Sua ta-
refa é pegar o arquivo M3U e apresentá-lo ao programa (player). Naturalmente,
para que isso funcione, é necessário que, antes, as três propriedades já tenham
sido definidas: o nome do player, o nome do arquivo M3U e o diretório onde
estão os arquivos musicais.

With Me
If .Player = “” Or .FileDir = “” Or .FileName = “” Then
s = “Antes de usar o método Play, é preciso ”
s = s & “definir as propriedades FileDir e ”
s = s & “Player do objeto SoundPlay.”
MsgBox s, vbCritical, “Objeto SoundPlay”
Exit Sub
End If
End With
Shell Me.Player & “ ” & Me.FileDir & “\” & Me.FileName, _
vbMinimizedNoFocus

Em outras palavras, o método Play só pode ser chamado depois da defini-


ção das propriedades e da criação do arquivo M3U (método CreateList). No
entanto, como o programador pode esquecer este detalhe, antes de tentar en-
viar informações ao player, testamos se os valores das propriedades Player, Fi-
leDir e FileName já foram definidos. É o que faz a instrução If, no trecho de
código acima.
Para encurtar caminho e reduzir a possibilidade de erro, usamos um pe-
queno truque em relação à propriedade FileName. Já vimos que ela deve ser de-
finida de fora para dentro, o que é feito mediante a rotina Let FileName. Contu-
do, o nome do arquivo M3U não precisa variar. Então, adicionamos a seguinte
linha de código à rotina Class_Initialize da classe SoundPlayer:

Me.FileName = “listasom.m3u”
177
Assim como a rotina UserForm_Initialize, dos formulários, Class_Initialize
deve conter todas as definições iniciais da classe. Em nosso exemplo, a proprie-
dade FileName é definida, como padrão, para o valor “listasom.m3u”. Portan-
to, se não for indicado um nome para o arquivo, esse nome já estará definido.

Como usar a classe SoundPlayer


A construção da classe SoundPlayer está terminada. Mas uma classe não é como
uma função ou uma sub-rotina que você, simplesmente, chama quando necessá-
rio. Há uma forma específica de trabalhar com ela. Para demonstrar essa forma,
vamos criar um formulário chamado frmSoundPlay (Figura 20.4).

F I G U R A 2 0 . 4 O formulário frmSoundPlay: uso da classe


SoundPlayer

Como controles fundamentais, esse formulário tem duas caixas de texto e


dois botões, associados dois a dois. A primeira caixa de texto (txtDir) associa-se
ao botão cmdProcurarDir. A outra (txtExe) trabalha em conjunto com o botão
cmdProcurarExe. Você já percebeu: o usuário pode digitar nas caixas de texto o
diretório dos arquivos de som e o caminho do programa player. Mas, se quiser,
pode também clicar no botão de comando para localizar o diretório e o arquivo
com uma caixa de diálogo do Word (janelas Cópia e Abrir). Restam os botões
Cancelar, que não requer explicação, e OK, que dispara a execução dos arqui-
vos musicais. Há ainda o botão Volume. Trata-se de um objeto acessório que
abre o controle de Volume (Sndvol32.exe) do Windows.
A parte externa do formulário está vista. Passemos para dentro. Vejamos as
rotinas ligadas aos botões cmdProcurarDir e comdProcurarExe. O botão
cmdProcurarDir abre a caixa de diálogo Cópia, que localiza diretórios:

Private Sub cmdProcurarDir_Click()


‘ Captura o diretório dos arquivos de som
178
Dim strPasta As String

If Dialogs(wdDialogCopyFile).Display = -1 Then
strPasta = Dialogs(wdDialogCopyFile).Directory

If strPasta <> “” Then


If Right$(strPasta, 1) = “\” Then
strPasta = Left$(strPasta, Len(strPasta) - 1)
End If
txtDir = strPasta
End If
End If
End Sub

Nesse caso, para abrir a caixa usa-se o método Display, e não o método
Show. A diferença é que exibe a caixa de diálogo e não executa nada. Serve ape-
nas como um objeto no qual o usuário escolhe um diretório. O valor fornecido
pela caixa de diálogo Cópia é transferido para a caixa txtDir. As linhas adicio-
nais no procedimento devem-se a um teste preventivo. Esse teste verifica se o
nome do diretório termina em barra invertida e elimina-a. Evita-se, assim, que
apareçam duas barras na hora de combinar diretório e nome do arquivo.
O botão cmdProcurarExe exibe a caixa de diálogo Abrir, que lista arqui-
vos.

Set dlg = Dialogs(wdDialogFileOpen)


dlg.Name = “*.exe”
If dlg.Display = -1 Then
txtExe = Options.DefaultFilePath(wdDocumentsPath) _
& “\” & dlg.Name
End If

O código acima faz com que a caixa Abrir mostre apenas os arquivos do tipo
EXE, já que o arquivo procurado é um executável. OK. O arquivo executável in-
dicado pelo usuário é transferido para a caixa txtExe. Mas as coisas acontecem,
mesmo, quando o usuário clica no botão OK. Vamos transcrever a rotina inteira:

Private Sub cmdOK_Click()

If Len(txtDir) <> 0 And Len(txtExe) <> 0 Then


Dim sp As SoundPlayer
Set sp = New SoundPlayer

sp.FileDir = txtDir
sp.Player = txtExe
sp.CreateList 179
sp.Play
Set sp = Nothing
Unload Me
Else
MsgBox “Preencha os dois campos.”, vbCritical, _
“Objeto SoundPlayer”
End If

End Sub

Primeiro, a rotina verifica se as duas caixas de texto foram preenchidas.


Em caso negativo, emite um aviso para o usuário e interrompe o programa. Em
caso positivo, segue em frente. Aqui começamos a lidar com nossa classe Sound-
Player. Primeiro, é preciso declarar uma variável qualquer como sendo do tipo
SoundPlayer. Ou seja, como a classe existe no ambiente do Word, ela passa a ser
um tipo de variável-objeto.

Dim sp As SoundPlayer

Depois, indica-se que a variável sp é uma instância da classe SoundPlayer.


Assim:

Set sp = New SoundPlayer

A partir de agora, você pode efetuar todas as operações suportadas pelo


objeto sp, pertencente à classe SoundPlayer. Que operações são essas? Há ape-
nas cinco, como você já sabe: três referem-se à definição de propriedades, e duas
são métodos de ação. No caso das três propriedades há, de fato, seis operações:
três definem valores e as outras três lêem esses valores.
Como vimos no início deste capítulo, as referências a métodos e proprie-
dades são sempre feitas com o nome do objeto e o nome do método ou proprie-
dade unidos por um ponto. Então, para tocar a seqüência de músicas, basta es-
crever quatro linhas:

sp.FileDir = txtDir
sp.Player = txtExe
sp.CreateList
sp.Play

As duas primeiras definem propriedades. As duas últimas executam méto-


dos. Lembre-se: usamos apenas duas das três propriedades. A terceira, FileNa-
me, foi deixada com o nome padrão: “listasom.m3u”. Preste atenção na linha a
seguir:

180 Set sp = Nothing


Concluídas as tarefas, não há mais necessidade de lidar com o objeto sp,
instância de SoundPlayer. Então, use a fórmula Set objeto = Nothing para des-
vincular a variável (no caso, sp) da classe (SoundPlayer). É importante fazer isso
para liberar memória. Neste exemplo, chamamos o objeto de sp. Alguns autores
recomendam que as variáveis de objeto sejam nomeadas com prefixos que facili-
tem a identificação. Em geral, aconselha-se que comecem com um “o” minúscu-
lo ou com o prefixo “obj”. Por essa regra, você poderia chamar sp de objSP ou
oSP, ou oSoundPlayer.
Um detalhe interessante. Quando você digita, no código, uma chamada a
funções ou sub-rotinas escritas por você mesmo, o ambiente do VBA apresenta a
etiqueta de ajuda com os parâmetros esperados pela rotina. O mesmo ocorre
com as classes. Depois que você cria nova instância de um objeto, o ambiente
exibe todos os métodos e propriedades associados a ele:

F I G U R A 2 0 . 5 O VBA assume a classe que você cria

Outro detalhe: no formulário, para economizar digitação, defini o valor


inicial das caixas de texto para o diretório e o player desejados. Isso está na roti-
na UserForm_Initialize. Assim, você só vai precisar digitar quando o diretório
ou o player for diferente. Na maioria dos casos, basta clicar no botão OK.
Agora, você deve estar pensando: mas qual a vantagem dessa história com-
plicada de classes e objetos? As vantagens são muitas, mas fiquemos com as mais
evidentes:
1. A facilidade para o programador que vai usar os serviços oferecidos pela
classe. Observe que, em nosso exemplo, todas as operações se resumi-
ram em declarar o objeto e chamar métodos ou propriedades. Tudo em
meia dúzia de linhas. Talvez o exemplo mostrado aqui não seja o mais
adequado para dar idéia dessa facilidade. Afinal, construímos o projeto
181
com base num código que você já conhecia bem. Mas no interior de uma
classe podem ocorrer processamentos supercomplexos que, no final, se
transformam em métodos e propriedades. Pense de outro modo: você
não precisa saber o que ocorre lá dentro de SoundPlayer. O certo é que,
com ela, você toca música com algumas linhas de um código muitíssimo
simples.
2. Reutilização de código. Você pode reutilizar funções e outras rotinas.
Basta copiá-las de um projeto e colá-las em outro. A utilização de obje-
tos facilita esse processo. Salve a classe em disco: selecione o módulo e
acione o comando Arquivo/Exportar Arquivo. Você terá um documen-
to com extensão CLS. Para incluí-lo em outro projeto, importe a classe.
Se o código estiver bem depurado e funcionando corretamente, você vai
poder reutilizar a classe numerosas vezes, sem voltar a abri-lo. No iní-
cio, pode dar trabalho. Depois, tudo fica mais fácil.

Para ir mais além


1. Testei a rotina ListaArquivosDeSom com os programas Media Player 2,
do Windows, WinAmp e MusicMatch Jukebox. Com este último não
funcionou. O programa é aberto, mas não entende o nome do arquivo
que lhe é passado. Então, nada acontece. Com os outros dois, tudo fun-
ciona corretamente. Um lembrete: se o Media Player já estiver aberto,
você receberá uma mensagem de erro.
2. Modifique o formulário frmSoundPlay para que o usuário tenha condi-
ções de indicar, também, o nome do arquivo M3U. Assim, ele poderia
ter diferentes programações musicais, cada uma contida num arquivo
M3U.
3. No método CreateList, experimente trabalhar com o nome completo
do arquivo. Isso possibilitará criar listas com arquivos musicais localiza-
dos em diferentes diretórios.
4. Estude a possibilidade de carregar a lista M3U num controle ListBox e
reordenar a seqüência das músicas. Veja um exemplo de reordenação
do conteúdo de listas no Capítulo 34, dedicado à criação de um assisten-
te de banco de dados.
5. Como exercício de programação, pense em criar outras classes úteis. Dê
preferência a criar objetos que resumam códigos que, volta e meia, você
precisa revisitar. Um exemplo que me ocorre é criar um objeto para exi-
bir as janelas Abrir e Cópia (e talvez outras caixas de diálogo do Word) e
retornar o arquivo ou o diretório selecionado pelo usuário. Esse assunto
é um candidato óbvio. Basta você contar as vezes que essa operação se
repete nos projetos deste livro.
182
Protetor de tela
Quer abrir um protetor de tela do Windows a partir de um programa
VBA? É fácil: use o seguinte procedimento, naturalmente adaptando o
nome do arquivo SCR:

Sub AcionaSCR()
Dim n As Long
n = Shell(“c:\windows\system\oceano.scr /s”, _
vbNormalFocus)
End Sub

Botões OK e Cancelar
No VBA, os formulários funcionam como caixas de diálogo. Portanto,
para seguir o padrão, o botão OK (ou equivalente) deve ter sua pro-
priedade Default ajustada para True. Também por causa do padrão, o
botão Cancelar (ou Fechar) deve ter a propriedade Cancel = True. Com
isso, se o usuário pressionar a tecla Enter, acionará OK. Se pressionar
Esc, fechará o formulário pela ação do botão Cancelar. Esta não é uma
regra absoluta, mas pode ser aplicada na maioria dos casos.

O público e o privado
Você deve ter estranhado, neste projeto, o nome das variáveis m_strFi-
leName, m_StringFileDir e m_strPlayer. Esse prefixo, m_, é usado para
indicar que a abrangência da variável é interna ao módulo. Em qual-
quer situação, isso é importante, em especial quando se está traba-
lhando com projetos grandes e desenvolvidos por mais de um progra-
mador, onde é maior a possibilidade de confusão. Em programação
orientada a objeto, identificar a abrangência das variáveis tem peso
ainda maior. Constitui um princípio básico isolar os métodos e proprie-
dades, que são públicos, dos valores internos de uma classe, que de-
vem ser estritamente privados.

183
21
Mala direta num
clique

Produza cartas personalizadas com dados


do Word, do Access ou do Excel

Ficha do projeto
Projeto:

Mala Direta

O que faz:

Prepara documentos e etiquetas personalizadas com uma


carta-modelo do Word e fontes de dados do Access, do
Excel e do próprio Word.

Arquivos e requisitos do projeto:

Formulário frmMalaDireta e código interno.

Conhecimento técnico:

Uso do VBA/Word para abertura de fontes de dados para


mala direta.
Esquemas para manipulação gráfica de controles em
formulários.
Para experimentar o programa, você pode usar os
seguintes arquivos:
Documentos-base: Cartabd2.dot, Cracha3.dot
Fontes de dados: Wdimport.doc, Clientes.mdb, Plclient.xls

Nível de programação:

Intermediário
Você sabe como emitir uma mala direta via VBA? Não é difícil. O projeto de que
trata este capítulo demonstra como fazer isso a partir de três fontes de dados dis-
tintas: um documento do Word, um banco de dados Access e uma planilha
Excel. Para utilizar este aplicativo, como em qualquer atividade de mala direta,
você precisa ter a carta-modelo e a fonte de dados. A mesclagem das informa-
ções provenientes desses dois documentos é que vai produzir o resultado final
da mala direta.
A carta-modelo, você sabe, é o documento que contém os campos de mala
direta, os quais serão substituídos, adequadamente, por informações extraídas da
fonte de dados. Naturalmente, os campos nesse documento devem corresponder
nominalmente aos campos da fonte de dados. A Figura 21.1 mostra um exemplo
de como se apresentam os campos no documento-base para a mala direta.

F I G U R A 2 1 . 1 Na oval em destaque, os campos da


carta-modelo para mala direta

Para inserir os campos de dados num documento do Word, você precisa


primeiro saber os nomes dos campos na fonte de dados. Com isso, aciona-se
Inserir/Campo e, na tela seguinte, escolhe-se Mala Direta e MergeField. Na cai-
xa Códigos de Campos, deve-se então digitar o nome do campo desejado (Figu-
ra 21.2). Essa operação repete-se para cada campo, durante a elaboração da car-
ta-padrão.
Concluída a carta modelo, pode-se salvá-la como um documento DOT
(modelo) ou como um DOC. A decisão depende de alguns detalhes. Se você pre-
tende usar continuadamente essa carta-padrão, o melhor é salvá-la como mode-
lo. Se, no entanto, a intenção é utilizá-la uma única vez, o melhor é escolher o
DOC. Modelo ou documento simples, ambos servem como base para a emissão
de malas diretas. 185
E a fonte de dados? Esta, entre outras possibilidades, pode ser um docu-
mento Word, uma base de dados Access ou uma planilha Excel. Em geral, o do-
cumento Word consiste numa tabela cuja primeira linha indica os nomes de
cada coluna. Passemos, então, ao projeto.

F I G U R A 2 1 . 2 Inserção de campos no documento-padrão

O aplicativo Mala Direta contém um único formulário, frmMalaDireta


(Figura 21.3), com os seguintes controles:
n os clássicos botões de comando OK (cmdOK) e Cancelar (cmdCan-
celar);
n uma moldura com quatro botões de opção (opt1 a opt4), correspon-
dentes às fontes de dados que o usuário pode escolher;
n duas caixas de texto, txtDoc e txtFonteDados, com dois botões de co-
mando associados: cmdProcurarDoc e cmdProcurarFonte. Nessas cai-
xas o usuário deve indicar, respectivamente, o documento-base para a
mala direta e a fonte de dados. Os botões de comando exibem a caixa de
diálogo Abrir, para que o usuário possa navegar na árvore de diretórios
e indicar os arquivos sem digitar; e
n uma caixa de texto, txtComplemento, na qual deve ser digitado uma in-
formação complementar, conforme a fonte de dados escolhida.

186
F I G U R A 2 1 . 3 O formulário frmMalaDireta, exibindo todos os
controles

Tratemos, primeiro, do funcionamento desse formulário. Cada fonte de da-


dos escolhida implica um tipo de arquivo e, se for o caso, um tipo específico de
complemento. A tabela abaixo lista todas as possibilidades cobertas pelo programa.

FONTE DE DADOS TIPO DE ARQUIVO COMPLEMENTO

Documento do Word DOC, com tabela na Nenhum


com tabela qual o primeira linha
contém os nomes dos
campos

Banco de dados Access – MDB Nome da tabela que é a


Tabela verdadeira fonte de
dados

Banco de dados Access – MDB Declaração SQL para


SQL filtrar registros de uma
ou mais tabelas do
banco de dados

Pasta de trabalho XLS – XLS Nome da planilha (folha


Planilha de dados) que contém as
informações desejadas

O formulário frmMalaDireta tem algumas características que o tornam


compatível com as diferentes características das fontes de dados. A fonte padrão
é o documento do Word. Assim, quando o programa se inicia, o usuário não vê
a caixa de texto txtComplemento, porque ela é desnecessária nesse caso. 187
F I G U R A 2 1 . 4 O formulário, com a opção-padrão: documento
do Word

Não é necessário exigir a caixa na qual o usuário deveria digitar o comple-


mento, já que a opção Fonte de dados (arquivos DOC) dispensa esse comple-
mento. No entanto, quando se clica em qualquer outra alternativa de fonte de
dados, a caixa txtComplemento aparece, como na Figura 21.3. Os rótulos asso-
ciados às caixas de texto txtFonteDados e txtComplemento também se modifi-
cam, conforme a fonte de dados escolhida. Essa movimentação é garantida pela
rotina Click de cada botão de opção. Aqui, o exemplo da sub opt3_Click:

Private Sub opt3_Click()


m_intOpcao = 3
m_strCuringa = “*.mdb”
If Right(txtFonteDados, 3) <> “mdb” Then _
txtFonteDados = “”
labComplemento = “Sentença SQL:”
labFonteDados = “Fonte de dados (arquivo MDB):”
ExibeOcultaControles True
End Sub

A rotina ExibeOcultaControles garante que a caixa de texto txtComple-


mento e o rótulo labComplemento fiquem ocultos quando a fonte de dados é
um documento do Word (opção 1), e se tornem visíveis nas outras situações.
Mas o que interessa, de fato, vem depois que o usuário clica no botão OK.
Em primeiro lugar, o programa testa se as caixas de texto (duas ou três) estão de-
vidamente preenchidas. No caso de preenchimento com nomes de arquivos, o
188 devidamente implica a existência do arquivo. As funções TestaPreenchimento,
ArquivoExiste e EscolherArquivo dão uma ajuda nesse processo. Escolher-
Arquivo exibe a caixa de diálogo Abrir, do Word, para que o usuário possa indi-
car o arquivo sem digitá-lo. Se ele fizer isso, passará, tranquilamente, nos testes
das outras duas funções. ArquivoExiste verifica se o conteúdo das caixas de tex-
to txtDoc e txtFonteDados corresponde, realmente, a um arquivo. Por fim, Tes-
taPreenchimento centraliza os testes, solicitando inclusive os serviços de Arqui-
voExiste. Se algo irregular é detectado, o programa avisa ao usuário e pára.
Quando tudo está normal, o botão cmdOK chama a rotina ProduzDocMa-
laDireta. Esta é, na verdade, a parte do programa que faz acontecer. Produz-
DocMalaDireta recebe quatro parâmetros:
n intFonte, o índice da fonte escolhida pelo usuário;
n strTemplate, o caminho completo do arquivo com a carta-padrão;
n strFonte, o caminho completo do arquivo da fonte de dados; e
n varComplemento, tabela, planilha ou sentença SQL, conforme a fonte
de dados.
Com relação a varComplemento, vale destacar dois aspectos. Primeiro:
trata-se de um parâmetro opcional. Portanto, não precisa ser incluído, obrigato-
riamente, na chamada da rotina. Isso permite que, quando a fonte de dados é
um documento do Word, a chamada não inclua esse parâmetro. O segundo as-
pecto está na chamada:

ProduzDocMalaDireta m_intOpcao, txtDoc, _


txtFonteDados, txtComplemento.Text

Oberve que o conteúdo de outras caixas de texto é passado com o nome do


controle (txtDoc, txtFonteDados). Todavia, se você usar txtComplemento, vai
provocar um erro. Isso porque o tipo de dados esperado por ProduzDocMala-
Direta é variant. O nome do controle causa confusão porque a rotina (na verda-
de, o método OpenDataSource) fica sem saber se se trata do objeto ou do conte-
údo dele. Para evitar dúvidas, use txtComplemento.Text. Outra alternativa se-
ria criar uma variável de texto (string), associar a ela o valor do texto em
txtComplemento e enviar essa variável.
Concluída a mesclagem dos dados, ProduzDocMalaDireta fecha a car-
ta-modelo, fecha o formulário e deixa na tela apenas o documento final:
Você pode usar como carta-padrão não apenas cartas, no sentido estrito.
Valem também documentos como etiquetas de endereçamento e crachás. Para
esses últimos documentos, existem no mercado etiquetas pré-formatadas, algu-
mas das quais estão listadas no Word (Ferramentas/Mala Direta/Criar/Etiquetas
de Endereçamento).
A dica para elaborar crachás e etiquetas ilustradas, como as exibidas na Fi-
gura 21.5, é produzir o documento básico e depois incluir os objetos e formata-
ções na primeira etiqueta (na verdade, a célula de uma tabela). Em seguida, basta 189
copiar o conteúdo dessa célula e colar nos demais. Observe que a primeira célula
contém o campo de dados NomeCliente (veja o arquivo Cracha3.dot). Nas de-
mais, esse campo é sempre precedido pelo campo Próximo. Isso garante que
cada etiqueta ou crachá corresponderá a um novo registro.

F I G U R A 2 1 . 5 Etiquetas ou crachás ilustrados: uma das


possibilidades da mala direta

F I G U R A 2 1 . 6 Estrutura dos campos para etiquetas ou crachás


com imagem e formatação

Por fim, um detalhe: ao contrário do que ocorre com os projetos desenvol-


vidos nos Capítulos 28 a 31 e 33-34, você precisa ter o Access ou o Excel em sua
190 máquina para executar essas operações de mala direta. De todo modo, quem
não possui esses dois programas pode trabalhar com tabelas do Word (veja o do-
cumento wdimport.doc), ou mesmo criar e acessar bancos de dados Access via
programação (busque a ajuda do VBA sobre o método CreateDatabase, do
DAO – Data Access Objects).

Para ir mais além


1. Entre todos os projetos deste livro, Mala Direta é um dos mais “ampliá-
veis”. Você pode modificá-la de inúmeras formas: para incluir opções
do método OpenDataSource não tratados aqui (banco de dados prote-
gidos por senhas, por exemplo), para criar nova interface ou, simples-
mente, para redesenhar a interface do programa.
2. Mala Direta é um projeto que se adaptaria como uma luva à criação de
um assistente. O assistente (veja um exemplo no Capítulo 34) é um tipo
de programa que guia o usuário, passo a passo, para concluir uma tare-
fa. Aqui, pode-se pensar no seguinte esquema:
n Passo 1 – O usuário escolhe o documento-base.
n Passo 2 – Escolha do tipo de fonte de dados.
n Passo 3 – Localização do arquivo da fonte de dados.
n Passo 4 – Indicação do complemento, conforme a fonte escolhida.
n Fim – Emissão do documento com os dados mesclados.
3. Se você tem o Office 2000 e resolve experimentar o projeto Mala Direta
com o banco de dados Clientes.mdb, fornecido como exemplo, vai re-
ceber a seguinte mensagem ao operar o programa:

F I G U R A 2 1 . 7 Aviso do Access 2000: o banco de dados é de


versão anterior

Simplesmente acione OK. Essa mensagem é normal. De fato, o banco de


dados Clientes.mdb foi construído com o Access 97. Preferi mantê-lo nessa ver-
são para que tanto usuários do Office 2000 como do Office 97 pudessem usar o
programa. Observe um detalhe: em outras aplicações deste livro, o mesmo ban-
co de dados é utilizado e essa mensagem não aparece. Por quê?
191
Como foi dito no capítulo, a operação de mala direta exige a presença do
Access, que é o responsável por esse aviso. Nos outros casos (por exemplo, nos
Capítulos 28, 30 e 34) o projeto manipula banco de dados, por meio das biblio-
tecas DAO. Estas usam os princípios de programação do Access mas não preci-
sam do programa, para funcionar.

Automação
Por meio da Automação – antes chamada Automação OLE –, você
pode trabalhar com outros programas em seus projetos tratando-os
como objetos. Naturalmente, para que isso seja possível é necessá-
rio que o programa dê suporte a essa tecnologia. Veja a seguir um
exemplo com o Excel. O código abaixo declara o programa como um
objeto, abre-o e, em seguida, manipula o programa por meio desse
objeto.
O procedimento abre um arquivo, seleciona a primeira planilha
da pasta de trabalho e, nela, a célula (1,1). Em seguida, apresenta
numa mensagem o valor dessa célula e fecha o programa.

Sub AbrirExcelViaAutomação()
On Error GoTo ExcelAuto_Err
Dim objXL As Object

Set objXL = CreateObject(“Excel.Application”)


objXL.Visible = True
objXL.Workbooks.Open “c:\solucoes\plclient.xls”
objXL.Worksheets(1).Cells(1, 1).Select
MsgBox objXL.Worksheets(1).Cells(1, 1).Value
objXL.Quit

Set objXL = Nothing

ExcelAuto_Fim:
Exit Sub
ExcelAuto_Err:
MsgBox Err.Description
Resume ExcelAuto_Fim
End Sub

A última linha do procedimento destrói o objeto criado com


CreateObject. Não se esqueça de incluir esse comando (Set Object
= Nothing) para garantir a liberação da área de memória ocupada
pelo objeto.
192
22
No comando de
todas as barras

Uma aplicação que lista todas as barras


de menus e de ferramentas do Word

Ficha do projeto

Projeto:

Barras de Comandos

O que faz:

Esta aplicação relaciona todas as barras de comandos


(ferramentas, menus) disponíveis no Word. Oferece ainda
uma forma de visualizar esses objetos e de gerar um
documento com uma lista de suas principais propriedades.

Arquivos e requisitos do projeto:

Formulário frmBarrasComandos e código interno.

Conhecimento técnico:

Manipulação das coleções de barras de comandos do


Word.

Nível de programação:

Intermediário
Assim como os estilos, as fontes, os documentos e uma longa série de outros
itens, as barras de comando, no Word, também constituem uma coleção de ob-
jetos – a coleção CommandBars. Esse conjunto de recursos envolve três tipos de
objetos:
n barra de menus
n barra de ferramentas normal
n barra de ferramentas pop-up
Naturalmente, as barras de menus e as barras de ferramentas são, dos três,
as classificações mais populares. Para tentar uma diferenciação simples, a barra
de menu é uma barra de ferramentas que, em lugar de botões e caixas de combi-
nação, traz apenas opções de menu. As barras de ferramentas pop-up compreen-
dem barras como Formas, AutoFormas, Setas Largas, Fluxogramas e Linhas.
Em geral, o termo barra de comandos engloba os seguintes itens:
n barras de menus, barras de ferramentas e menus de atalho
n menus em barras de menus e barras de ferramentas
n submenus em menus, submenus e menus de atalho
Para demonstrar como o VBA lida com as barras de comando, desenvolve-
mos um aplicativo chamado Barras de Comandos que trabalha com as principais
propriedades desses objetos. O programa exibe uma lista de todas as barras dis-
poníveis no ambiente do Word.
O projeto compreende apenas um formulário e seu código interno. Esse
formulário (frmBarrasComandos) contém uma caixa de listagem (lstBarras), um
rótulo (labNumBarras), dois botões de comando principais – Exibir Barra
(cmdExibir) e Ocultar Barra (cmdOcultar) – e dois botões de opção – Nome Local
e Nome (opt1 e opt2). Adicionalmente, há ainda um botão Fechar (cmdFechar)
e um rótulo Exibir Dica/Não Exibir Dica (labToolTip) que, clicado, funciona
como indicador/comutador para exibir ou ocultar uma dica a respeito da barra
selecionada na caixa lstBarras. Também está no formulário o botão de comando
Produzir Lista Doc (cmdProduzir), que gera um documento com a relação de to-
das as barras de ferramentas e suas principais propriedades. Há ainda o rótulo
Controles da Barra (labControlesBarra), que exibe a lista de controles existentes
na barra de comandos, selecionada na caixa de listagem.
Como funciona o programa? Ao entrar em ação, ele exibe, na caixa lstBar-
ras, a lista de todas as barras de comando disponíveis no Word. Os itens, portan-
to, variam se o seu Word é 97 ou 2000, ou se você criou barras personalizadas.
Ao rodar o Barras de Comandos em meu Word 2000, ele aponta a existência de
109 barras, das quais – verifico – somente duas são pessoais (ou seja, foram cria-
das por mim, não vieram embutidas no programa). Para exibir uma barra de fer-
ramentas, deve-se selecionar o nome dela na caixa de listagem e acionar o botão
Exibir Barra. Para ocultá-la, pressiona-se o botão Ocultar Barra.
194
F I G U R A 2 2 . 1 A tela da aplicação: exibir, ocultar e listar barras

Os botões de opção Nome Local e Nome fazem a caixa de lista mostrar,


respectivamente, o nome da barra de comando em português e no original, em
inglês. Naturalmente, as barras que você cria têm o mesmo nome nos dois casos.
Por fim, vem a etiqueta Exibir Dica/Não Exibir Dica. Esse rótulo tem o papel
duplo de comutador e indicador. Na primeira função, ao receber um clique, liga
ou desliga a exibição da dica, no controle lstBarras. Na outra, indica, em sua
propriedade Caption, a função ativa: Exibir Texto ou Não Exibir Texto.
Quando o usuário clica no rótulo Controles da Barra, abre-se uma caixa de
mensagem com a lista de todos os controles disponíveis na barra selecionada.
Observe que os rótulos ExibirDica e Controles da Barra poderiam muito bem
ser botões de comando. Contudo, achei que os botões para os dois casos deveri-
am ser menores. Infelizmente, os objetos CommandButton do VBA têm uma li-
mitação: não aceitam redução de sua altura abaixo de certo valor, sem esconder
a legenda. Como os rótulos não apresentam esse problema, resolvi ficar com
eles, fazendo-os parecer botões (propriedade SpecialEffect igual a fmSpecialE-
ffectRaised = 1).

O código
O primeiro movimento do programa é preencher a caixa lstBarras com a lista
das barras de comandos disponíveis no ambiente do Word. Para isso, é chamada
à ação a rotina ExibirLista. Esta rotina recebe um parâmetro inteiro que indica
se ela deve mostrar as barras com o nome original (propriedade Name) ou com
o nome em português (propriedade NameLocal). Os valores – atribuídos arbi-
trariamente – são 1 para NameLocal e 2 para Name. Assim, ExibirLista define o
que fazer a partir desse parâmetro. Em ambos os casos, a ação básica é percorrer
a coleção de objetos CommandBars:
195
For n = 1 To CommandBars.count
lstBarras.AddItem n & “ ” & CommandBars(n).NameLocal
Next n

O que varia, aí, é apenas a propriedade: NameLocal ou Name. ExibirLista


convoca o trabalho de outra rotina, DefinirToolTip. Esta recebe um parâmetro
booleano. Se verdadeiro, a dica será exibida. Se falso, a propriedade Control-
TipText de lstBarras é anulada – ou seja, reduzida a uma string nula:

lstBarras.ControlTipText = “”

A definição dessa string, quando não nula, é uma lista de valores das pro-
priedades da barra de comandos escolhida. Essa lista, separada por pon-
tos-e-vírgulas, reúne:
n Propriedade NameLocal, se a listagem está em inglês; ou Name, em
caso contrário;
n Propriedade BuiltIn (Verdadeiro/Falso) – Indica se a barra é própria do
Word ou criada externamente;
n Propriedade Visible (Verdadeiro/Falso) – Indica se a barra está visível
no momentoP;
n Propriedade Type – Informa se a barra é do tipo msoBarTypeNormal
(0), msoBarTypeMenuBar (1) ou msoBarTypePopup (2).
A dica a ser exibida é definida quando se seleciona uma barra de ferramen-
tas na lista de lstBarras. Depois, basta deixar o cursor do mouse por alguns se-
gundos sobre lstBarras para provocar a exibição da dica. Adicionalmente, po-
de-se dar um duplo clique no nome da barra para mostrar uma mensagem com a
discriminação de todas as propriedades da barra selecionada.

F I G U R A 2 2 . 2 Resumo de propriedades da barra Cabeçalho e


196 Rodapé
As outras operações executadas pelo programa dependem da intervenção
do usuário. Os botões Exibir Barra e Ocultar Barra cumprem suas funções, gra-
ças ao trabalho da rotina ExibirOcultar. Esta recebe dois parâmetros: blnExibir
(True/False), que sinaliza exibir ou ocultar; e lngPos, um inteiro longo opcional,
usado para indicar a posição em que a barra deve ser exibida na tela no caso de
blnExibir=True. Essa posição é expressa por uma das seguintes constantes in-
trínsecas:

CONSTANTE VALOR POSIÇÃO

msoBarLeft 0 À esquerda

msoBarTop 1 No alto

msoBarRight 2 À direita

msoBarBottom 3 Na parte inferior

msoBarFloating 4 Flutuante

msoBarPopup 5 Pop-up

msoBarMenuBar 6 Barra de menu

Não importa se a operação consiste em exibir ou ocultar a barra seleciona-


da: o eixo da atividade é definido por este mesmo trecho de código:

With CommandBars(n)
.Visible = blnExibir
.Position = lngPos
End With

O valor n, no caso, corresponde ao índice da barra indicada na coleção


CommandBars. Se a chamada ao procedimento passa um valor para lngPos, en-
tão a barra é exibida na posição indicada; se nenhum valor é passado, o padrão é
mostrar a barra na parte superior da janela. Ou seja, o valor-padrão é msoBar-
Top. Em muitos casos, o comando para tornar a barra visível/invisível vai pro-
duzir um erro: “Não é possível exibir/ocultar a barra indicada”. Na maioria das
vezes, isso vai ocorrer durante as tentativas de exibir (e não de ocultar) a barra.
Esse é o comportamento normal. Lembre-se, por exemplo, de que a maio-
ria das barras de comando só se apresenta dentro de um contexto específico. A
barra Editar Figura, por exemplo, só aparece quando há uma figura selecionada.
Restrições similares ocorrem com Cabeçalho e Rodapé, Mala Direta, Tabelas e
numerosas outras barras.
O botão Produzir Lista Doc, como vimos, gera um novo documento
Word, com a lista das barras de comandos e todas as suas principais proprieda-
197
des. Nessa operação, o texto é “digitado” com o método TypeText e depois
convertido em tabela.
Um aspecto interessante a destacar nesta aplicação é que, se você extrair o
código associado ao botão Produzir Lista Doc, ela assume as características do
programa em que estiver hospedada. Isso significa que é possível exportar o for-
mulário e fazê-lo rodar, sem nenhuma modificação (com exceção do código ci-
tado acima), em diferentes programas VBA. Além de criá-lo no Word, experi-
mentei-o no FrontPage, no Excel e no PowerPoint, versão 2000. No Access foi
possível importar o formulário, mas as constantes relativas às barras de coman-
dos não foram reconhecidas. Na versão 97, também consegui rodá-lo no Word
e no Excel.
Para não dizer que, absolutamente, não modifiquei o programa, acrescen-
tei à rotina UserForm_Initialize a seguinte linha:

Me.Caption = Me.Caption & “ - ” & Application.Name

O objetivo era forçar que, em ação, o formulário mostrasse, na linha de tí-


tulo, o nome de nossa aplicação ao lado do nome do programa hospedeiro.
Além disso, alterei o rótulo localizado acima de lstBarras para que mostrasse
apenas “Barras disponíveis”, e não “Barras disponíveis no Word”. É o que você
pode ver nas telas a seguir:

F I G U R A 2 2 . 3 O programa, rodando no Excel, no FrontPage e


no PowerPoint

Você deve estar se perguntando: por que extrair a rotina cmdProdu-


zir_Click? É simples: de todo o código, apenas ela contém referências a objetos
que existem somente no Word – por exemplo, o método ConvertToTable. A
tentativa de executar um comando desses em outro aplicativo resulta em erro.
198
Até agora, falamos unicamente das barras de comandos em si. Mas, é claro,
essas barras abrigam diferentes tipos de controles, dos quais os mais populares
são os botões de comando. Na verdade, as barras de comandos podem incorpo-
rar outros tipos de objetos, como caixas de combinação, menus (no estilo Arqui-
vo, Editar etc.) e controles pop-up. Basta você dar uma olhada nos diferentes
objetos existentes nas barras de ferramentas do Word.
Em outros projetos deste livro, você pode ver como criar uma barra de fer-
ramentas e, também, como incluir e eliminar controles. Neste projeto, o clique
no rótulo Controles da Barra apenas mostra a lista dos controles existentes na
barra selecionada. Isso é feito mediante o seguinte código:

n = PegarNúmero()
iTot = CommandBars(n).Controls.count
s = “Total de controles: ” & iTot & vbCr & vbCr
For i = 1 To iTot
s = s & CommandBars(n).Controls(i).Caption & vbCr
Next i

MsgBox s, vbOKOnly + vbInformation, “Barra ” & _


CommandBars(n).Name

O valor n corresponde ao índice da barra de ferramentas, na coleção Com-


mandBars. A partir dele, obtém-se o total de controles na barra em questão e,
com um loop, acumula-se a lista dos nomes dos controles, afinal exibida numa
caixa de mensagem. Esta tem por título o nome da barra e informa o número e o
nome dos objetos.

F I G U R A 2 2 . 4 Dados sobre a barra Visual Basic

199
Para ir mais além
1. Os métodos e propriedades das barras de comandos somam-se às deze-
nas. Você só vai criar intimidade com esses itens se tiver necessidade de
usá-los e se pesquisar sobre eles. O próprio VBA oferece as fontes bási-
cas de pesquisa. A primeira delas é a ajuda pop-up. Em dúvida sobre um
objeto? Escreva o nome dele na janela Imediata e, em seguida, coloque
um ponto, como quem vai pedir um método ou propriedade. A caixa de
ajuda pop-up lhe dá dicas preciosas sobre os recursos do objeto. Outra
fonte de consulta é o Pesquisador de Objeto (no VBA, Exibir/Pesquisa-
dor de Objeto, ou simplesmente F2). Por fim, é claro, a Ajuda.

F I G U R A 2 2 . 5 Ajuda pop-up, uma fonte de pesquisa

2. Estenda os recursos da aplicação Barra de Comandos. Inclua no projeto


uma segunda caixa de listagem para abrigar os controles existentes na
barra selecionada em lstBarras. Ou seja, um clique em lstBarras provoca
a atualização da nova caixa, a qual passa a exibir a lista de controles cor-
respondentes.

200
Intimidade com desconhecidos
Ao longo deste livro, você tem visto que a maior parte dos objetos do
Word pertence a uma coleção. A vantagem disso é que você ganha
intimidade até com objetos dos quais nunca se aproximou antes. Eis
um exemplo. Eu nunca escrevi uma rotina a respeito de parágrafos.
Mas, por dedução, sei que deve existir uma coleção Paragraphs. Sei,
também, que tem de haver uma propriedade que controle o alinha-
mento, que deve ser Alignment (à esquerda, à direita, centralizado
etc.). Então, vamos escrever uma pequena rotina baseada, apenas,
na dedução e na intimidade adquirida no trato com outros objetos.
Aí está:

Sub AlinhaParágrafo()
Dim p As Paragraph

For Each p In ActiveDocument.Paragraphs


If p.Alignment = wdAlignParagraphCenter Then
p.Alignment = wdAlignParagraphJustify
End If
Next p
End Sub

Logo ao escrever Dim p As, na primeira linha, a ajuda pop-up já


me deu a dica do tipo de objeto-variável Paragraph. Depois, joguei na
lógica: os parágrafos existem num documento. Então escolhi o docu-
mento ativo. Com um If, defini: se for encontrado um parágrafo com
alinhamento central, vamos trocá-lo para justificado. Talvez essa inti-
midade pré-adquirida não seja de muita valia para situações mais
complexas, mas que ajuda, ajuda.

201
23
Todos os ícones à
sua disposição

Como criar um catálogo de todas as imagens


de botões disponíveis no Word

Ficha do projeto
Projeto:

Barras de Comandos

O que faz:

Esta aplicação relaciona todas as barras de comandos


(ferramentas, menus) disponíveis no Word. Oferece ainda
uma forma de visualizar esses objetos e gerar um
documento com uma lista de suas principais propriedades.

Arquivos e requisitos do projeto:

Formulário frmBotões e código interno.


Modelo Icones.dot.

Conhecimento técnico:

Manipulação das coleções de barras de comandos do


Word.

Nível de programação:

Intermediário
As barras de ferramentas do Word reúnem centenas de ícones. Alguns já se tor-
naram óbvios, como o disquetinho do comando Salvar ou a impressora do co-
mando Imprimir. Mas há uma enorme quantidade deles nos quais você nunca
teve a oportunidade de pousar o olho. Muito bem, se eles são ilustres desconhe-
cidos, então não interessam mesmo. Certo? Erradíssimo.
Quando você desenvolve aplicativos no ambiente Word, precisa de ícones
para montar suas barras de ferramentas personalizadas – e a melhor fonte deles
é o próprio Word. Mas, para usar um ícone disponível no ambiente, você preci-
sa conhecer duas de suas propriedades: a imagem, claro, e o seu número-índice.
Este projeto mostra como listar essas duas propriedades de todos os ícones do
Word, e assim poder escolher os mais convenientes para um novo projeto.
Os botões em barras de ferramentas têm três características que agora nos
interessam, em particular. Primeiro, eles são controles do tipo msoControlBut-
ton; depois, têm as propriedades Caption (a legenda que apresentam quando o
cursor do mouse se move sobre eles) e FaceID, seu número-índice. De posse des-
sas informações, nosso objetivo é criar barras de ferramentas que reúnam nume-
rosos botões com seus ícones. Esses botões devem mostrar como legendas o seu
número índice. Como há um número muito grande de ícones (no Word 2000,
verificamos que, sem contar os saltos, eles chegam a 1000), vamos dar ao usuá-
rio a opção de escolher uma faixa de FaceIDs que deseje exibir.
Para isso precisamos de um formulário, a que chamaremos de frmBotões.
Esse formulário terá duas caixas de texto – Início (txtIni) e Fim (txtFim ) – e três
botões de comando: Exibir Botões (cmdExibir), Ocultar Botões (cmdOcultar) e
Fechar (cmdFechar). Nas duas caixas de texto, o usuário indicará os números
correspondentes ao início e ao fim da faixa de FaceIDs que deseja exibir. Os bo-
tões de comando têm, respectivamente, a função de exibir os ícones, ocultá-los e
encerrar a aplicação.

F I G U R A 2 3 . 1 O form: criando barras de ferramentas

Passemos ao código. O eixo das atividades está na rotina cmdExibir_Click.


Sua primeira tarefa é chamar a sub TestaValores para verificar o preenchimento
das caixas de texto txtIni e txtFim. Superado esse teste, a sub associada ao clique 203
do botão Exibir cria, no âmbito do modelo Normal (CustomizationContext =
NormalTemplate), uma nova barra de ferramentas, chamada Ícones do Word,
cujos botões têm FaceIDs correspondentes aos números (de txtIni a txtFim) e le-
gendas (propriedade Caption) iguais aos próprios números-índices.
Usa-se o método Add para criar uma barra de ferramentas chamada Botões
do Word. O mesmo método é convocado para agregar a essa barra uma coleção
de botões cujos índices variam de txtIni a txtFim. O código é o seguinte:

Set BarraFer = CommandBars _


.Add(Name:=strBarraFer, Position:=msoBarFloating, _
Temporary:=True)

With BarraFer
.Visible = True
n = 1
For i = intIni To intFim
.Controls.Add Type:=msoControlButton
.Controls(n).Caption = i
.Controls(n).FaceId = i
n = n + 1
Next i
CustomizationContext = NormalTemplate
End With

Cria-se, então, uma barra de ferramentas com grande número de botões.


Para acomodá-la em sua tela, arraste para baixo sua extremidade inferior e você
terá algo como a figura abaixo:

F I G U R A 2 3 . 2 Barra, no Word 2000, para a faixa de


FaceIDs de 1 a 250
204
Nessa barra você vê apenas os ícones dos botões. Mas o que interessa, mes-
mo, é saber qual o índice de cada uma dessas figuras. Afinal, a intenção é usar
esse painel como um catálogo no qual se possa escolher ícones para uso em apli-
cações personalizadas. Se você exibir o formulário frmBotões da maneira co-
mum, isso não será possível. Simplesmente porque, como o form é modal (so-
mente ele detém o foco), não há como passar o cursor sobre a barra re-
cém-criada a fim de verificar o valor de FaceID para cada botão.
A solução reside num pequeno truque. Você vai carregar o form a partir de
uma macro. Nela, normalmente, você chamaria o formulário assim:

Public Sub ÍconesDosBotões()


frmBotões.Show
End Sub

Pois bem. Use o método Show com um parâmetro incomum, forçando que
o formulário seja não-modal:

frmBotões.Show False

Ou, em outras, palavras, o foco da ação não será exclusivo do formulário.


Desse modo, ele continuará ativo e, ao mesmo tempo, dará acesso à barra de fer-
ramentas recém-criada. Ao passar o mouse sobre ela, será possível ver as etique-
tas, indicando o número do FaceID de cada botão.
Clique no botão Ocultar Botões e a barra de ferramentas desaparecerá.
Para isso, entrará em cena a rotina RemoveCommandBar, cujo cerne são as se-
guintes linhas:

CustomizationContext = NormalTemplate
Dim cbar As CommandBar
For Each cbar In Application.CommandBars
If cbar.Name = strNomeBarra Then
cbar.Delete
End If
Next cbar

Essa rotina recebe uma string com o nome da barra de ferramentas


(strNomeBarra), localiza-a na coleção CommandBars e apaga-a. E aqui aparece
mais uma idiossincrasia do VBA. O método Delete para o objeto CommandBar
é perfeitamente legítimo e encontra-se documentado tanto no Word 97 como
no 2000. Todavia, se você o utilizar no Word 2000, corre o risco de produzir
resultados desagradáveis. Em várias situações, ao empregar esse método, o Word
2000 não apresentou nenhuma mensagem de erro. Mas, também, não eliminou
a barra de ferramentas. Aí, estranhamente, permitiu que nova barra com o mes-
mo nome fosse criada – o que, obviamente, não é aceitável. Para checar isso, vá ao
205
menu Exibir/Barras de Ferramentas/Personalizar e tente criar nova barra com o
nome de outra, embutida ou personalizada, já existente. O Word emite um
aviso de erro dizendo que aquela barra já existe.
Um bug? Talvez
Pois bem. Por algum mistério, o Word 2000 finge que apagou uma barra
com o nome X e, em seguida, aceita criar outra barra com o mesmo nome.
Quando você vai conferir, há barras X duplicadas. Bug? Possivelmente sim. Na
ajuda do Word 2000, você encontra um caminho alternativo para eliminar uma
barra de comando, que é o seguinte:

For Each cbar In Application.CommandBars


If cbar.Name = strNomeBarra Then
Application.OrganizerDelete _
Source:=NormalTemplate.Name, _
Name:=strNomeBarra, _
Object:=wdOrganizerObjectCommandBars
End If
Next cbar

Essa alternativa funciona corretamente nas duas versões do Word. Portan-


to, em lugar do simples e cômodo cbar.Delete, deve-se usar o longo e complica-
do Application.OrganizerDelete, a fim de manter a compatibilidade com as
duas versões do processador de texto. Na verdade, o problema não é exatamen-
te de compatibilidade, mas de fazer o programa funcionar.
Para coletar uma seqüência de 500 ícones, o Word consome cerca de 40 se-
gundos em meu Celeron 333 com 128 MB de memória. É tempo demais. Então,
resolvi criar uma alternativa mais rápida para exibir os botões de comando do
Word. Curiosamente, ela é uma solução que envolve procedimentos manuais.
Primeiro, usei o programa descrito até aqui para gerar uma barra de ferramen-
tas, chamada Botões do Word 1, com os botões de índices 1 a 400. Reutilizei o
recurso para criar outra barra, Botões do Word 2, com os botões de 401 a 815.
Em seguida, copiei as duas barras para um modelo, Icones.dot.
Para isso, usei o comando Ferramentas/Modelos e Suplementos/Biblioteca.
Transferi as barras Botões do Word 1 e 2 de Normal.dot para Icones.dot, que
contém apenas essas duas barras de ferramentas. Em seguida, excluí as barras de
Normal.dot.
Em Icones.dot, na pasta ThisDocument, adicionei a seguinte rotina:

Private Sub Document_New()


CommandBars(“Botões do Word 2").Visible = True
CommandBars(“Botões do Word 1").Visible = True
End Sub

206
F I G U R A 2 3 . 3 Cópia manual de barras de ferramentas
para outro modelo

Dessa forma, toda vez que se criar um novo documento baseado em Ico-
nes.dot, automaticamente as duas barras de ferramentas serão exibidas. A dife-
rença, em relação à primeira solução, está em que as barras são exibidas imedia-
tamente. Afinal, o Word não precisa sair coletando ícone a ícone – ele já os tem
reunidos em duas barras e, apenas, os apresenta. Nesse caso, basta fechar o do-
cumento que contém as barras, aberto apenas para que você possa visualizar os
ícones e escolher algum para uso em seus projetos.

F I G U R A 2 3 . 4 Barras Botões do Word 1 e 2: mais de 800 ícones

Como a exibição rápida das barras Botões do Word 1 e Botões do Word 2


nada tem a ver com o projeto atual, podemos modificar o projeto para que elas
sejam exibidas a partir do formulário frmBotões. Basta acrescentar a esse form
um botão de comando. Ao fazer isso, redesenhamos o form, incluindo também 207
duas molduras, a fim de separar as barras de ferramentas a ser construídas e as
barras já prontas. Também entrou no espaço uma caixa de imagem para abrigar
um pequeno desenho, a fim de ocupar o espaço em branco à direita, acima do
botão Fechar. O resultado final ficou assim:

F I G U R A 2 3 . 5 O form redesenhado: com molduras

Projeto concluído. Se você analisar cuidadosamente os ícones disponíveis


no Word, com certeza encontrará muitos que lhe poderão ser úteis ao criar ou
personalizar suas próprias barras de ferramentas.

Para ir mais além


1. Pratique a criação de barras de ferramentas. O procedimento é similar
ao da criação de outros objetos do Word. Primeiro, adiciona-se nova
barra à coleção CommandBars. Em seguida, agregam-se à barra recém-
criada os botões desejados. Um exemplo desse processo está mostrado
na rotina cmdExibir_Click.
2. Vimos aqui duas propriedades dos botões nas barras de ferramentas: Fa-
ceID, que identifica a imagem do botão, e Caption, a legenda apresenta-
da diante do cursor do mouse. Outra propriedade muito importante é
OnAction. Ela assume o nome da macro que o botão deve disparar,
quando clicado.

BarraFer.Controls(1).OnAction = “NomeDaMacro”

Não é demasiado lembrar que essa macro deve ser uma Sub do tipo Pu-
blic. Caso contrário, não estará acessível para uma chamada feita fora
208 do módulo em que se encontra.
Documento como modelo
Você sabia que um documento pode funcionar como modelo para ou-
tro documento? É simples: o arquivo não precisa ser do tipo DOT (mo-
delo) para que seja tomado como matriz a fim de gerar um novo docu-
mento. Para usar um arquivo DOC como modelo, utilize um código
como o seguinte exemplo:

Sub AbrirDocComoModelo()
Dim strDoc As String

strDoc = “c:\meus documentos\arquivo.doc”


Documents.Add Template:=strDoc
End Sub

Modelos globais e suplementos


Se você escreveu no Word uma série de programas úteis para o
dia-a-dia de seu trabalho, reúna-os num modelo, crie uma barra de
ferramentas e passe a usar esse modelo como uma biblioteca global.
Há duas maneiras de fazer isso. Uma é copiar o modelo para o diretó-
rio de inicialização, do Word, que varia conforme a versão do progra-
ma e a instalação. Se você não sabe onde ele fica, digite a seguinte li-
nha na janela Imediata:

? Options.DefaultFilePath(wdStartupPath)

F I G U R A 2 3 . 6 Tela para a inclusão de modelos e


suplementos
209
Em minha máquina, com o Word 2000, ele fica em c:\win-
dows\application data\microsoft\word\inicialização. No Word 97, essa
pasta fica dentro do diretório do Office e se chama Iniciar. O Word car-
rega automaticamente todos os modelos colocados aí. Outra forma de
deixar seus projetos sempre disponíveis no sistema é usar o modelo
que os contém como um suplemento (add-in). Vá a Ferramentas/Mo-
delos e Suplementos e adicione o modelo. Nesse caso, ele pode estar
em qualquer diretório. Mas lembre-se: não é possível visualizar o códi-
go nem editar os projetos contidos num modelo global ou num suple-
mento. Nessa condição, eles podem apenas ser usados.
Naturalmente, também é possível instalar um suplemento via
programação. O exemplo abaixo instala como add-in o modelo Solu-
coes.dot, e exibe sua barra de ferramentas.

Sub AcrescentaAddIn()
AddIns.Add _
FileName:="C:\Meus documentos\Livro\Solucoes.dot", _
Install:=True
CommandBars(“Soluções em Word 2000 e 97").Visible = True
End Sub

210
24
Um quebra-cabeça
de número e cores

Domine os 16,7 milhões de cores existentes


no arco-íris de seu monitor

Ficha do projeto

Projeto:

Cores

O que faz:

Permite visualizar cores no padrão RGB (o sistema dos


monitores de vídeo) , compondo-as a partir de cores
primárias.

Arquivos e requisitos do projeto:

Formulário frmCores e código interno.

Conhecimento técnico:

Programação com o objeto ScrollBar (barra de rolagem) e


números inteiros longos.

Nível de programação:

Intermediário
Neste capítulo, nosso alvo é mostrar como o Visual Basic trabalha com as
cores disponíveis na tela do computador. Conhecendo o mecanismo das cores,
você poderá tirar melhor proveito delas em seus projetos escritos em VB.
Você sabe: a cor em cada ponto da tela de seu micro é formada por diferen-
tes combinações de três tonalidades básicas: vermelho, verde e azul. Essas três
cores, ditas primárias, constituem a base do sistema RGB (red, green, blue), usa-
do nos monitores de vídeo. Cada componente básico desse sistema pode variar
de 0 a 255, admitindo, portanto, 256 diferentes intensidades de uma mesma
cor. Assim, o padrão RGB comporta um total de 256´ 256´ 256 combinações –
ou 16,7 milhões de cores.
Na caixa de diálogo Cores, do Windows, pode-se montar qualquer uma des-
sas combinações, atribuindo valores a R, G e B. No entanto, esse jogo de números
dá apenas uma idéia solta e abstrata do imenso estoque de cores. Você entenderá
melhor – ou, pelo menos, visualizará melhor – o sistema RGB se o imaginar como
um cubo de cores, traçado num espaço cartesiano em três dimensões.

F I G U R A 2 4 . 1 O cubo de cores RGB

É fácil: cada cor ocupa um eixo e pode assumir valores de 0 a 255 (veja a
Figura 24.1). Portanto, você tem coordenadas do tipo (R,G,B) correspondentes
a pontos-cores localizados na superfície ou no interior desse cubo cromático.
Na origem dos eixos está o ponto (0, 0, 0), que é o preto – ou seja, a ausência de
cor. Cada cor básica ocupa um dos vértices do cubo, diretamente ligados à
origem: vermelho (255, 0, 0), verde (0, 255, 0) e azul (0, 0, 255).
Há ainda quatro vértices de que não falamos. Três deles são os pontos que
formam faces do cubo com os pontos básicos. Esses representam as chamadas
cores secundárias – amarelo, magenta e ciano. Na prática, elas são combinações
de doses máximas de duas cores primárias:

212
CORES PRIMÁRIAS COR SECUNDÁRIA RGB

vermelho e verde amarelo (255, 255, 0)

vermelho e azul magenta (255, 0, 255)

verde e azul ciano (0, 255, 255)

O último vértice do cubo situa-se em posição diagonalmente oposta ao


ponto de origem. Trata-se do ponto (255, 255, 255). Nele, todas as cores bási-
cas estão em carga máxima. Aí temos o branco.
Como o sistema RGB é moeda comum, diferentes linguagens (Basic, C,
Pascal) o adotam. Em todas elas, existe uma função RGB, que fornece o valor
das combinações de cores. A cor cinzenta, que é o padrão das telas do Windows,
por exemplo, corresponde ao trio (242,242,242). Para usá-la como cor de fun-
do de uma caixa de imagem chamada Image1, basta fazer:

Image1.BackColor = RGB(242, 242, 242)

Mas o que quer dizer RGB(242, 242, 242)? Ou, para ser mais claro, que
tipo de variável a função retorna? Resposta: um inteiro longo, que varia de zero
(preto) a 16.777.215 (branco). Isso traz à tona outra pergunta: de onde vêm es-
ses números? O valor de retorno da função RGB é calculado com a seguinte fór-
mula:

ValorRGB = R + 256*G + 65536*B

Aí, R, G e B são as intensidades das cores primárias que entram na compo-


sição de uma tonalidade específica. E os números multiplicados por essas variá-
veis são, respectivamente, 256 (o lado do cubo) elevado a 0, 1 e 2.

O aplicativo Cores
Para demonstrar visualmente essa relação das cores e seus números RGB, vamos
desenvolver um programa em VBA chamado Cores. Trata-se de um formulário
único com uma caixa de imagem (Image1), três barras de rolagem horizontais
(ScrollBar1, ScrollBar2 e ScrollBar3) e quatro labels (labValor1, labValor2, lab-
Valor3 e labRGB).
Cada barra de rolagem representa uma cor primária. À medida que você
manipula essas barras, vai atribuindo diferentes cores à caixa de imagem.
Três das labels indicam os valores assumidos pelas barras de rolagem. A quar-
ta exibe o número RGB, calculado a partir dos valores isolados de cada com-
ponente.
213
F I G U R A 2 4 . 2 O programa Cores: RGB na prática

O código do programa
Vejamos como se desenvolve o código do programa Cores. Para que as três bar-
ras de rolagem representem o universo RGB, é preciso definir, adequadamente,
os valores mínimo e máximo de cada uma delas para, respectivamente, 0 e 255.
Quando o usuário deslocar uma das barras, ela assumirá um valor dentro desse
espectro e esse valor deve ser transmitido para três outros pontos: para a etique-
ta correspondente à barra deslocada; para a cor mostrada em Image1; e para o
número representativo da cor na etiqueta labRGB.
A transferência do valor assumido pela barra de rolagem para a etiqueta
correspondente é feita a partir do código associado ao evento Change (mudan-
ça) da barra de rolagem. Para não escrever um código idêntico no evento Chan-
ge de cada barra, cada uma delas chama a rotina MoveBarra com um parâmetro
identificador: 1 para R, 2 para G e 3 para B.
O procedimento MoveBarra recebe, portanto, a indicação de qual barra
foi deslocada. A transferência ocorre mediante a seguinte linha de código:

Controls(“labValor” & Index).Caption = _


Controls(“ScrollBar” & Index).Value

Observe que, aí, usamos o recurso de concatenar os nomes seqüenciais dos


controles labValor (1, 2 e 3) e ScrollBar (idem) para fazer a correspondência dos
números. A mesma rotina, MoveBarra, define a cor a ser exibida por Image1.
Para isso, lê os valores atuais de cada uma das barras (valores R, G e B) e monta
cor de fundo de Image1:

Image1.BackColor = RGB(R, G, B)
214
A cor RGB é exibida, visualmente, em Image1 e, numericamente, na eti-
queta labRGB. Em outras palavras, isso significa que a tonalidade formada pela
combinação de três números (R, G, B) também é representada por um número
único – um inteiro longo que é o número RBG. Para calcular esse número, a ro-
tina MoveBarra chama a função ValorRGB, que se resolve em uma linha e se ba-
seia na fórmula já citada:

ValorRGB = R + (256 * G) + (65536 * B)

Assim, o valor RGB, formatado, transfere-se para a etiqueta labRGB:

labRGB = Format(ValorRGB(R, G, B), “##,##0")

A rotina MoveBarra revela-se o eixo de nosso aplicativo. Ela é que distribui


todos os efeitos cromáticos e numéricos que representam o verdadeiro funcio-
namento do programa. Há ainda alguns retoques adicionais.
Quando o aplicativo se abre, as três barras estão na posição zero. Por-
tanto, a cor exibida na caixa Image1 deve ser (0, 0, 0), ou seja, preto. Mas to-
das as atualizações de números e cores só acontecem, como vimos, a partir do
evento Change das caixas de rolagem. No momento inicial, não há mudança
nessas caixas. Então, o valor zero não será escrito nas três etiquetas labValor
(1, 2 e 3).
Vamos, literalmente, forçar as barras, para que esse número apareça. No
evento UserForm_Initialize, definamos o valor de cada barra, primeiro para 1
(número escolhido arbitrariamente) e depois para 0. Isso provoca um evento
Change, que dá início à atualização dos valores nas etiquetas. O trecho do códi-
go é o seguinte:

For i = 1 To 3
With Controls(“ScrollBar” & i)
.Min = 0
.Max = 255
.LargeChange = 16
.Value = 1 ‘ força a mudança
.Value = 0
End With
Next i

Nesse mesmo trecho, define-se também como 16 o valor da propriedade


LargeChange de cada barra de rolagem. Se você clica nas setas das extremidades
da barra, o valor é incrementado ou reduzido de 1 em 1. LargeChange é o valor
do acréscimo (ou subtração) que ocorre quando você clica diretamente na barra,
à direita ou à esquerda do botão de rolamento. Escolhemos 16 por uma razão
simples: é um submúltiplo de 256, o comprimento total da barra. Com alguns
215
toques à direita do botão de rolamento, podem-se definir valores-chave na esca-
la RGB, como 64 (a quarta parte), 128 (o meio) e 242 (três quartos).
Outro detalhe: para dar maior realidade às labels labValor, cada uma delas
tem como tonalidade de fundo a cor primária que representa.
O projeto Cores inclui ainda a rotina SeparaCores, que mostra como partir
do número de um matiz RGB e extrair dele os números das cores primárias que
o compõem:

Private Sub SeparaCores()


Dim R As Long
Dim G As Long
Dim B As Long
Dim corRGB As Long

corRGB = Image1.BackColor

R = corRGB Mod 256


G = corRGB \ 256 Mod 256
B = corRGB \ 65536 Mod 256
End Sub

Essa rotina foi agregada ao código apenas para demonstrar como separar
as cores básicas de um número RGB. No entanto, ela não é utilizada no projeto.
Agora que você já está craque nas correspondências entre números e cores,
não vá cair na tentação de sair por aí dizendo frases do tipo: “Que seria do
16.711.680 se todos gostassem do 65.535?”

Para ir mais além


1. Um dos pontos de destaque, no código do projeto Cores, é o uso de va-
riáveis do tipo inteiro longo para trabalhar com os números RGB.
Como o número RGB máximo atinge 16,7 milhões, se você usar variá-
veis inteiras, por exemplo, provocará erros por estouro de capacidade.
Os valores inteiros variam apenas de -32.768 a 32.767.
2. Observe com cuidado o funcionamento do operador Mod – operador
de módulo, ou resto. Por exemplo, 10 Mod 3 retorna 1, que é o resto da
divisão de 10 por 3.
3. Na rotina UserForm_Initialize do projeto Cores, você encontra linhas
com o seguinte feitio para definir a cor de fundo de um objeto:
labValor1.BackColor = RGB(255, 0, 0)

Aqui, usou-se a função RGB porque o objetivo era colocá-la em desta-


216 que. No entanto, para cores primárias, seria mais fácil usar as constantes
intrínsecas do VBA relativas a cores: vbRed, vbGreen, vbYellow,
vbBlue, vbWhite, vbBlack. Exemplo:
labValor1.BackColor = vbRed

4. As cores usadas na indústria gráfica obedecem ao padrão CMYK. Dife-


rente do RGB, esse sistema baseia-se em quatro cores primárias: ciano,
magenta, amarelo (yellow) e preto (black). Uma das tarefas básicas dos
programas encarregados que geram trabalhos que vão ser impressos em
gráficas é converter o RGB que se vê na tela para o CMYK que vai ser
posto no papel, e fazer com que os dois sistemas de cores tenham a me-
lhor correspondência possível. O processo de impressão baseado no sis-
tema CMYK é chamado quadricromia. Nele, prepara-se um filme para
cada cor básica e obtém-se o resultado final imprimindo uma cor de
cada vez. Quer dizer, a página passa por uma série de quatro impres-
sões, uma sobreposta à outra.

Cores nos objetos de desenho


A definição da cor de fundo dos objetos de desenho – caixas de texto e
outras autoformas – é feita de forma diferente das tabelas. No modo
interativo, em lugar de procurar o menu Formatar, clique com o botão
direito no objeto e escolha, conforme o caso, Formatar Caixa de Texto
ou Formatar AutoForma. Depois, na área Preenchimento, escolha uma
cor.
No VBA, a seleção do objeto deve ser feita pelo seu índice na cole-
ção Shapes. Em seguida, aplica-se a cor, como mostrado a seguir:

ActiveDocument.Shapes(3).Select
Selection.ShapeRange.Fill.ForeColor.RGB = wdColorGray10

Na segunda linha, acima, também se pode aplicar a cor no for-


mato:

Selection.ShapeRange.Fill.ForeColor.RGB = RGB(204, 255, 255)

217
25
Fazendo os papéis
da sorte

Construa um programa que organiza


e imprime cupons para sorteios

Ficha do projeto

Projeto:

Bilhetes Numerados

O que faz:

Emite documentos numerados, como cupons ou bilhetes


para sorteio.

Arquivos e requisitos do projeto:

Sorteio.dot, modelo que contém a base para a confecção


dos bilhetes.
Formulário frmBilhetesComControle, com a lógica de
preenchimento, numeração e multiplicação dos bilhetes.

Conhecimento técnico:

Programação com objetos de desenho do Word.

Nível de programação:

Avançado
Muitas vezes, na escola ou no escritório, você quer organizar um sorteio entre
colegas ou alunos. Nessas ocasiões, em geral, você tira cópias xerox de um texto
e, depois, escreve à mão os números de cada bilhete. Com o Word é possível so-
lucionar esse problema de forma mais fácil e elegante. É disso que trata o projeto
atual. Na verdade, ele não se aplica somente a essas situações de brincadeira.
Uma vez alguém – se não me engano, ligado a uma pequena gráfica – me pergun-
tou como imprimir no Word certa quantidade de cópias numeradas de um mes-
mo documento. O princípio básico está aqui.
Em primeiro lugar, vamos precisar o que pretendemos fazer. Para dar um
certo charme ao nosso sorteio no escritório, vamos pegar uma folha de papel A4
e construir nela um modelo de documento, contendo seis bilhetes de sorteio.
Trata-se de uma tabela com duas colunas, seis linhas principais e cinco linhas de
menor altura que funcionam como separadores entre dois bilhetes (veja a Figu-
ra 25.1). Definido esse documento, ele deve ser salvo como o modelo Sorteio.dot.

F I G U R A 2 5 . 1 Página-modelo: seis bilhetes em cada folha A4;


destaque para as caixas de texto

A primeira coluna do bilhete serve como um canhoto de controle,


como se fosse um cheque. Assim, se você mantém o canhoto, pode saber
qual colega ficou, por exemplo, com o número 17 no sorteio do brinde de
Natal em sua seção. A segunda coluna contém palavras-chave que serão
substituídas, conforme o caso, por texto ou pelo número do bilhete. Elas são:
<TÍTULODOBILHETE>, <Textodobilhete>, ValorDoBilhete e NúmeroSort.
Esta última aparece tanto na coluna de controle como no lado do bilhete: o nú-
mero de um lado se repete no outro.
Há ainda outra particularidade: o título e o texto do bilhete estão soltos na
célula da tabela. Naturalmente, o título não deverá ultrapassar uma linha (máxi-
mo: 35 caracteres) e o texto, também, está limitado a um total de 325 caracte-
res. Esses números garantem que o texto para os dois itens não vai extrapolar o
espaço previsto. Isso deve ser evitado a todo custo, caso contrário o objetivo de
produzir seis bilhetes idênticos em cada página irá por água abaixo. Basta lem-
brar que, com mais texto, a célula da tabela vai ter sua altura aumentada. 219
Muito bem. Mas aqui aparece um problema: mesmo que o título e o texto
principal não excedam os limites, dependendo do tamanho do texto, as pala-
vras-chave ValordoBilhete e NúmeroSort poderão ficar mais acima ou mais abai-
xo, dentro da célula. Para impedir essa dança, colocamos esses itens dentro de cai-
xas de texto. Esses objetos ancoram numa posição da página e não se deslocam
com a variação do texto ao seu redor. Portanto, as duas palavras-chave Número-
Sort e ValordoBilhete estão contidas em caixas de texto (veja a Figura 25.1).
Feito o desenho do primeiro bilhete, deve-se copiar o seu conteúdo e co-
lá-lo nos demais. Assim, todas as linhas principais da tabela (ou seja, sem contar
as linhas de separação de um bilhete para o outro) terão o mesmo conteúdo.
Uma pequena manha: no programa, vamos precisar fazer referência às caixas de
texto, que são objetos de desenho. Quando se incluem objetos desse tipo num
documento, eles vão assumindo identidades numeradas seqüencialmente numa
coleção chamada Shapes. O primeiro objeto de desenho é Shapes(1), o segundo
Shapes(2), e assim por diante. Esses números vão sendo atribuídos pela ordem
de inclusão do objeto. Se o primeiro que você desenhou fica no fim do docu-
mento, não importa – ele terá o índice 1.
Em vista disso, tenha o cuidado de, no primeiro bilhete, desenhar as caixas
de texto da esquerda para a direita. Ao copiar o conteúdo para os bilhetes subse-
qüentes, também tenha o cuidado de manter a ordem de cima para baixo. Isso
garante que os objetos de desenho vão assumir índices em ordem crescente, da
esquerda para a direita e de cima para baixo. Quando discutirmos o código,
você vai entender por quê.

O formulário do projeto
Neste projeto, o modelo com os bilhetes não contém código. A lógica de mani-
pulação do documento está fora dele, em outro modelo. Basicamente, essa lógi-
ca reside num formulário (frmBilheteComControle) e em seu código interno.

F I G U R A 2 5 . 2 O formulário para preencher e numerar os


bilhetes
220
O formulário segue o padrão já definido no perfil dos bilhetes. Há quatro
caixas de texto: uma para o título (txtTítulo), outra para o texto do bilhete
(txtTexto), mais outra para abrigar o total de bilhetes (txtTotal), e uma última
(txtValor), opcional, para situações em que seja necessário atribuir um valor
ao bilhete – uma rifa, por exemplo. Por fim, vêm os botões OK (cmdOK), que
dispara a confecção dos bilhetes, e Cancelar (cmdCancelar), que encerra o
aplicativo.

O código
Vejamos agora o funcionamento interno desse formulário. A ação básica ocorre
quando o usuário clica no botão OK. A primeira tarefa da rotina cmdOK_Click
é chamar a função TesteOK, que verifica o preenchimento dos campos do for-
mulário. Caso haja problema, o processamento é interrompido com aviso ao
usuário.
A própria estrutura do formulário já é preparada para evitar alguns tipos
de erros. A caixa txtTítulo, por exemplo, não aceita textos com mais de 35 ca-
racteres. Sua propriedade MaxLength foi definida para esse número. Outro
exemplo: as caixas txtTotal e txtValor estão ajustadas para só aceitar a digitação
de números. As rotinas associadas ao evento KeyPress desses controles garantem
essa característica. Veja o exemplo da sub txtTotal_KeyPress:

Select Case KeyAscii


Case 8, 48 To 57
‘OK
Case Else ‘
KeyAscii = 0
End Select

O que está dito nessas linhas de código é o seguinte. Se as teclas pressiona-


das em txtTotal corresponderem aos valores ASCII 8 (retrocesso) ou aos alga-
rismos (48 a 57), tudo bem. Todas as outras serão anuladas.
Mas voltemos à rotina cmdOK_Click. Feito o teste de preenchimento, ela
passa a calcular o número de páginas necessárias para produzir o total de bilhe-
tes, indicado pelo usuário em txtTotal. (Aqui, é necessário abrir um parêntese:
neste projeto, limitamos o número máximo de bilhetes a 1000. Esse limite está
definido na função TesteOK. Para alterá-lo, modifique a função.) Para calcular
o número de páginas, basta dividir o total de bilhetes pela capacidade de cada
página (seis bilhetes, em nosso exemplo).
Com esse número na mão, a rotina avança. Cria um documento novo ba-
seado no modelo Sorteio.dot. Esse documento tem apenas uma página, ou seis
bilhetes. Agora, vamos preencher esses seis bilhetes com o título e o texto digita-
dos pelo usuário. Para isso é convocada a sub DefinePágina. Numa primeira ver-
são dessa rotina, não conseguíamos passar mais de 255 caracteres como texto 221
do bilhete. O problema: a rotina baseava-se no esquema de busca e troca, e o ob-
jeto Selection.Find não substitui strings maiores que 255 caracteres.
Para fugir dessa limitação, recorremos a um pequeno truque em DefinePá-
gina. Usamos Selection.Find para localizar e selecionar a palavra-chave procura-
da. Mas em lugar de usar o recurso de substituir, aproveitamos que a expressão
está selecionada e aplicamos o método TypeText. Isso nos garantiu um acrésci-
mo de 65 caracteres no texto, elevando a capacidade total para 325 – o máximo
que é possível escrever na célula.
Como o valor, quando existe, é um elemento fixo, é hora de aproveitar e
também preencher cada uma das caixas com valor. Para isso, observe que os ín-
dices dessas caixas são 2, 5, 8 etc. até 17 – uma progressão aritmética de razão 3.
Escrever o valor agora, em cada uma dessas caixas, resulta em economia de tra-
balho. Se deixarmos para depois, será necessário escrevê-lo não apenas seis ve-
zes, mas em seis vezes o número de páginas necessário para perfazer o total de
bilhetes escolhido pelo usuário.
Agora, temos uma página com seis bilhetes preenchidos. Falta numerá-los.
Mas antes é preciso replicar essa página única para o número já calculado.
Como fazer isso? Seleciona-se toda a página, cujo conteúdo é copiado para a
memória. Agora, num loop de 2 (a página 1 já está pronta) até o total de páginas,
emprega-se o método Paste (Colar) para gerar novas páginas e bilhetes. Isso é fei-
to pelas linhas abaixo:

ActiveDocument.Content.Select
‘ Copia a primeira página
With Selection
.Range.Copy
.EndKey Unit:=wdStory
.TypeParagraph
End With

‘ Expande o documento até intTotalPáginas


For n = 2 To intTotalPáginas
Selection.Paste
Next n

O próximo passo é numerar os bilhetes.Trata-se da tarefa mais complica-


da do projeto. Em cada bilhete há três caixas de texto a preencher. Se fosse
apenas uma caixa em cada bilhete, tudo ficaria muito fácil: bastaria percorrer,
num loop, caixa a caixa, selecioná-las e numerá-las. Aí, o índice da coleção
Shapes seria, basicamente, igual ao número a ser impresso na caixa. Em nosso
caso, a coisa é mais complexa. É preciso escrever o mesmo número na primeira
e na terceira caixas de cada bilhete, sendo que a segunda caixa já está preenchi-
da com o valor.
222
No final, o programa produz bilhetes nos moldes mostrados na Figu-
ra 25.3. Basta imprimir o documento, empilhar as folhas e cortá-las com uma
guilhotina ou com um estilete de escritório. Os bilhetes estão prontos.
Uma observação final. Durante o processo de multiplicação dos bilhetes, o
programa mantém na Área de Transferência do Windows (Clipboard) uma pá-
gina com a estrutura de seis bilhetes básicos. Por isso, no final do procedimento
cmdOK_Click, chama-se a sub LimpaMemória, que zera o conteúdo do Clip-
board. No entanto, nos testes que fiz, esse procedimento funciona em algumas
versões do Word, em outras não. Se em sua máquina você receber uma mensa-
gem de erro, desative a chamada a LimpaMemória.
Não vou cometer a temeridade de afirmar em quais sim e em quais não.
Digo apenas que nas versões do Word 2000 a que tive acesso, o programa fun-
cionou normalmente. Idem na versão 97a. Mas o Word 97, versão b, acusa um
erro, embora não haja nenhum problema no código. É bom dizer que também
não tenho certeza quanto a essas versões. É difícil encontrar uma máquina em
que se possa afirmar qual é a versão existente. Somente em condições de labora-
tório, mas não cheguei a fazer testes tão apurados.
Mesmo quando duas máquinas informam, por exemplo, versão 97b, isso
não significa que as duas têm o Word com a mesmíssima configuração. É possí-
vel que a DLL que contém o número da versão seja a mesma. Só que há numero-
sos arquivos interferindo no funcionamento de programas como o Word. Fique
atento a esse detalhe.
O esquema de numeração de documentos, demonstrado neste projeto, tem
utilidade muito maior do que a simples confecção de bilhetes para pequenos
sorteios em seu local de trabalho. Usei esse exemplo porque, aparentemente, é o
mais próximo da maioria das pessoas. Mas tenho certeza de que você vai encon-
trar aplicações comerciais, escolares e domésticas realmente úteis e criativas,
empregando essa técnica. Mesmo que não haja sorteio, boa sorte.

F I G U R A 2 5 . 3 Os bilhetes prontos: basta cortar e distribuir

223
Para ir mais além
1. Quer tornar mais acessível a idéia deste projeto? Adapte-o para produ-
zir cupons com apenas um número.
2. Para adicionar um pouco de complexidade, avance para bilhetes que in-
cluem duas vezes o mesmo número, como os mostrados aqui, mas sem o
item complicador da caixa com o valor do bilhete.
3. Também vale a pena considerar a confecção de bilhetes duplos – ou seja,
bilhetes que têm dois números em lugar de um. Para um universo de mil
números, por exemplo, você pode numerar os bilhetes com os pares
000-500, 001-501, e assim por diante. Ou então, começando pelas ex-
tremidades: 000-999, 001-998...
4. Com base nos recursos mostrados neste projeto, desenvolvi outro que
produz seqüências de várias cópias de um documento com o mesmo nú-
mero – ou seja, 1,1,1–2,2,2–3,3,3, num exemplo para três cópias de
cada. Esse novo projeto, que você pode analisar no próximo capítulo,
também permite numerar documentos partindo de qualquer número in-
dicado pelo usuário.

224
Constantes, uma força para o programador
As constantes do Visual Basic representam uma mão na roda para o
programador. Elas evitam que você tenha de memorizar números ou
consultar, com freqüência, a ajuda ou manuais. Numa caixa de diálo-
go, por exemplo, se o usuário clica no botão Sim, escolhe o valor vbYes;
se aciona o botão Não, escolhe vbNo; se desiste da operação, escolhe
vbCancel. Isso é muito mais fácil de guardar do que os números corres-
pondentes. No caso, Sim, na resposta do usuário, equivale a 6, Não a
7; e Cancelar a 2.
Há constantes para várias outras situações, como o valor dos
botões do teclado, cores e dias da semana. Em geral, são itens muito fá-
ceis de memorizar e deduzir uns a partir de outros. Por exemplo:
vbKeyA, vbKeyB, vbKeyF3, vbKeyNumlock; vbBlue, vbBlack, vbYellow;
vbMonday, vbTuesday, vbSaturday. Para visualizar a lista completa de
constantes intrínsecas do VB, acione Exibir/Pesquisador de Objeto (ou
F2) no ambiente de desenvolvimento do Visual Basic.
Também é possível descobrir o valor numérico da constante sem
consultar o Pesquisador de Objeto. Basta ir à Janela Imediata e digitar
? seguido do nome da constante. Por exemplo:

? vbMonday <Enter>

O VBA apresenta o número 2 na linha seguinte. Se a resposta for


uma string vazia, das duas uma: ou a constante não existe, ou você a
digitou erroneamente.
Observe que o Word também tem suas constantes intrínsecas, to-
das com o prefixo wd. Boa parte delas se refere a itens específicos do
Word, mas algumas têm o mesmo objetivo (e, em certos casos, o mes-
mo valor) de constantes do VB. Nos exemplos abaixo, tanto faz usar
uma constante como a outra, embora nem sempre elas tenham o mes-
mo valor numérico:

wdBrazil = vbBrazil = 55
wdBlue = 2; vbBlue = 16711680
wdDarkBlue = 9; vbDarkBlue não existe

225
26
Clones ao gosto
do freguês

Produza documentos numerados com


quantidade de cópias indicada pelo usuário

Ficha do projeto
Projeto:

Documentos Múltiplos Numerados

O que faz:

Produz documentos numerados com cópias múltiplas em


número indicado pelo usuário.

Arquivos e requisitos do projeto:

Multidoc.dot, modelo que contém a base para a confecção


dos documentos.
Formulário frmDocsRepetidos, com a lógica de numeração
e multiplicação dos documentos.

Conhecimento técnico:

Programação com objetos de desenho do Word. Algoritmo


de cálculo para o número dos documentos.

Nível de programação:

Avançado
226
Este projeto é uma extensão do anterior. Naquele, o objetivo era criar uma série
de bilhetes numerados (vários numa mesma folha de papel), com texto, valor e
número. Neste caso, o processo é simplificado, pois envolve apenas o número.
Em compensação, traz uma diferença básica: em vez de vários bilhetes numa
mesma página, temos aqui um documento em cada página. O usuário vai deter-
minar quantas cópias deseja produzir do mesmo documento e o número de do-
cumentos a emitir, cada um com cópias múltiplas. Se, por exemplo, o usuário
escolher três cópias, os documentos, todos iguais, serão numerados na seqüên-
cia: 1,1,1-2,2,2 etc.
O projeto baseia-se num modelo, Multidoc.dot. O documento-padrão
contém apenas uma caixa de texto para receber o número do documento. Fica
claro que o objetivo, aqui, é apenas mostrar o uso do recurso. Num documento
real, você vai colocar essa caixa de texto no tamanho certo e no lugar adequado,
ao lado de outras informações.
Como o usuário precisa fornecer informações ao programa, impõe-se a
necessidade de um formulário. Vamos criar um, chamado frmDocsRepeti-
dos. Esse formulário tem apenas dois botões, OK (cmdOK) e Fechar (cmdFe-
char), além de três caixas de texto: txtNumBilInicial, txtTotalBilhetes e
txtRepetições.
Nessas caixas o usuário deve digitar os números que vão definir as caracte-
rísticas do documento a ser gerado. Na primeira, ele deve informar o número do
documento inicial. Na segunda, o total de documentos que deseja produzir. E,
na última, o número de repetições de cada documento.
A ação é rápida. Quando o botão OK é pressionado, o programa primeiro
verifica se as três caixas de texto estão preenchidas. Em seguida, chama o proce-
dimento Multidoc, que é realmente a principal rotina do aplicativo. O algorit-
mo para determinar os números dos documentos é semelhante ao utilizado no
projeto anterior. A diferença é que agora, em vez de repetir o número num mes-
mo bilhete, o número se repete em cópias do mesmo documento. Esse recurso é
útil na produção de qualquer documento que precise ser numerado, e que tenha
mais de uma via em cada número.
Vale observar que o total de documentos a ser informado pelo usuário
refere-se apenas à primeira via. No exemplo da Figura 26.1, está proposta a
emissão de 15 documentos, numerados a partir de 50, com três vias cada. Ou
seja, serão 45 folhas. Uma idéia visual do resultado é dada pela Figura 26.2.

227
F I G U R A 2 6 . 1 O formulário frmDocsRepetidos

F I G U R A 2 6 . 2 Documentos numerados a partir de 50, com três


repetições

Para ir mais além


1. Estude com critério a rotina Multidoc. Ela utiliza alguns artifícios para
manter em paralelo várias seqüências de numeração. Uma é a seqüência
dos índices das caixas de texto. Não importa o que você faça, eles são
sempre números naturais: 1, 2, 3 etc. Outra seqüência é definida pelo
número inicial escolhido pelo leitor. Há ainda uma terceira, que contém
a lógica de repetição do número de cada documento conforme a quanti-
dade de repetições solicitada.
2. Você pode adaptar o formulário deste projeto para receber, além dos
dados que vão controlar a numeração, as informações textuais do docu-
mento – como no caso dos bilhetes numerados.
3. Com os recursos de bancos de dados, mostrados nos Capítulos 27 a 32 e
228
33 a 34, você pode pensar num composto de numeração e persona-
lização. Digamos que seja preciso emitir três cópias de um documento
para cinqüenta pessoas cadastradas num banco de dados. Então, além
de numerar, você marcaria cada cópia com o nome da pessoa.

Atributos de arquivos
Quer saber, num programa, se um arquivo é somente leitura? Use a
função GetAttr. Ela retorna um número correspondente à soma dos
atributos do arquivo. Por exemplo, para saber se o arquivo Teste.doc,
em c:\download, é somente leitura:

r = GetAttr(“c:\download\teste.doc”) And vbReadOnly

Se r for igual a zero, isso significa que ele não possui o atributo so-
mente leitura (read only). Caso contrário, ele será igual à constante
correspondente ao atributo definido depois da expressão And. Essas
constantes são: vbNormal = 0; vbReadOnly = 1; vbHidden = 2;
vbSystem = 4; vbDirectory = 16; e vbArchive =32.
A definição dos atributos obedece à mesma lógica e é feita com a
instrução SetAttr. Exemplo para tornar um arquivo somente leitura e
oculto:

SetAttr “c:\download\teste.doc”, vbReadOnly + vbHidden

229
27
Para acabar com a
“letra de médico”

Um programa que emite receitas para


médicos e dentistas

Ficha do projeto
Projeto:
Receita Médica
O que faz:
Automatiza a emissão de receitas médicas e
odontológicas. Preenche todo o cabeçalho, numera e salva
o documento.
Arquivos e requisitos do projeto:
Receita.dot, modelo que contém, externamente, a base do
documento e, internamente, o formulário frmReceita, com
seu código interno.
Receita.ini, arquivo que armazena os itens de
personalização do aplicativo.

Conhecimento técnico:

Programação com indicadores (bookmarks) e o objeto


Selection.Find. Escrita e recuperação de informações em
arquivos INI. Acesso, via VBA, ao cabeçalho e ao rodapé
do documento.

Nível de programação:

Intermediário
230
Alguns meses atrás, fui ao consultório de um médico e fiquei animado com o fato
de vê-lo emitir a receita usando um computador e uma impressora. Enquanto
ele digitava, pensei comigo: Que bom! Isso resolve o problema da “letra de
médico” – aquelas garatujas que exigem trabalho de interpretação e adivinhação
do paciente e do balconista da farmácia. Claro que há aí algo folclórico: nem
todos os médicos têm caligrafia incompreensível, mas pensei nisso ao vê-lo
operando o computador.
Só que, notei depois, ele usava muito pouco do que a tecnologia é capaz de
oferecer. Motivado por essa constatação, resolvi criar, no Word, uma solução
simples para automatizar a emissão de receitas médicas e odontológicas. Sem
nenhuma mudança, a mesma aplicação também pode ser usada para emitir a so-
licitação de exames. Essa aplicação, a Receita Médica, é apresentada a seguir.

O documento-modelo
Toda a aplicação está contida no modelo Receita.dot, que apresenta, por fora, a
base do documento-receita e, internamente, o código para a automação de seu
preenchimento. A estrutura do documento é a mais singela possível. Contém
um cabeçalho, no qual constam o nome do médico ou dentista, sua especialida-
de e seu número no Conselho Regional de Medicina ou no de Odontologia.
Ainda no cabeçalho, estão o endereço e o telefone do consultório. Algo com es-
trutura semelhante ao seguinte:

Dra. Ana Lúcia de Lima Rua das Acácias, 978 cj. 54


Endocrinologista 00000-000 – Cidade – UF
CRM-UF 00.000 Tel. (000) 2727-3344
E-mail: analima@provedor.com.br

Numa primeira versão deste projeto, incluí um cabeçalho fixo, como o


mostrado acima. Para usar a solução, o médico ou dentista teria de abrir o arqui-
vo Receita.dot e editar o cabeçalho, escrevendo seu nome, especialidade e ende-
reço. Depois, decidi que seria mais prático para o usuário que o preenchimento
do cabeçalho também fosse automatizado. Assim, substituí todas as informações
daquela área por palavras-chave de substituição. A idéia é que, durante o preen-
chimento da receita, o cabeçalho também seja ajustado com os dados fornecidos
pelo usuário. Essa parte do documento ficou assim:

TítuloNomeDoMédico EndereçoMédico
EspecialidadeDoMédico CEPMédico – CidadeMédico – UFMédico
NúmeroCRM TelefoneMédico
EmailMédico
231
O documento-receita, em si, envolve quatro blocos de variáveis. No pri-
meiro bloco estão a data e o nome do paciente. O segundo reúne os medicamen-
tos (ou exames) prescritos e as respectivas orientações (“Tomar uma colher de
chá, de duas em duas horas”). No terceiro grupo, as variáveis dizem respeito à
pessoa do médico ou dentista: seu nome, título (“Dr.”, “Dra.”), especialidade,
matrícula no CRM/CRO etc. Há ainda um conjunto de variáveis relativas ao
consultório do profissional: endereço, telefone, e-mail.
As variáveis dos dois primeiros blocos devem ser preenchidas na hora de
emitir a receita ou o pedido de exames. Já os dados do profissional e as informa-
ções do consultório correspondem a configurações fixas para cada médico ou
dentista. Com base nessa análise, vamos construir o único formulário da aplica-
ção, frmReceita.

O formulário frmReceita
O formulário frmReceita contém os seguintes controles:
Um objeto multipágina (Multipage1) com três orelhas: Receita, Dados
Profissionais e Consultório (Page1 a Page3). A primeira contém os controles as-
sociados às variáveis dos blocos 1 e 2, que são:
Caixa de texto Data (txtData)
Caixa de texto Nome do Paciente (txtNome)
Quatro caixas de texto Medicamento 1 a 4 (txtMedicamento1 a txtMedi-
camento4)
Quatro caixas de texto Dose e Uso (txtDoseUso1 a txtDoseUso4).

F I G U R A 2 7 . 1 O programa em ação, destacando a orelha


principal (Receita)
232
Na orelha Page2 (Dados Profissionais) estão os seguintes objetos:
Caixa de texto Nome do Médico ou Dentista (txtNomeMédico)
Caixa de texto Número CRM/CRO (txtCRM)
Caixa de texto CPF (txtCPF)
Caixa de combinação Título (cboTítulo)
Caixa de combinação Conselho Regional (cboConselho)
Caixa de texto Especialidade (txtEspecialidade)
Caixa de texto Pasta para Armazenamento das Receitas (txtPastaDoc)
Caixa de verificação Não Armazenar as Receitas Emitidas (chkArmazenar)
Botão de comando Procurar (cmdProcurar), que abre uma caixa de diálo-
go para definir um diretório para txtPastaDoc.
Botão de comando Salvar (cmdSalvar), que salva num arquivo INI as confi-
gurações indicadas nos controles acima.

F I G U R A 2 7 . 2 Orelha 2: dados do médico ou do dentista, e


pasta-padrão para as receitas

A orelha Page3 (Consultório) reúne os controles ligados ao endereço do


consultório:
Caixa de texto Endereço (txtEndereço)
Caixa de texto CEP (txtCEP)
Caixa de texto Cidade (txtCidade)
Caixa de texto Estado (txtEstado)
Caixa de texto Telefone (txtTelefone)
Caixa de texto Email ou Bip (txtEmail)
Caixa de verificação Não Preencher o Cabeçalho (chkCabeçalho)
233
Diretamente no formulário – ou seja, não no controle multipágina – há
ainda dois botões de comando, OK (cmdOK) e Cancelar (cmdCancelar). O pri-
meiro executa a emissão da receita e o outro fecha o formulário, encerrando a
aplicação.
Afora o cabeçalho, o documento-modelo da receita contém apenas as se-
guintes informações:

Para: <NomeDoPaciente>
Data: <DataDaConsulta>

Na hora do preenchimento, as expressões que contêm os sinais < e > são


substituídas pelos valores correspondentes. Mas o documento tem ainda, ocul-
tos, oito indicadores (Medicamento1 a Medicamento4; e doseMedicamento1 a
doseMedicamento4), que marcam as posições em que as informações corres-
pondentes devem aparecer no texto. Esta solução também poderia ser concebi-
da usando apenas o recurso da substituição de palavras-chave. O uso dos indica-
dores constitui um caminho alternativo.
Vamos agora entender o mecanismo de funcionamento do aplicativo, co-
meçando pela sua rotina fundamental, a que está associada ao botão de coman-
do OK. Quando o usuário clica nesse botão, o programa chama a função Tes-
taPreenchimento, que verifica se estão preenchidos os itens fundamentais da re-
ceita. Quais são esses itens? Primeiro, a data; depois, o nome do paciente e, por
fim, pelo menos um dos campos MedicamentoX. O programa também testa se
as informações pessoais do médico ou do dentista estão disponíveis. Em caso ne-
gativo, o processo é interrompido.

F I G U R A 2 7 . 3 Os indicadores de Receita.dot

234
Com todos os dados no lugar, o aplicativo segue em frente e, primeiro, usa
a técnica da substituição de palavra-chave para preencher o nome do paciente e
a data da consulta. Em seguida, localiza cada um dos indicadores (bookmarks),
posiciona o cursor nos pontos marcados por eles e lá insere a informação corres-
pondente. Isso é feito mediante um loop que varia de 1 a nCaixas (=4), o núme-
ro de caixas para medicamentos.

For n = 1 To nCaixas
If Controls(“txtMedicamento” & n) <> “” Then
With Selection
.GoTo What:=wdGoToBookmark, Name:="Medicamento" & n
.Font.Bold = True
.TypeText CStr(n) & “. ” & _
Controls(“txtMedicamento” & n).Text
.Font.Bold = False
.GoTo What:=wdGoToBookmark, _
Name:="DoseMedicamento" & n
.TypeText Controls(“txtDoseUso” & n).Text
End With
End If
Next n

Preenchida a receita propriamente dita, o programa recolhe as informa-


ções pessoais do médico ou do dentista e acrescenta-as ao final do documento,
no qual o profissional deve assinar. Nesse caso, a técnica empregada vale-se do
método TypeText do objeto Selection:

With Selection
For n = 1 To 4 ‘ quatro linhas em branco
.TypeText vbCrLf
Next n
.Font.Italic = True
.Font.Size = 10
.TypeText cboTítulo & “ ” & txtNomeMédico & vbCrLf
.TypeText cboConselho & “: ” & txtCRM & vbCrLf
.TypeText “CPF: ” & txtCPF
.Font.Italic = False
.Font.Size = 12
End With

As informações inseridas no documento pelas linhas de código acima estão


todas na orelha Dados Profissionais do formulário (Figura 27.2).
Muito bem. Já vimos o funcionamento básico da aplicação. Mas faltam
ainda alguns pontos essenciais. Todos os dados exibidos na orelha Configura-
ções ficam guardados num arquivo INI (Receita.ini). Como eles vão parar nesse 235
arquivo e como são recuperados de lá? Para personalizar suas receitas, o médico
ou o dentista deve preencher esses campos de configuração. Após isso, ao clicar
no botão Salvar Configurações, transfere todos os dados pessoais para o arquivo
INI. Como um toque adicional de personalização, seu nome também passa a
aparecer na barra de título do formulário. Assim:

Receita – Dra. Ana Lúcia de Lima

Para salvar as informações no arquivo INI, o aplicativo usa a propriedade


PrivateProfileString, do objeto System. O mesmo recurso é utilizado para recu-
perar essas informações, durante a inicialização de Receita Médica. O programa
lê os dados armazenados em Receita.ini e os exibe nas caixas de texto e caixas de
combinação da orelha Configurações, quadro Dados Profissionais.
Observe que as informações que aparecem em caixas de texto (nome do
médico, CPF e número de matrícula no Conselho Regional) são armazenadas
no arquivo, como texto normal. No entanto, o que se registra das caixas de
combinação não é o texto do item, mas o índice correspondente a ele. Na caixa
cboTítulo, por exemplo, a opção “Dr.” é a primeira da lista – e portanto tem o
índice 0. Se “Dr.” é a opção escolhida, o número 0 vai para a chave Título, no
arquivo INI. Ao ser recuperado, ele é aplicado à propriedade ListIndex da caixa
de combinação:

cboTítulo.ListIndex = CInt(strTítulo)

A função CInt é usada, aí, para converter em número inteiro a string lida
no arquivo INI (strTítulo).
Além dos dados profissionais do médico ou do dentista, a orelha 2 envolve
itens que estão vinculados ao controle dos documentos-receitas. Esses itens es-
tão dentro do quadro Documentos. O primeiro deles é a caixa de texto txtPasta-
Doc, na qual o usuário deve indicar um diretório-padrão para o armazenamento
das receitas emitidas. O botão Procurar facilita essa tarefa. Ele abre uma caixa
de diálogo do Word na qual o usuário escolhe o diretório desejado.
O último item de configuração dessa orelha é representado pela caixa de
verificação chkArmazenar, que tem por legenda “Não Armazenar as Receitas
Emitidas”. Portanto, se essa caixa for ativada, as receitas não serão salvas. Ou
melhor, todas elas serão salvas com o mesmo nome, Receita.doc, de modo que a
receita mais nova sobrescreverá a anterior. Quando a opção Não Armazenar
está selecionada, o rótulo labDocReceita passa a exibir Receita.doc como nome
do próximo documento a ser emitido. O padrão, no entanto, é a emissão de do-
cumentos numerados.
Para gravar todas as receitas, os nomes dos arquivos obedecem a uma nu-
meração similar à adotada no projeto do Capítulo 14. Os documentos-receitas
recebem nomes seqüenciais obedecendo ao formato Rxxxx-yy.doc, no qual
236 xxxx é um número que varia de 0001 a 9999; yy é o ano, escrito com dois dígi-
tos. No início de um novo ano, yy assume o valor correspondente e o número
xxxx recomeça de zero.
Esse esquema de denominação dos arquivos funciona graças ao registro do
último número feito no arquivo Receita.ini. Não discutiremos os procedimen-
tos aqui porque eles são idênticos aos usados no Capítulo 14. Aliás, eles serão
discutidos também no Capítulo 31. O arquivo Receita.ini abriga ainda anota-
ções referentes aos controles reunidos na terceira orelha de Multipage1 – as in-
formações que servem para preencher o cabeçalho da receita.
O médico ou o dentista deve preencher esses campos e clicar no botão Sal-
var. Observe que há dois botões Salvar, um na orelha 2 e o outro na orelha 3.
Trata-se de uma redundância, de propósito. Pareceu-me que assim fica mais fá-
cil para o usuário. Ele preenche os campos da orelha 2 e salva; depois, preenche
a orelha 3 e salva outra vez. Internamente, de fato, os dois botões salvam as in-
formações em separado.

F I G U R A 2 7 . 4 Orelha Consultório: informações para o


cabeçalho da receita

Depois de personalizado com as informações do médico e de seu consultó-


rio, e iniciado o processo de numeração dos arquivos, o conteúdo do arquivo
Receita.ini assume o seguinte formato:

[Usuário]
CRM=00.000
CPF=000.000.000-00
Título=1
Nome=Ana Lúcia de Lima
Conselho=0
Espec=Endocrinologista
237
[Arquivos]
Ano=1999
RecNum=35
PastaDoc=c:\solucoes\receitas
SalvarDocs=Sim

[Endereço]
Rua=Rua das Acácias, 318 cj. 42
CEP=04568-000
Cidade=São Paulo
Estado=SP
Telefone=(011) 2727-3344
E-mail=E-mail: analima@provedor.com.br
Cabeçalho=Sim

Conforme você pode observar, as três seções de Receita.ini armazenam in-


formações de áreas distintas. A seção Usuário junta os dados sobre o médico ou
o dentista. A seção Arquivos ocupa-se de controlar as opções associadas ao ar-
mazenamento e à numeração dos documentos. Por fim, o bloco Endereço guar-
da os dados do consultório e a alternativa de preencher ou não o cabeçalho da
receita.
Preencher ou não preencher, eis a questão. Se você tem um cabeçalho pró-
prio, mais sofisticado que o modelo simplório usado neste projeto, prefira o seu.
Então, escolha a opção Não Preencher o Cabeçalho da Receita. O programa não
perderá tempo tentando substituir palavras-chave que não irá encontrar. No en-
tanto, se você não tem um cabeçalho e quer começar, desde já, a usar uma recei-
ta personalizada, informe seus dados pessoais/ profissionais, e utilize sem medo
o cabeçalho de Receita.dot.
O preenchimento do cabeçalho e do rodapé traz um aspecto inédito. Até
agora, sempre trabalhamos com o corpo do documento. Para editar essas re-
giões que ficam em segundo plano, é necessário torná-las acessíveis. O acesso ao
cabeçalho é dado pelas linhas:

ActiveDocument.ActiveWindow.View.Type = wdPrintView
ActiveWindow.ActivePane.View.SeekView = wdSeekCurrentPageHeader

Na verdade, somente a segunda linha é que coloca o cabeçalho (PageHea-


der) em primeiro plano. A linha anterior coloca a página no modo Layout de
Impressão (wdPrintView), um pré-requisito para se ter acesso ao cabeçalho ou ro-
dapé. Se o documento não estiver nesse modo de visualização, a segunda linha de
código, acima, provoca um erro. De modo similar, abre-se o rodapé com o mes-
mo comando, apenas trocando o valor da propriedade para wdSeekCurrentPage-
Footer. E, para retornar ao corpo do documento, wdSeekMainDocument.
Para concluir o projeto, falta apenas lembrar que, no módulo ThisDocu-
238 ment do modelo Receita.dot, você deve incluir a seguinte rotina:
Private Sub Document_New()
frmReceita.Show
End Sub

Como toda rotina Document_New, ela garante a abertura do formulário


frmReceita sempre que um novo documento é criado com base no modelo Re-
ceita.dot. No final, a receita produzida tem o aspecto mostrado na Figura 27.5.

F I G U R A 2 7 . 5 A receita pronta: cabeçalho e rodapé


preenchidos e personalizados

Para ir mais além


1. Preste atenção para duas propriedades das caixas de texto DoseUso, na
orelha Receita. Como o conteúdo dessas caixas pode não caber em uma
única linha, elas têm a propriedade MultiLine definida para True. Isso
239
garante a introdução de uma quebra de linha automática no final do
controle, evitando que o texto prossiga na mesma linha, indefinidamen-
te. A outra propriedade é ScrollBars, ajustada para 2 – fmScrollBarsVer-
tical. Com isso, se o texto não couber na altura do controle, surgirá, au-
tomaticamente, uma barra vertical para facilitar ao usuário o acesso a
qualquer parte do texto.
2. Veja as caixas de verificação Não Armazenar as Receitas Emitidas e Não
Preencher o Cabeçalho da Receita. Ambas definem uma situação pelo
lado negativo. No arquivo INI, ao contrário, elas são representadas por
chaves afirmativas:
SalvarDocs=Sim
Cabeçalho=Sim

Portanto, ao gravar a informação marcada nesses controles e também ao


recuperá-las no arquivo de inicialização, é preciso inverter o sinal da in-
formação. Se houver “Sim” no arquivo INI, o valor da caixa de verifica-
ção deve ser falso. E, inversamente, se a caixa está marcada (valor igual a
True), registre-se “Não” no arquivo Receita.ini.
3. Pense num sistema mais completo de automação para médicos. Além de
emitir receitas, esse sistema poderia cadastrar pacientes e armazenar in-
formações sobre eles – as prescrições da receita e outras anotações –
num banco de dados. Como todo projeto mais arrojado, dá trabalho,
mas é perfeitamente possível fazê-lo sem sair do Word. Ou, se for o caso
– por que não? –, usar também recursos de outros aplicativos do Office,
como o Excel e o Access. Tente. Com certeza, você não vai precisar de
informações mais complexas do que as mostradas neste livro.
4. O modelo de documento Receita.dot foi desenhado de modo a aprovei-
tar ao máximo as bordas do papel. Isso leva a variações de comporta-
mento de uma impressora para outra. Se, por acaso, em sua impressora
a tabela que contém os bilhetes ficar fora da área de impressão, ajuste-a,
convenientemente, com pequenos retoques, a fim de que toda ela caiba,
justa, numa página A4.

240
Construa bibliotecas públicas
Neste projeto, conforme você viu, rotinas inteiras foram reaproveitadas
de outra aplicação. Depois que você começa a desenvolver certa
experiência em programação, nota que uma série de procedimentos
tendem a se repetir. Isso ocorre, especialmente, com atividades “buro-
cráticas”, como exibir caixas de diálogo do Word e capturar as defini-
ções do usuário, verificar se um diretório existe ou formatar um
determinado tipo de string.
Neste livro, fazia sentido copiar rotinas de um projeto para o ou-
tro porque a intenção era tratar cada projeto como unidade isolada e
auto-suficiente. Mas em seu trabalho é possível acabar com a necessi-
dade de copiar rotinas de uma aplicação para outra. Uma boa solução
é criar uma biblioteca. O que é isso? Crie um módulo no modelo Nor-
mal.dot que contenha todos os procedimentos repetitivos. Esses proce-
dimentos – subs e functions – devem ter abrangência global, para estar
disponíveis a qualquer momento para todos os outros projetos. Portan-
to, cada sub e cada função deve ser iniciada com a instrução Public.
Melhor ainda será se você construir duas bibliotecas públicas:
uma para procedimentos específicos do Word e outra para procedi-
mentos válidos em qualquer outra aplicação Visual Basic. A primeira
coleção de rotinas ficará exclusiva para o Word. A outra poderá ser ex-
portada e reaproveitada no Excel, no Access ou em qualquer outro apli-
cativo que suporte o VBA.

241
28
Epa! Word com
banco de dados?

Use o processador de texto para gerenciar


arquivos do Access

Ficha do projeto
Projeto:

Bancos de Dados no Word

O que faz:

Abre um banco de dados num formulário VBA e executa


todas as operações básicas como salvar, alterar e apagar
registros.

Arquivos e requisitos do projeto:

Formulários frmBancoDeDados e frmBancoTrat e


respectivos códigos internos.
Arquivo de banco de dados Clientes.mdb.

Conhecimento técnico:

Trabalho com bancos de dados Access, usando os Data


Access Objects, DAO. Conceitos básicos de bancos de
dados relacionais.

Nível de programação:

Avançado
242
Para quem só navega em águas rasas, o Word é para escrever texto, o Excel para
calcular, e o Access para gerenciar bancos de dados. Claro, isso não está errado,
mas representa apenas uma parte da história. E se eu disser que o Word também
serve para gerenciar bancos de dados? Não se espante: é a pura verdade – e va-
mos demonstrá-la neste capítulo.
Nosso objetivo, aqui, é criar um aplicativo que abra um arquivo Access e ofe-
reça ao usuário a oportunidade de executar todas as operações típicas de um banco
de dados, como adicionar, editar e remover registros. Para essa tarefa, precisamos,
em primeiro lugar, de um banco de dados Access. Vamos usar o arquivo Clien-
tes.mdb, criado com o Access versão 97. Com isso, pretende-se garantir o uso do
aplicativo tanto no Word 97 como no 2000, já que as duas encarnações do progra-
ma trabalham com versões diferentes das bibliotecas de acesso a dados do VBA, ou
DAO (Data Access Objects). O Word 97 utiliza o DAO 3.5 e o 2000, o DAO 3.6.
Essas bibliotecas reúnem todas as ferramentas de manipulação de dados do Access,
disponíveis a todos os produtos que suportam o VBA, via programação.

Atenção É possível que você receba uma mensagem de erro ao tentar abrir um
programa que envolve o uso das bibliotecas DAO de acesso a bancos
de dados. No ambiente do VBA, acione Ferramentas/Referências e
marque a caixa Microsoft DAO 3.6 Object Library, se estiver no Word
2000. No 97, marque Microsoft DAO 3.5 Object Library.

O banco de dados Clientes.mdb tem apenas duas tabelas, Clientes e Trata-


mento, cuja estrutura é mostrada no quadro a seguir. Os campos Pronome, na
tabela Tratamento, e Tratamento, na tabela Clientes, estão relacionados, sendo
que a tabela Tratamento funciona como fonte primária de informações. O rela-
cionamento entre esses campos é do tipo “um-para-muitos” – ou seja, um regis-
tro exclusivo na tabela Tratamento deve corresponder a um número indetermi-
nado de registros na tabela Clientes. Exemplo: o pronome “Sr.” é uma das op-
ções na tabela primária. Ele se repete em todos os registros nos quais o usuário
resolva tratar o cadastrado como “Sr.”. Mas só pode existir essa opção uma úni-
ca vez na tabela Tratamento.
O relacionamento entre as tabelas Cliente e Tratamento apresenta ainda
outra característica: reforça a chamada integridade referencial. Como a tabela
Tratamento é a fonte primária, só pode ser incluído no campo Tratamento, em
Clientes, um valor previamente cadastrado na tabela primária.
Para visualizar as informações do banco de dados, precisamos criar um
formulário, que vai receber o nome frmBancoDeDados. Nele, vamos traçar
sete caixas de texto, as quais exibirão informações de diferentes campos da
tabela Clientes. Os nomes dessas caixas acompanham os nomes dos campos:
txtNomeCliente, cboTratamento, txtEndereço, txtCEP, txtCidade, txtEstado e
txtEmail. O campo Tratamento, como vem de outra tabela, é representado por
uma caixa de combinação, na qual o usuário deve escolher uma das opções
disponíveis: Sr., Sra., Srta., Dr., Prof. etc. 243
F I G U R A 2 8 . 1 Relacionamento entre as tabelas

TABELA CAMPO TAMANHO DO CAMPO TIPO DE DADOS


(caracteres)

Clientes Código – Inteiro Longo


NomeCliente 50 Texto
Tratamento 10 Texto
Empresa 50 Texto
Endereço 50 Texto
CEP 9 Texto
Cidade 50 Texto
Estado 2 Texto
Email 50 Texto
Telefone 25 Texto
Fax 25 Texto
ValorPago — Moeda
Tratamento2 20 Texto

Tratamento Pronome 20 Texto

244
FIGURA 28.2 O formulário frmBancoDeDados: controle de
clientes

Além desses oito controles de dados – sete caixas de texto e uma caixa de
combinação –, precisamos agregar ao formulário controles para administrar e
visualizar as informações. Vamos adicionar nove botões de comando e uma eti-
queta, ou rótulo. Os botões são divididos em três grupos. No primeiro estão os
comandos manipuladores de registros: Novo, Salvar e Apagar (cmdNovo,
cmdSalvar e cmdApagar). Em seguida, vêm os botões de navegação do banco de
dados: Primeiro (cmdFirst), Último (cmdLast), Próximo (cmdNext) e Anterior
(cmdPrevious). Por fim, os botões Fechar (cmdFechar), que encerra o aplicati-
vo, e o pequeno cmdTratamento, sem legenda, localizado acima da caixa de
combinação cboTratamento. Este último dá ao usuário a possibilidade de cadas-
trar, no banco de dados, novas formas de tratamento.
Duas observações. A primeira: o nome dos botões de navegação, em inglês,
faz referência aos comandos de linguagem que você deverá usar em cada caso. A
outra: os nomes Primeiro, Último etc. não estão escritos na face dos botões de
navegação. Em lugar deles, há os já tradicionais <<, < e >, >>, como nos apa-
relhos de videocassete e gravadores de áudio. Se, em lugar dos sinais de maior e
menor, você quiser algo mais sofisticado, use a fonte WingDings 3 (disponível,
acho, apenas no Windows 98). Com ela, escreva t minúsculo para a seta à es-
querda e u minúsculo para a seta à direita. O resultado é mostrado na próxima
figura. O único cuidado a observar é que nem todo usuário possui a fonte Wing-
Dings 3 em sua máquina.
Muito bem. Só não falamos do rótulo. Situado entre os botões de navega-
ção, o rótulo labNumReg exibe o número do registro atual e o total de registros,
no formato X de Y. Com isso, o formulário está pronto. Agora, falta o principal:
a lógica dentro dele, que o faz funcionar.

245
FIGURA 28.3 Botões de navegação com setas na fonte
WingDings 3

O código por trás do formulário


Vamos acompanhar o código, passo a passo, a partir do momento em que o for-
mulário frmBancoDeDados é ativado. A primeira rotina que entra em ação é
UserForm_Initialize. Nela, abre-se o banco de dados, trabalha-se com informa-
ções das duas tabelas e, por fim, exibe-se o primeiro registro ao usuário.
A primeira tarefa é abrir o banco de dados. Depois, criam-se dois dynasets
(conjuntos dinâmicos de dados): rs, baseado na tabela Clientes e organizado em
ordem alfabética, segundo o campo NomeCliente; e rsTrat, que traz as informa-
ções da tabela Tratamento.

‘ Abre o banco de dados


strSQL = “Select * from Clientes Order By NomeCliente”
strSQLTrat = “Select * from Tratamento Order By Pronome”
strDirMDB = “c:\solucoes”

Set db = OpenDatabase(strDirMDB & “\clientes.mdb”)


Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)
Set rsTrat = db.OpenRecordset(strSQLTrat, dbOpenDynaset)

Está concluída a leitura inicial no banco de dados. Agora, é preciso mostrar


ao usuário o resultado dessa leitura. Primeiro, vamos ao último registro porque,
como rs é um dynaset, só assim é possível apurar o total de registros (lngNum)
correspondente à propriedade RecordCount:

‘ Captura o total de registros


rs.MoveLast
lngNum = rs.RecordCount
rs.MoveFirst

Em seguida, percorre-se o conjunto de dados rsTrat, da tabela Tratamento,


para preencher a caixa de combinação cboTratamento:

‘ Preenche cboTratamento
Do While Not rsTrat.EOF
cboTratamento.AddItem rsTrat!Pronome
rsTrat.MoveNext
Loop
MostraRegistro
246
Por fim, chama-se a rotina MostraRegistro, que se encarrega de exibir, nos
controles correspondentes, o registro atual – no caso, o primeiro registro do
conjunto rs. MostraRegistro coloca, em cada campo do formulário, o valor
correspondente no banco de dados:

‘ Atualiza o valor dos campos de dados


txtNomeCliente = rs!NomeCliente
cboTratamento = rs!Tratamento
txtEmpresa = rs!Empresa
txtEndereço = rs!Endereço
txtCEP = rs!CEP
txtCidade = rs!Cidade
txtEstado = rs!Estado
txtEmail = rs!Email

‘ Exibe a posição
labNumReg = rs.AbsolutePosition + 1 & “ de ” & lngNum

Na última linha, a rotina define o valor do rótulo labNumReg, que indica o


número do registro atual e o total de registros do conjunto.
O banco de dados foi aberto e seu primeiro registro está visível na tela. Pas-
semos agora para as diversas operações. Se você clicar no botão Próximo (>), o
que acontece? Basicamente, a rotina cmdNext_Click vai mover o ponteiro do
banco de dados para o próximo registro (rs.MoveNext) e chamar a rotina Mos-
traRegistro para exibir, nos controles do formulário, as informações do banco
de dados agora ativas.
Em cada movimento de navegação, esses dois comandos serão necessários.
Primeiro, o método correspondente ao botão. Depois, MostraRegistro. Mas há
também certas precauções. No caso do botão Próximo, não se pode deixar que
o ponteiro do conjunto de dados caia no vazio. Esclareçamos: ao navegar num
conjunto de dados, o ponteiro em cada momento encontra-se num registro.
Quando ele atinge o último registro e o usuário pede para que siga em fren-
te (botão Próximo), o que acontece? Ele cai naquilo que chamamos de vazio –
uma área que não corresponde a nenhum registro. O mesmo acontece, em senti-
do inverso, quando o ponteiro está no primeiro registro e o usuário aciona o bo-
tão Anterior. Essas áreas vazias são propriedades do conjunto de dados: EOF
(sigla de End of File, ou fim do arquivo) e BOF (de Beginning of File, ou início
do arquivo). Na movimentação pelo bancos de dados, deve-se evitar que o pon-
teiro caia no BOF ou no EOF. A partir desses pontos, qualquer tentativa de des-
locamento produz um erro. Por causa disso, o código da rotina associada ao cli-
que no botão Próximo fica assim:

If rs.AbsolutePosition + 1 = lngNum Then Exit Sub


If Not rs.EOF Then
rs.MoveNext 247
MostraRegistro
blnNovoReg = False
End If

A primeira linha testa se o próximo passo é o fim do arquivo. Em caso posi-


tivo, cancela-se a movimentação com a instrução Exit Sub. Aqui, o teste se faz
com a ajuda da propriedade AbsolutePosition, que indica a posição do ponteiro,
contando os registros a partir de zero.
Em seguida, move-se o ponteiro para o próximo registro, o qual é exibido
no formulário. Na última linha, indica-se que não se trata de um registro novo,
tornando o indicador blnNovoReg igual a False. Mais adiante você vai entender
a função desse indicador.
Para exibir o registro Anterior, o procedimento praticamente se repete:

If rs.AbsolutePosition = 0 Then Exit Sub


If Not rs.BOF Then
rs.MovePrevious
MostraRegistro
blnNovoReg = False
End If

Observe, no trecho de código acima, que agora trabalhamos com a pro-


priedade BOF, o início do arquivo. No mais, tudo é igual. Para os botões Últi-
mo e Primeiro, as coisas são mais simples. Vejamos o Último:

rs.MoveLast
MostraRegistro
blnNovoReg = False

Como não há nenhum perigo de cair no vazio na ida ao último registro,


executa-se o comando sem ressalvas. O mesmo acontece em relação ao primeiro
(rs.MoveFirst). Vejamos, então, as operações de modificação do registro, indi-
cadas pelos botões Novo, Salvar e Apagar.
Botão Novo. A tarefa fundamental cumprida por esse botão é limpar a área
para a digitação de um novo registro. Ao mesmo tempo, é preciso indicar que es-
tamos trabalhando com um registro zero km, e não um velho registro modificado.
Isso será importante na hora da operação Salvar. Então, o código fica assim:

blnNovoReg = True
LimpaRegistro
labNumReg = “Novo”

Na primeira linha, indica-se que o registro é novo. Na última, exibe-se a


palavra Novo no rótulo que indica o número do registro atual. Na linha do
248
meio, chama-se a sub LimpaRegistro, que apaga todo o conteúdo dos controles
no formulário. LimpaRegistro tem o seguinte código:

Dim ctl As Control

For Each ctl In Me.Controls


If Left$(ctl.Name, 3) = “txt” Then
ctl = “”
End If
Next ctl
cboTratamento = “”
txtNomeCliente.SetFocus

LimpaRegistro reduz a branco o conteúdo de todos os controles do formu-


lário e põe o foco da ação no primeiro controle: txtNomeCliente. Só para você
não achar estranho o código em LimpaRegistro, o que está escrito acima corres-
ponde ao seguinte:

txtNomeCliente = “”
cboTratamento = “”
txtEmpresa = “”
txtEndereço = “”
txtCEP = “”
txtCidade = “”
txtEstado = “”
txtEmail = “”
txtNomeCliente.SetFocus

Botão Apagar. Ao clicar nesse botão, o usuário entra numa área perigosa.
Será que ele clicou com plena consciência, ou o fez inadvertidamente? Na dúvida,
você precisa dar a ele a chance de corrigir um eventual descuido. Por isso, a
primeira tarefa, nesse caso, é perguntar ao usuário se ele de fato deseja apagar o
registro.

s = “Tem certeza de que deseja apagar este registro?”


i = MsgBox(s, vbYesNo + vbDefaultButton2 + vbQuestion, “Apagar Registro”)
If i = vbNo Then GoTo cmdApagar_Fim

Aqui, mais um parêntese. Ao apresentar a caixa de mensagem com a per-


gunta ao usuário, preste atenção para alguns detalhes. A mensagem oferece dois
botões para resposta: Sim e Não. Como se trata de uma operação perigosa (apa-
gar um registro), coloque o foco no botão que não oferece risco (Não). Assim, se
o usuário o acionar sem querer, nada acontecerá. Isso é garantido com a cons-
tante vbDefaultButton2. Outro detalhe: para apresentar o ícone com o sinal de
interrogação, adicione a constante vbQuestion. Fecha o parêntese.
249
Se o usuário responde Sim, então elimina-se o registro. Para isso, primeiro
faz-se o teste: será que o ponteiro não está no vazio (BOF ou EOF)? Se não esti-
ver, apaga-se o registro (rs.Delete), move-se o ponteiro para o próximo registro
e subtrai-se de 1 o número total de registros. Em seguida, só para evitar proble-
mas, faz-se o teste para ver se o ponteiro não caiu no fim do arquivo. Se caiu, ele
é reposicionado para o último registro. Tudo isso é providenciado pelo código
seguinte:

If Not (rs.BOF Or rs.EOF) Then


rs.Delete
cmdNext_Click ‘próximo
lngNum = lngNum - 1
End If

If rs.EOF Then rs.MoveLast

Botão Salvar. Este é o mais complicado dos três comandos de modificação


do registro. A tarefa 1, quando o usuário clica nesse botão, consiste em determi-
nar se ele deseja gravar um registro novo ou um registro modificado. O registro
novo é sinalizado pelo indicador blnNovoReg, de que já falamos antes. Como
vimos, um clique no botão Novo atribui o valor True a esse flag. Somente depois
que a adição de um novo registro é confirmada (com a operação Salvar) ou
abortada (com o deslocamento para um registro qualquer) é que blnNovoReg
assume o valor False.
Há diferenças de tratamento se o registro a salvar no banco de dados é
novo ou apenas alterado. No primeiro caso, é preciso usar o comando rs.New,
que prepara o recordset para receber um novo registro. No outro, emite-se o co-
mando rs.Edit, avisando ao banco de dados que o registro, já existente, sofrerá
alterações.

‘ Adiciona ou edita registro


If blnNovoReg Then
rs.AddNew
Else
rs.Edit
End If

Seja o registro novo ou antigo, é preciso definir, item a item, o que deve ser
gravado, atribuindo, a cada campo de dados, a informação presente no corres-
pondente controle do fomulário:

‘ Define/redefine valores dos campos


rs!NomeCliente = txtNomeCliente
rs!Tratamento = cboTratamento
250 rs!Empresa = txtEmpresa
rs!Endereço = txtEndereço
rs!CEP = txtCEP
rs!Cidade = txtCidade
rs!Estado = txtEstado
rs!Email = txtEmail

Após tudo isso, o registro é salvo:

rs.Update

Por fim, chegamos a uma porção de código específica para registros novos.
Lembre-se de que o conjunto de dados exibe os registros em ordem alfabética
segundo o campo NomeCliente. Quando se inclui um novo registro, é necessá-
rio manter essa regra. Para isso, usa-se um estratagema simples, contido nas li-
nhas a seguir:

If blnNovoReg Then
blnNovoReg = False
rs.MoveLast
lngID = rs!Código
rs.Close
Set rs = db.OpenRecordset(strSQL, dbOpenDynaset)

rs.MoveLast
lngNum = rs.RecordCount
rs.FindFirst “Código=” & lngID
MostraRegistro
End If

Primeiro, desliga-se o flag blnNovoReg: se já foi salvo, o registro não é


mais novo. Depois, move-se o ponteiro até o fim do recordset, a fim de armaze-
nar, na variável lngID, o número de código do último registro – aquele que aca-
bou de ser gravado. Então, o recordset rs é fechado e aberto outra vez. Obtém-se
o número total de registros (lngNum) e exibe-se, exatamente, o registro que aca-
bou de ser gravado. Essas operações transcorrem tão rapidamente que o usuário
nem percebe. Como resultado, o registro recém-adicionado passa a ser exibido
com um número – 17 de 95, por exemplo. O 17 corresponde à posição do novo
registro, respeitada a ordem alfabética que define o conjunto de dados.
O último item a mencionar está ligado ao pequeno botão Tratamento.
Quando se clica nele, abre-se o formulário frmBancoTrat, que é o segundo do
projeto. Esse formulário tem botões de navegação, botões de edição e apenas
um campo de informação: txtPronome. A lógica de navegação é semelhante à já
discutida para o formulário principal. Os botões de edição (Novo, Salvar e
Apagar) fazem as tarefas esperadas.
251
Esse formulário trabalha com um reduzido conjunto de dados: a tabela
Tratamento, que tem apenas um campo, Pronome, e nele as formas de trata-
mento cadastradas. A operação mais simples, no caso, é adicionar um novo re-
gistro. Até aí, tudo bem. No entanto, se você resolver apagar um registro exis-
tente ou modificá-lo, entram em cena alguns senões.

F I G U R A 2 8 . 4 O segundo formulário: formas de tratamento

Como sabemos, as duas tabelas do banco de dados Clientes.mdb mantêm


um relacionamento entre si tendo como eixos os campos Tratamento, na tabela
Clientes, e Pronome, na tabela Tratamento. Além do mais, esse relacionamento
é marcado pela opção Manter Integridade Referencial”, oferecida pelo Access.
Se, por exemplo, o pronome “Sr.”, assim escrito, já foi usado em algum registro,
o banco de dados não vai aceitar que você o modifique para “Senhor”. A própria
inteligência embutida no arquivo MDB vai dizer que já existem registros na ta-
bela Clientes utilizando a informação que você deseja alterar. Da mesma forma,
não será possível apagar um registro de Tratamento já em uso na outra tabela.
Em ambos os casos, o programa apresentará o seguinte aviso de erro:

FIGURA 28.5 Aviso para manter a lógica do relacionamento


entre tabelas

Depois que você faz as alterações permitidas na tabela Tratamento, elas


precisam ser refletidas na lista da caixa de combinação cboTratamento, no for-
mulário principal. Afinal, o conteúdo dessa lista não é outra coisa senão a pró-
pria tabela. Mas como executar essa atualização se existe a fronteira entre os
dois formulários? Precisamos, aqui, lançar mão de uma leve artimanha.
Observe: no formulário frmBancoDeDados existe uma rotina chamada
252 PreencheRsTrat. Ela varre a tabela Tratamento e transfere seu conteúdo para a
lista da caixa cboTratamento. PreencheRsTrat é acionada pela primeira vez no
evento de inicialização do formulário. O segredo dessa rotina está no fato de ela
ser declarada como Public. Assim, pode ser chamada a partir de outro módulo
qualquer do projeto – o que resolve nosso impasse.
Após fazer as modificações no formulário auxiliar, você o fecha. Nesse mo-
mento, antes que o form seja eliminado da memória, entra em ação o evento Ter-
minate. Na rotina associada a esse evento, chamamos PreencheRsTrat no formu-
lário principal. Para isso indicamos o nome do módulo e o nome da rotina:
frmBancoDeDados.PreencheRsTrat

Pronto. A caixa de combinação Tratamento é esvaziada e repreenchida


com o conteúdo atualizado da tabela Tratamento. Com essas rotinas, sua aplica-
ção está pronta para adicionar, remover ou modificar registros no banco de da-
dos. E fica provado – pelo menos com um exemplo – que o Word não serve ape-
nas para escrever texto.

Para ir mais além


1. Você deve ter observado que o projeto não inclui a detecção de mudan-
ça no registro atual. Quer dizer, se um registro estiver na tela e você o
modificar, sem salvar, perderá todas as alterações ao passar para outro
registro. Com um detector de mudança, quando você tentasse mudar de
registro, o programa perguntaria: deseja salvar as modificações? Você
pode incluir um detector no projeto. Basta criar uma variável booleana
válida para todo o formulário (por exemplo, blnRegistroMudou) e
dar-lhe valor verdadeiro se houver qualquer mudança num dos contro-
les. A mudança é indicada pelo evento Change. Por exemplo, para a cai-
xa txtNomeCliente:
Private Sub txtNomeCliente_Change()
blnRegistroMudou = True
End Sub

Então, nos eventos associados aos botões de navegação, você verifica o


valor de blnRegistroMudou e, se for o caso, pergunta ao usuário se quer
salvar as modificações. Se a resposta for positiva, chama-se a rotina
cmdSalvar_Click.
2. O gerenciamento de banco de dados oferecido por este projeto é bem
simples. Não inclui, por exemplo, a possibilidade de listar registros ou
imprimir relatórios. Mas tudo isso é possível, mediante a criação de do-
cumentos do Word a partir das informações do banco de dados, confor-
me é mostrado no capítulo dedicado ao Assistente de Banco de Dados
ou no capítulo sobre os conversores de arquivos do Word. Tente fazer
uma dessas adaptações. 253
Integridade referencial?!!
As tabelas Tratamento e Clientes, no projeto atual, estão relacionadas
de forma que a primeira fornece dados primários à segunda. Para ter
um exemplo prático do que isso significa, abra o aplicativo, digite uma
palavra qualquer no campo Tratamento e tente salvar o registro. O
programa vai apresentar a seguinte mensagem de erro: “Não foi
possível adicionar ou alterar registros, pois um registro relacionado é
exigido na tabela ‘Tratamento’.”
Em palavras mais simples, isso significa que, como as tabelas es-
tão relacionadas, você não pode incluir no campo Tratamento da tabe-
la Clientes um item que não esteja previamente cadastrado na tabela
Tratamento. Essa reação do banco de dados tem o objetivo de manter a
chamada integridade referencial. Em respeito a essa lógica, também
não se aceita a eliminação da tabela Tratamento de um registro já in-
cluído em Clientes.
Isso é pura lógica.Veja um exemplo real. Num aplicativo para ge-
renciamento de pessoal, admita que você tem duas tabelas: uma cha-
mada Funcionários, que reúne os dados de cada empregado, e a outra,
Seções, com a lista dos departamentos da empresa. Você já percebeu:
a tabela primária, aqui, é Seções. Portanto, não é possível incluir na ta-
bela Funcionários uma área não cadastrada em Seções. Seria o mesmo
que dizer: “este funcionário trabalha em nossa empresa numa área
que não existe!”
Se você pensar em outras situações, poderá encontrar dívidas sem
devedores, vendas sem compradores e objetos (mercadorias, docu-
mentos, valores) que se movimentam, mas não se sabe nem de onde,
nem para onde. É esse tipo de absurdo que a manutenção da integrida-
de referencial procura evitar.

254
29
Os dados estão
na planilha

No Word, use os métodos do Access


para gerenciar arquivos do Excel

Ficha do projeto

Projeto:

Planilha como banco de dados

O que faz:

Abre uma planilha Excel e trabalha com ela como se fosse


um banco de dados, empregando recursos de
gerenciamento do Access.

Arquivos e requisitos do projeto:

Formulário frmExcel e código interno.


Arquivo do Excel PlClient.xls.

Conhecimento técnico:

Utilização dos métodos do Data Access Objects, DAO, para


planilhas Excel.

Nível de programação:

Avançado
255
No capítulo anterior, vimos como um banco de dados do Access pode ser
controlado a partir do Word. Agora, na mesma linha de raciocínio, vamos mos-
trar como trabalhar com uma planilha do Excel, tratando-a como um banco de
dados. Você vai ver que os procedimentos são bastante semelhantes aos utiliza-
dos para o arquivo do Access.
O ponto de partida, neste caso, é o arquivo Plclient.xls. Para manter o pa-
ralelismo com a solução anterior, esse arquivo contém apenas uma folha de da-
dos (Plan1), a qual exibe as mesmas informações da tabela Clientes no banco de
dados Clientes.mdb. Portanto, nossa intenção é construir um projeto idêntico
ao anterior, tendo essa planilha como base de dados.

F I G U R A 2 9 . 1 A planilha Excel que sevirá como banco de dados


para o projeto

Como a planilha já está pronta, o primeiro passo é construir, no VBA do


Word, um formulário para manipulação dos dados. Vamos chamá-lo de
frmExcel. Sua estrutura é completamente idêntica à do formulário criado no
projeto anterior. Há apenas uma diferença: em lugar de uma caixa de combina-
ção com as opções de tratamentos, temos aqui uma caixa de texto comum.
Vejamos o que acontece com a primeira rotina que entra em ação (User-
Form_Initialize) quando se ativa o programa. A tarefa básica consiste em
abrir a planilha, verificar o número de registros existentes e exibir o primeiro
deles. No que se refere aos procedimentos de bancos de dados, tudo é seme-
lhante ao já visto no projeto anterior. Mas há alguns macetes relativos à aber-
tura da planilha. O arquivo XLS funciona como o banco de dados e a folha de
cálculo (quer dizer, a planilha) faz o papel de uma tabela. O nome da planilha
deve receber um cifrão no final. Eis porque a variável strFolhaPlanilha é
mostrada abaixo como “Plan1$”, quando o nome da folha de cálculo é ape-
nas Plan1.

strArquivoPlanilha = “c:\solucoes\plclient.xls”
strFolhaPlanilha = “Plan1$”
256
F I G U R A 2 9 . 2 O formulário frmExcel: planilha como
banco de dados

Set db = OpenDatabase(strArquivoPlanilha, _
False, False, “Excel 8.0")
Set rs = db.OpenRecordset(strFolhaPlanilha)

Simplificadamente, o método OpenDatabase obedece à seguinte sintaxe:


OpenDatabase (nomedobancodedados, exclusivo, somenteleitura, conexão)
Veja a seguir o que significa cada um dos parâmetros exigidos na linha acima:

PARÂMETRO OBSERVAÇÃO

Nomedobancodedados Caminho completo do arquivo de banco de dados.

Exclusivo – True, abre o banco de dados em modo exclusivo.


– False, abre o banco de dado sem modo
compartilhado.

Somenteleitura – True, abre o arquivo somente para leitura.


– False, abre o arquivo para leitura e gravação.

Conexão Uma string que indica o tipo de banco de dados, a


senha de acesso e outras informações.

No parâmetro conexão, usaremos aqui apenas o tipo de banco de dados:


“Excel 8.0”, válido para planilhas das versões 97 e 2000. Para abrir uma plani-
lha do Excel 95, por exemplo, você deve usar a string “Excel 7.0”.
Ao contrário do que ocorre com os bancos de dados Access, não existe o
perigo da movimentação indevida do ponteiro de registros para fora da área de
trabalho. Portanto, não há com que se preocupar nas rotinas dos botões de na- 257
vegação. Ao atingir o último registro, o programa simplesmente se recusa a se-
guir em frente. O mesmo ocorre com o primeiro registro: nada ocorre se você
clicar no botão Anterior.
Um detalhe: quando você clicar no botão Apagar, vai receber uma mensa-
gem, indicando que não é possível eliminar registros em bases de dados do
Excel. De fato, ao acessar pasta de trabalho com o DAO, não há um método
para apagar registros. Mas você pode acrescentar e editar todas as informações.

Para ir mais além


1. Neste projeto também é possível usar uma caixa de combinação para
apresentar uma lista de pronomes de tratamento disponíveis. Basta fa-
zer um paralelo com o banco de dados Access, criando nova folha de da-
dos para conter a lista de pronomes. Na verdade, o arquivo plclient.xls
contém duas folhas de cálculo. Uma, Plan1, contém a tabela de clientes.
A outra, Plan2, exibe uma tabela com uma única coluna (Pronome), a
qual contém a lista de tratamentos disponíveis.
Então, desenhe, numa área livre do formulário, uma caixa de combina-
ção – por exemplo, cboTratamento. Em seguida, vá à rotina User-
Form_Initialize e acrescente as seguintes linhas junto às outras declara-
ções de variáveis:
Dim rsTrat As Recordset

Agora, depois da linha que define o conjunto de dados rs (Set rs =...),


escreva:
Set rsTrat = db.OpenRecordset(“Plan2$”)

Do While Not rsTrat.EOF

F I G U R A 2 9 . 3 A tabela Plan2 no Excel


258
cboTratamento.AddItem rsTrat!Pronome
rsTrat.MoveNext
Loop

Execute a aplicação e verifique o conteúdo da caixa de combinação. Os pro-


nomes estão lá! Sim, eles vieram da folha Plan2 da pasta de dados do Excel.
Para que a caixa cboTratamento exiba as informações do banco de
dados, registro a registro, será necessário aplicar a ela todos os métodos
antes aplicados à caixa de texto txtTratamento.
2. No Access, a manutenção da integridade referencial é um item que faz
parte da própria estrutura do banco de dados. Vimos isso no capítulo
anterior. Neste projeto, se você quiser garantir que somente pronomes
já cadastrados possam ser incluídos na planilha, terá de cuidar pessoal-
mente disso. Uma saída é, por exemplo, ajustar as propriedades da caixa
de combinação para que aceite somente itens constantes da lista.

Detalhes na caixa de mensagem


Ao apresentar uma caixa de mensagem com pergunta ao usuário,
preste atenção nos detalhes. Eles fazem uma enorme diferença nesse
caso. Veja o seguinte trecho de código:
s = “Tem certeza de que deseja apagar este registro?”
i = MsgBox(s, vbYesNo + vbDefaultButton2 + vbQuestion, _
“Apagar Registro”)
If i = vbNo Then GoTo cmdApagar_Fim

A constante vbYesNo indica que a caixa de mensagem exibirá


dois botões de comando: Sim e Não. Outra constante, vbQuestion, ga-
rante a exibição de um ícone com o sinal de interrogação. É mais uma
informação ao usuário, mostrando que ele precisa dar uma resposta. E
esse valor vbDefaultButton2, para que serve? Essa constante coloca o
foco da ação no botão 2 (Não). Num caso como o do exemplo, em que
a resposta Sim deflagra a destruição de um item, o botão-padrão deve
ser sempre o que não causa nenhum problema. Se, por acaso, o usuá-
rio esbarrar na tecla Enter, sem querer, nada acontecerá.

F I G U R A 2 9 . 4 A mensagem: foco no botão Não


259
30
Do banco de dados
para o documento

Monte um controle imobiliário com o Word


e recursos de bancos de dados
Ficha do projeto
Projeto:

Controle de Aluguéis

O que faz:

Cadastra e gerencia clientes, emitindo relatórios simples e


recibos de aluguel personalizados para uma pequena imobi-
liária ou para pessoa física que gerencia locações de imóveis.

Arquivos e requisitos do projeto:

Formulário frmDocBDados e código interno.


Arquivo Clientes.mdb, com o banco de dados Access.
Modelo para recibos de aluguel Reciboal.dot.
Biblioteca para geração de valores por extenso em reais,
Extens32.dll.

Conhecimento técnico:

Trabalho com bancos de dados Access, usando os Data


Access Objects – DAO. Preenchimento automático de um
modelo de documentos. Geração de relatórios, a partir de
um banco de dados.

Nível de programação:

Avançado
260
Nos dois capítulos anteriores, você viu como o Word tem condições de traba-
lhar com arquivos do Access e do Excel, gerenciando-os com métodos de bancos
de dados. Agora vamos usar esses mesmos recursos, combinando-os com a pro-
dução automática de documentos no Word. Portanto, vão-se encontrar aqui
técnicas de gerenciamento de bancos de dados e esquemas de produção de do-
cumentos, também já vistos em capítulos anteriores.
Neste projeto, vamos trabalhar com o mesmo banco de dados (Clien-
tes.mdb) utilizado dois capítulos atrás, no projeto Banco de Dados no Word.
Como agora a intenção é construir documentos, utilizaremos também um mo-
delo do Word (Reciboal.dot) e um formulário. Este último, chamado frmDocB-
Dados, é semelhante ao daquele projeto, tanto no design como no código. Por-
tanto, vamos destacar aqui o que é diferente.
Antes de avançar para o traçado do formulário, é importante determinar
quais são nossos objetivos com este novo projeto. A idéia é oferecer a uma pe-
quena imobiliária, ou a um locador pessoal de imóveis, um pequeno controle de
seus clientes. Com o projeto Controle de Aluguéis, associado à fictícia Imobiliá-
ria Cidade Aberta, ele vai poder cadastrar clientes, listá-los em relatórios e emi-
tir recibos personalizados.
Essas funções demandaram a inclusão de um novo campo na tabela Clien-
tes. Trata-se de ValorPago, que abriga o valor do aluguel. Na verdade, esse cam-
po já estava lá, simplesmente não havia sido utilizado até o momento. Aparecem
também três novas caixas de combinação: Mês, Ano e Tratamento – nenhuma
delas ligada ao banco de dados. Nas duas primeiras o usuário deve escolher o
mês e o ano de referência na hora de emitir um recibo de aluguel.

F I G U R A 3 0 . 1 Controle imobiliário: cadastro, relatório e recibo

A terceira caixa, embora também se chame Tratamento, tem um conteúdo


diferente de sua homônima no projeto Banco de Dados no Word. Em vez de 261
“Sr.”, “Sra.”, lista opções como “do Sr.”, “da Sra.” ou simplesmente “de”. Seu ob-
jetivo é fornecer, pronta, uma partícula de texto para a redação do recibo: “Rece-
bemos do Sr. Fulano de Tal...” As informações que compõem as listas dessas três
caixas de combinação provêm do próprio código, e não do banco de dados.
Além dos objetos associados ao gerenciamento do banco de dados, o for-
mulário frmDocBDados exibe ainda dois botões de comando – Recibo e Relató-
rio – envolvidos por uma moldura cuja legenda é Imprimir. As caixas Valor,
Mês e Ano também estão circunscritas por uma moldura – Dados para o Recibo
–, indicando sua vinculação direta à emissão desse tipo de documento. A nova
caixa de texto Telefone também se associa a um campo já existente antes no
banco de dados.
Outra novidade especial é a caixa de combinação Localizar (cboLocalizar),
que funciona como um instrumento de busca rápida. Escolha um nome na lista
de Localizar, e o registro correspondente é trazido para o primeiro plano.

As caixas Tratamento, Mês e Ano


Passemos aos destaques no código deste projeto. Na rotina de inicialização do
formulário, além dos procedimentos relativos ao banco de dados, chama-se a
sub PreencheCombos. Esta encarrega-se de fornecer conteúdo às caixas de com-
binação Tratamento, Mês e Ano. O preenchimento das duas últimas envolve al-
guns macetes. A caixa cboMês exibe os nomes dos meses por extenso. Para in-
cluí-los, poderíamos ter usado repetidamente o método AddItem, para janeiro,
fevereiro etc. Mas há uma forma mais elegante: capturar o nome do mês a partir
de um loop de doze datas quaisquer, uma em cada mês:

With cboMês
For n = 1 To 12
.AddItem Format$(“1/” & n & “/2000", ”mmmm")
Next n
.ListIndex = Month(Now) - 1
End With

A caixa Ano é preenchida com 21 anos: o atual, dez anteriores e dez futu-
ros. Tanto em cboMês como em cboAno, a propriedade ListIndex é ajustada de
tal forma que os controles exibam, como padrão, o mês e o ano atuais.

With cboAno
For n = Year(Now) - 10 To Year(Now) + 10
.AddItem n
Next n
.ListIndex = 10
End With
262
Caixa de combinação Localizar
O funcionamento da caixa de combinação Localizar (cboLocalizar) exige um es-
forço adicional de programação. No evento de inicialização do formulário, o pro-
grama chama o procedimento AtualizaCboLocalizar. Essa sub-rotina cria um con-
junto de dados (recordset) chamado rsNome, que lê, na tabela Clientes, os cam-
pos Código e NomeCliente. Código é o número que fornece o identificador úni-
co de cada registro. Os valores de rsNome são adicionados à lista da caixa de
combinação Localizar. Preste atenção ao trecho abaixo: usa-se o método AddItem
para preencher a primeira coluna e a propriedade List para incluir o código na
coluna 2 (na verdade, o índice dela é 1 porque o da primeira coluna é 0).

i = -1
Do While Not rsNome.EOF
i = i + 1
cboLocalizar.AddItem rsNome!NomeCliente
cboLocalizar.List(i, 1) = rsNome!Código
rsNome.MoveNext
Loop

Vale lembrar que, desde o procedimento UserForm_Initialize, a caixa cbo-


NomeCliente já foi caracterizada como tendo uma lista de duas colunas:

cboLocalizar.ColumnCount = 2

Quando o usuário seleciona um nome na lista (evento Click da caixa de


combinação), o programa pega o código associado ao nome escolhido e usa o
método FindFirst para encontrar o registro.

lngCódigo = CLng(cboLocalizar.Column(1))
If blnRegistroMudou And Not blnNovoReg Then QuerSalvar
rs.FindFirst “Código =” & lngCódigo
MostraRegistro
cboLocalizar.ListIndex = -1

Como cboLocalizar tem apenas a função de busca – não precisa exibir ne-
nhuma informação –, tão logo ela ajuda a encontrar um registro, seu texto é
anulado, definindo-se valor da propriedade ListIndex para –1.

Detector de alterações
Uma deficiência do projeto Banco de Dados no Word era sua incapacidade de
detectar alterações ocorridas no registro durante sua exibição na tela. Assim, ao
passar de um registro para outro, perdiam-se as alterações feitas e não salvas no
263
primeiro. O projeto atual preenche essa lacuna. O detector de mudanças é mon-
tado da seguinte maneira: quando se modifica o texto de um controle, essa ação
é indicada no evento Change. Com base nisso, o primeiro passo é criar uma va-
riável booleana, blnRegistroMudou, para representar a mudança do registro.
Exemplo, para a caixa de texto txtTelefone:

Private Sub txtTelefone_Change()


blnRegistroMudou = True
End Sub

A linha acima (blnRegistroMudou = True) deve ir para os eventos Change


de todos os controles vinculados ao banco de dados. Isso vale para todas as cai-
xas de texto, mas não atinge as caixas de combinação.
Agora, a segunda parte. Nos eventos Click dos botões de navegação, o pro-
grama verifica o valor de blnRegistroMudou. Em caso positivo, pergunta ao
usuário se deseja salvar as modificações. Se ele responder Sim, entra em cena a
rotina cmdSalvar_Click. Portanto, a pergunta “o registro mudou?” deve ser fei-
ta no evento Click dos quatro botões de navegação e da caixa Localizar. Em to-
dos eles, a rotina Objeto_Click deve conter a seguinte linha:

If blnRegistroMudou Then QuerSalvar

Não estranhe: QuerSalvar é o nome da rotina que faz a pergunta ao usuá-


rio, por meio da seguinte caixa de mensagem:

F I G U R A 3 0 . 2 Mensagem emitida pela rotina QuerSalvar

Outro ponto em que o detector de alterações deve ser acionado é no fecha-


mento do formulário, que pode ser disparado a partir de dois comandos: o bo-
tão Fechar e o botão com o pequeno X, também chamado Fechar, no canto su-
perior direito do form. Portanto, a linha de teste também foi inserida no evento
QueryClose, que ocorre antes de o formulário ser eliminado da memória.
Para que o programa não dê alarmes falsos, apontando mudança no regis-
tro depois do acionamento do botão Novo, é preciso afirmar, logo aí, que não
aconteceu nenhuma alteração. É por isso que, na rotina cmdNovo_Click, você
encontra a linha:

264 blnRegistroMudou = False


Emissão de recibos
Na Imobiliária Cidade Aberta, é fácil emitir um recibo personalizado. Basta sele-
cionar o registro do cliente e clicar no botão Recibo. A rotina cmdRecibo_Click
cria um documento novo com base no modelo Reciboal.dot e preenche esse do-
cumento com os valores lidos nos controles do formulário. O recurso usado
aqui baseia-se nos serviços do objeto Selection.Find, responsável pelas funções
de localizar e substituir no Word. Para tanto, como já vimos em outros projetos,
o recibo-modelo precisa conter palavras-chave que serão encontradas e substi-
tuídas pelas variáveis adequadas.
Um detalhe oculto, mas que merece ser ressaltado nesse modelo de recibo,
é a data automática. Em projetos anteriores, usei o VBA para montar a data e in-
seri-la no documento. Nesse caso, resolvi aproveitar a data que o Word, sem
programação, é capaz de oferecer. Ao elaborar um documento, há, pelo menos,
duas maneiras interativas de incluir datas. A mais simples é utilizar o comando
Inserir/Data e Hora. Se, na tela Data e Hora, a caixa de verificação Atualizar
Automaticamente estiver desligada, você simplesmente insere a data ou hora no
formato escolhido. Com aquela caixa marcada, insere um campo de data/hora –
que aparentemente serve para os propósitos de automatizar o preenchimento de
documentos. O problema é que o valor mostrado nesse campo vai mudar cada
vez que você abrir o documento. Ou seja, ela mostra dia 20 hoje, dia 21 amanhã.
Em suma, não fica registrada ali a data da criação do texto. Portanto, o coman-
do Inserir/Data e Hora não é o caminho.
A outra maneira de automatizar datas está também no menu Inserir, alter-
nativa Campo, categoria Data e Hora.Você encontra lá seis possibilidades. O
campo que nos interessa é CreateDate. Ele fornece exatamente o que queremos:
a data em que o documento foi criado. Assim, o conteúdo do campo passa a ser:

CREATEDATE \@ “d’ de ‘MMMM’ de ‘yyyy”

A parte depois do sinal @ é o formato da data, aqui ajustado para algo


como “22 de março de 2000”. No Word 2000, a caixa de diálogo para inserção
de campos é mostrada na Figura 30.3. Para ver o conteúdo do campo, acione
Ferramentas/Opções/orelha Exibir, caixa Código de Campos.
Para emitir recibos reais com o Controle de Aluguéis, você precisa adaptar
o modelo Reciboal.dot aos seus padrões. Primeiro, ir ao cabeçalho e colocar lá o
nome e o logotipo de sua própria empresa, acompanhados de endereço, telefo-
ne etc. Precisa, também, ajustar o próprio texto do recibo aos seus padrões.
Você pode modificar tudo, desde que preserve as palavras-chave. Nesse modelo
elas são:

quantiavalorpago
pronometratamento
nomedopagador 265
F I G U R A 3 0 . 3 Inserir/Campo: para exibir datas que não
mudam

quantiavalorpago
quantiaporextenso
mespagamento
anopagamento
endereçodoimóvel

Só para lembrar: as palavras-chave são assim esquisitas para evitar a confu-


são com qualquer outro termo do texto. Se você quiser, pode incluir novas va-
riáveis, como o nome da pessoa que assina o recibo, o cargo que ela ocupa e até
mesmo o nome da empresa.
No final, o recibo produzido tem o layout mostrado na Figura 30.4.

Nota O recibo só pode ser emitido se duas condições estiverem satisfeitas.


A primeira: o arquivo Extens32.dll deve estar na pasta de sistema do
importante Windows. A função extenso (assim mesmo, com letra minúscula),
residente nessa DLL, é a responsável por fornecer o texto do número
por extenso. A declaração da função, nos moldes da interface de
programação do Windows, deve ser feita assim:

Public Declare Function extenso Lib “Extens32.dll” _


(ByVal valor As String, ByVal Retorno As String) As Integer

O segundo requisito está ligado ao fato de que essa declaração só pode ser fei-
ta num módulo: não é aceito o código de um formulário. Por isso, o formulário
frmDocBDados deve ser acompanhado de um módulo que contenha a linha acima.
266
F I G U R A 3 0 . 4 Recibo de aluguel: os valores em
destaque vêm do aplicativo

Relatório
O relatório produzido por esta aplicação lista, em ordem alfabética por nome,
todos os clientes da imobiliária, com seus dados básicos: endereço, telefone, va-
lor do aluguel. A rotina cmdRelatório_Click, disparada com o clique no botão
Relatório, envolve uma série de detalhes interessantes.
A lista de clientes é apresentada em forma de tabela, com todos os campos
fundamentais mostrados no formulário. O documento é montado, basicamente,
com a ajuda do método TypeText, aplicado ao objeto Selection em diferentes si-
tuações. Primeiro, cria-se um documento novo e ajusta-se a orientação da pági-
na para a posição horizontal, para que os campos da tabela – nove – sejam aco-
modados com mais espaço. Em seguida, escrevem-se duas linhas de cabeçalho
mais uma linha em branco.
Agora, vem a tabela. Cada linha é formada pelos valores dos campos sepa-
rados pelo caractere Tab, aqui representado pela constante intrínseca vbTab.
No final, a constante vbCrLf, que introduz novo parágrafo. Primeiro, a linha
com os nomes dos campos, ou seja, os títulos da tabela:

Selection.TypeText “No.” & vbTab & “Nome” & vbTab & _


“Aluguel (R$)” & vbTab & “Endereço” & vbTab & _
“CEP” & vbTab & “Cidade” & vbTab & _
“Estado” & vbTab & “Telefone” & vbTab & _
“E_mail” & vbCrLf

Seguem-se as outras linhas da tabela, agora retiradas do banco de dados.


Um loop percorre todo o conjunto de dados rs e vai enfileirando os valores de
cada campo a ser incluído na tabela. Ao escrever o código do qual vai resultar a 267
tabela, é necessário prestar muita atenção à seqüência utilizada na linha de cabe-
çalho, a fim de que as outras linhas correspondam exatamente.

n = 0
Do While Not rs.EOF
n = n + 1
Selection.TypeText CStr(n) & vbTab & rs!NomeCliente & _
vbTab & Format(rs!ValorPago, “#,##0.00") & _
vbTab & rs!Endereço & vbTab & rs!CEP & vbTab & _
rs!Cidade & vbTab & rs!Estado & vbTab & _
rs!Telefone & vbTab & rs!Email & vbCrLf
rs.MoveNext
Loop

O valor n incluído na tabela é um recurso para numerar seqüencialmente


cada linha da tabela. Depois de escrever todas as linhas, na verdade ainda não te-
mos a tabela. Para construí-la e formatá-la, vamos precisar de mais de um micro-
malabarismo. O primeiro deles tem por objetivo selecionar somente a parte do
documento que formará a tabela – o cabeçalho fica de fora. Como fazer isso? Ao
escrever a última linha da tabela, o cursor, naturalmente, está no final do docu-
mento. Então, vamos levá-lo até o início, estendendo a seleção. Em seguida,
para deixar à parte as três linhas do cabeçalho (duas, mais uma em branco), va-
mos mover o cursor três linhas para baixo.

With Selection
‘ Seleciona somente o texto que será tabela
.HomeKey Unit:=wdStory, Extend:=True
.MoveDown Unit:=wdLine, Count:=3, Extend:=True

Perfeito. Agora, basta usar o método ConvertToTable e temos, enfim, uma


tabela. Nem é preciso indicar que o caractere separador é o Tab, e que são nove
colunas. O Word é suficientemente esperto e faz tudo direitinho. Quer dizer –
se você ajudar. Aqui vai um exemplo em que você pode atrapalhar. Aliás, mais
um caso de atenção para os detalhes. Você vai notar, ao emitir relatórios, que a
palavra E-mail, no título da coluna, aparece como E_mail. Esta foi uma saída
que encontrei para resolver um embaralhamento da tabela que ocorre quando
se usa no título a palavra “E-mail”. A confusão ocorre, igualmente, no Word
2000 e no 97. Portanto, cuidado com o hífen no cabeçalho.
Mais detalhes: para que o valor do aluguel seja mostrado corretamente no
formulário ou no relatório – como moeda, com duas casas decimais –, é preciso
formatá-lo:

Format(rs!ValorPago, “#,##0.00")

268
Sigamos em frente. A tabela está pronta, mas precisa de ajustes. Ao criar
uma tabela, o Word atribui largura igual a todos os campos. Além disso, alinha
todas as colunas à esquerda. Para corrigir a primeira inconveniência, aplique-
mos o comando Selection.Cells.AutoFit com toda a tabela selecionada. Com
ele, as colunas se rearranjam, redistribuindo o espaço.
Quanto ao alinhamento do texto, ele só constitui problema nas colunas 1
(o número seqüencial) e na 3, o valor do aluguel. Então, vamos selecionar a pri-
meira coluna e aplicar nela o alinhamento de parágrafo à direita. Por fim, sal-
va-se o documento com o nome Lista de Clientes.doc.
A montagem do relatório envolve ainda outros detalhes, como a atribuição
de uma cor de fundo à linha de títulos da tabela e a aplicação de diferentes tama-
nhos de fontes no cabeçalho e no corpo da tabela. Analise a rotina cmdRelató-
rio_Click. Ela tem uma série de aspectos utilíssimos para quem programa com o
Word. No final, o relatório tem o aspecto mostrado pela Figura 30.5:

F I G U R A 3 0 . 5 O relatório: números formatados e cabeçalho


com destaque em cor

Para ir mais além


1. A aplicação Controle de Aluguéis é daquelas que permitem reunir um
imenso rol de idéias para modificação e ampliação. Por exemplo: você
pode incluir no banco de dados e no formulário um campo do tipo Me-
morando, para armazenar informações textuais sobre os clientes.
2. Somente o item Relatório dá pano para muitas mangas. Basta você parar
alguns minutos e já terá uma lista de diferentes relatórios. Pense – e po-
nha as mãos na massa!
269
3. Ao longo deste livro, temos repetido, de forma clara ou implícita, que
uma parte fundamental do trabalho de programação consiste em prestar
atenção aos detalhes. Eis mais um exemplo. Em todas as rotinas em que
foi incluída, a linha de código abaixo é sempre a primeira.
If blnRegistroMudou Then QuerSalvar

No entanto, o evento cboNomeCliente_Click constitui uma exceção.


Nele, essa linha é a número dois. A mudança foi feita porque o progra-
ma acusava um erro na seguinte situação:
O registro sofreu mudança e o usuário escolhia um nome na caixa Loca-
lizar. Surgia a mensagem com a opção de salvar o registro. Se a resposta
fosse não, tudo bem. Caso contrário, vinha o erro.
Portanto, uma simples troca na posição de duas linhas aparentemente
desvinculadas e sem obrigação de manter seqüência pode produzir um
bug.
4. Ao percorrer o conjunto de dados rs para gerar o relatório de clientes,
usou-se uma variável n, que vai sendo acumulada a cada linha escrita no
documento. Uma alternativa, baseada apenas em recursos do próprio
motor do banco de dados, seria trabalhar com a propriedade Absolute-
Position. Bastaria declarar uma variável – digamos j – como Long e in-
cluir a seguinte linha dentro do loop:
j = AbsolutePosition + 1
Selection.TypeText CStr(j)

5. Uma das novidades do Word 2000 é a propriedade BackGroundPat-


ternColor, que aceita cores RGB (16,7 milhões de tonalidades). No
Word 97 só está disponível a propriedade BackgroundPatternColor-
Index, correspondente a um estoque de apenas dezoito cores. Portanto,
a linha abaixo produz um erro no Word 97, mas é aceita no 2000.
Selection.Range.Shading. _
BackgroundPatternColor = wdColorGray10

Para manter a compatiblidade com as duas versões do programa, usa-


mos sempre a propriedade BackgroundPatternColorIndex. No entanto,
se você usa o Word 2000, prefira a outra.

270
Banco de dados com senha
Se você conhece a senha, é fácil abrir um banco de dados protegido via
programação VBA. Admita que a senha seja “abc123”. Para acessar o
banco de dados, basta usar:
Set db= OpenDatabase (“g:\custos.mdb”, False, _
False, “MS Access;pwd=abc123")

Se se tratasse de uma planilha do Excel, bastaria adaptar a string


final:
“Excel 8.0;pwd=abc123"

Planilha Excel sem Excel


Nos três últimos capítulos, usamos, como banco de dados, um arquivo
do Access e outro do Excel. Partimos de arquivos prontos, criados com
os respectivos programas. Todavia, mesmo quem não tem o Access e o
Excel pode criar bancos de dados MDB e planilhas XLS, via pro-
gramação. Sobre os primeiros, consulte a ajuda do VBA quanto ao
método CreateDatabase, do DAO. Para criar pastas de trabalho do
Excel, o esquema, também baseado no DAO, é mostrado no exemplo a
seguir. Ele cria uma pasta de trabalho chamada Pasta0.xls, com uma
planilha chamada Custos. Nesta, cria dois campos: Item, de texto, e
Custo, com valores em formato Moeda. Além disso, escreve duas linhas
nessa planilha, conforme se vê na figura abaixo.

F I G U R A 3 0 . 6 A planilha Custos

Sub CriaPastaXLS()
Dim db As Database ‘banco de dados
Dim td As TableDef ‘tabela
Dim fl As DAO.Field ‘campo
Dim rs As Recordset ‘planilha
271
‘ Cria o db, adiciona a tabela (planilha)
‘ e dois campos (colunas)
Set db = OpenDatabase(“c:\teste\Pasta0.xls”, _
False, False, “Excel 8.0;”)
Set td = db.CreateTableDef(“Custos”)
Set fl = td.CreateField(“Item”, dbText, 20)
td.Fields.Append fl
Set fl = td.CreateField(“Custo”, dbCurrency)
td.Fields.Append fl
db.TableDefs.Append td

‘ Abre a tabela para edição


Set rs = db.OpenRecordset(“Custos$”)

‘ Adiciona um registro (linha)


rs.AddNew
rs(“Item”) = “Peças”
rs(“Custo”) = 2345.51
rs.Update

‘ Adiciona outro registro


rs.AddNew
rs!Item = “Acessórios”
rs!Custo = 1350.85
rs.Update

‘ Fecha o arquivo
rs.Close
db.Close

End Sub

Alguns comentários. 1. Observe que a variável fl, para o campo


de dados, é declarada como DAO.Field. Por quê? Como estamos no
Word, e este também tem seu objeto Field (campo), o prefixo DAO evita
a confusão, indicando que estamos tratando do campo de banco de
dados. 2. Ao abrir a tabela para edição, não se esqueça de adicionar o
cifrão ($) ao final do nome da tabela. 3. Ao adicionar registros, o pro-
grama acima exibe duas formas de referência ao campo de dados. A
primeira usa o nome do campo como índice textual: rs(“Custo”). A ou-
tra usa o campo diretamente como objeto rs!Custo. Há ainda uma ter-
ceira, que trabalha com índices numéricos: rs(1). 4. No código, use o
padrão americano para escrever números não inteiros: 1350.85, e não
1350,85.

272
31
Um recibo para
todas as transações

Crie um gerador de recibos configurável


para diferentes usos e situações

Ficha do projeto
Projeto:

Gerador de Recibos

O que faz:

Oferece ao usuário um programa configurável e adaptável


a diferentes tipos de recibos.

Usuários potenciais:

Qualquer usuário do Word.

Arquivos e requisitos do projeto:

Formulário frmReciboGeral e código interno, contido nos


no modelo Recibog.dot, o qual também abriga o
documento-base para o recibo. O projeto envolve ainda os
seguintes arquivos:
• Rclients.lst, lista de clientes.
• Rpessoas.lst, lista de pessoas que assinam recibos.
• Rtipserv.lst, lista de tipos e descrições de serviços.
• Extens32.dll, biblioteca para geração valores monetários
por extenso.
• Rc_ajuda.txt, arquivo de ajuda.
Conhecimento técnico:

Operações com arquivos-texto e manipulação de listas. Uso do controle MultiPage


(guias) e do objeto Selection.Find, para busca e substituição de informações em
documentos do Word.

Nível de programação:

Avançado

Depois de experimentar com o desenvolvimento de aplicativos em Word/VBA


para automatizar a emissão de diferentes documentos, resolvi criar um gerador
universal de recibos. A idéia é criar um programa configurável para emitir reci-
bos, de modo que o usuário possa utilizá-lo sem a necessidade de mexer na pro-
gramação.
A origem deste projeto é curiosa. Eu já havia escrito soluções específicas
para o preenchimento automático de memorandos, cartas, bilhetes de sorteio e
até recibos específicos, como os de aluguel. Todavia, jamais me ocorrera criar
um recibo universal, um documento pau-para-toda-obra, capaz de atender a di-
ferentes finalidades comerciais.
Foi então que um leitor, Eduardo Smith, dono de um escritório de consul-
toria em Niterói, RJ, enviou-me um e-mail perguntando como automatizar a
confecção de recibos. Respondi dizendo que tinha uma solução pronta e a man-
daria para ele. A solução de fato existia: era um gerador de recibos de aluguel.
Antes de enviá-la, passou-me pela cabeça que ela não serviria aos propósitos do
leitor.
Assim, comecei a lhe fazer perguntas (sempre via e-mail) sobre o que ele re-
almente queria fazer, qual era a tarefa a automatizar. Nessa correspondência
eletrônica, Smith revelou o que queria, mandou-me um modelo de recibo. A mi-
nha intenção era tornar a aplicação a mais genérica possível, então fomos tro-
cando idéias até chegar a um resultado final, que é o projeto Gerador de Reci-
bos, discutido neste capítulo.

O que faz o Gerador de Recibos


Como ficou claro, o programa evoluiu a partir da necessidade concreta de um
usuário e de minha intenção de torná-lo universal. Uma das idéias-chave é per-
mitir que o usuário utilize a solução de forma personalizada, não importa o tipo
de recibo que ele queira emitir. Para tanto, o Gerador de Recibos oferece as se-
guintes características:
1. Trabalha com as variáveis: valor do recibo; cidade onde é emitido; data;
nome da pessoa ou empresa pagadora; tratamento a ser dado a essa pes-
soa (senhor, senhora, empresa etc.); extenso automático do valor; mês e
ano do fato gerador do recibo; motivo do pagamento (descrição de ser-
274
viços prestados, aluguel etc.); nome da empresa recebedora; nome e
cargo da pessoa que assina o recibo. Alguns desses itens (como data) são
fornecidos pelo próprio sistema operacional. Outros, como o nome do
pagador e do recebedor, devem ser informados pelo emitente.
2. Certas informações utilizadas num recibo são recorrentes em cada em-
presa. O escritório de prestação de serviços, por exemplo, tende a ter
clientes fixos, dos quais recebe pagamentos periódicos. Da mesma for-
ma, várias pessoas dentro da empresa podem assinar os recibos. Além
disso, os recibos são emitidos pela prestação de diferentes tipos de servi-
ços. Todos esses itens (clientes, pessoas que assinam os recibos e tipos de
serviços) podem ser catalogados e se transformar em itens de escolha na
hora produzir um recibo.
3. Outros itens (como cidade e nome da empresa que emite o recibo) são
únicos e, portanto, merecem outro tipo de tratamento.
Neste projeto, mais uma vez, vamos trabalhar com um documento-modelo
para o recibo, e um formulário – a caixa de diálogo, a partir da qual o usuário vai
configurar cada recibo. A estratégia será manter as palavras-chave no documen-
to, as quais serão substituídas conforme as definições feitas pelo usuário na caixa
de diálogo.
O usuário que não conhece programação terá a liberdade de modificar, a
seu gosto, o texto do documento. Ele apenas é obrigado a manter as pala-
vras-chave, para permitir a substituição. O formato do documento também
pode ser, livremente, modificado, com a inclusão de cabeçalho e rodapé, ajuste
da folha de papel (Carta, A4, Ofício), mudança de margens, alteração dos for-
matos de parágrafo, tamanho e estilo de fontes. Os únicos itens que não podem
ser modificados – repita-se – são as palavras-chave.
Para apresentar uma imagem concreta do formulário, veja a Figura 31.1. O
formulário frmReciboGeral contém um controle Multipage, com três guias, ou
orelhas. Na orelha principal (Dados para o Recibo), são apresentados todos os
elementos necessários para a emissão de recibos. Nas outras duas estão apenas
itens de personalização das informações fixas (cidade, nome da empresa), ou
móveis (clientes, tipos de recibo etc.).

Orelha Dados para o Recibo


Para emitir um recibo, o usuário deve fazer as seguintes operações:
1. Escolher (ou digitar) o nome do pagador na caixa Nome do Pagador.
2. Escolher o tratamento para o pagador (Sr., Sra., empresa, etc.).
3. Digitar o valor recebido. O padrão é 1234,67. O programa incluirá, au-
tomaticamente, a separação de milhares, se necessário (1.234,67).
275
F I G U R A 3 1 . 1 O formulário para a emissão de recibos: com
orelhas

4. Selecionar a pessoa que assina o recibo.


5. Selecionar o mês e o ano aos quais o recibo se refere. No caso de não se
tratar de recibo repetitivo, o usuário tem a liberdade de modificar o mo-
delo de recibo, eliminando as variáveis relativas a mês e ano.
6. Escolher o tipo de recibo.
7. Clicar no botão OK.
Antes de disparar a confecção do documento, o Gerador de Recibos dá ao
usuário a oportunidade de rever suas escolhas e voltar para corrigi-las. Isso é fei-
to mediante a apresentação de uma caixa de diálogo com o resumo das defini-
ções estabelecidas pelo usuário.

F I G U R A 3 1 . 2 A caixa de diálogo de confirmação


276
Na dúvida, o usuário pode acionar o botão Ajuda, que abre um texto com
orientação completa sobre o uso do programa. Detalhe: a etiqueta, ou rótulo,
exibida acima do botão OK mostra o nome com o qual o recibo será salvo em
disco.

Orelha Empresa e Cidade


Esta segunda orelha (Figura 31.3) é dedicada à configuração dos itens que serão
fixos para cada usuário na emissão de seus recibos: cidade, empresa do usuário,
e pasta para armazenar os documentos.
Para emitir o recibo, o usuário deve preencher as caixas de texto Sua Cida-
de, Sua Empresa e Pasta para Armazenamento dos Arquivos e, em seguida, acio-
nar o botão Salvar Configurações. No caso da caixa Pasta para Armazenamento,
ele tem a opção de clicar no botão Procurar e indicar o diretório desejado.

F I G U R A 3 1 . 3 Orelha Empresa e Cidade: configurações fixas

A orelha Empresa e Cidade inclui ainda a caixa de verificação Confirmar


Definições ao Emitir Recibos. Ligada, ela provoca a exibição da caixa de diálogo
de confirmação quando o usuário aciona o botão OK para disparar a emissão de
um recibo. Se, depois de algum tempo, ele concluir que a confirmação se tornou
um estorvo, pode desligá-la e, para fixar essa escolha, clicar no botão Salvar
Configurações.
Esse último botão também provoca a exibição de uma caixa de diálogo,
apenas para informação do usuário.

277
F I G U R A 3 1 . 4 Informação após salvar configurações

Orelha Clientes, Recebedores e Serviços


Se a guia Empresa e Cidade é dedicada à configuração dos itens fixos, a orelha
Clientes, Recebedores e Serviços volta-se para as informações móveis. Para in-
cluir, modificar ou excluir um item cadastrado, basta clicar num dos três botões
principais dessa guia.

F I G U R A 3 1 . 5 Guia Clientes, Recebedores e Serviços: cadastro

O clique num desses botões provoca a abertura, com o Bloco de Notas, de


um arquivo texto que contém um cadastro de opções correspondentes. O botão
Lista dos Clientes Mais Comuns abre o arquivo Rclients.lst, que contém uma re-
lação simples com os nomes dos clientes, um em cada linha. O botão Lista das
Pessoas Que Assinam Recibos abre um arquivo idêntico (Rpessoas.lst) com os
278 nomes das pessoas da empresa autorizadas a assinar recibos.
O terceiro botão, Tipos de Recibos e Descrição dos serviços abre no Bloco
de Notas uma listagem (Rtipserv.lst) um pouco diferente. Admita que sua em-
presa preste diferentes gêneros de serviços, os quais devem constar nos recibos.
Com algum esforço, você pode classificar esses serviços, dando a cada um título
e descrição. Exemplos:

Serviços contábeis
execução de balancete mensal e emissão de guias fiscais
Assessoria jurídica
consultoria jurídica e acompanhamento de questões imobiliárias

Esta é a estrutura do arquivo Rtipserv.lst. Aqui, é importante deixar claros


alguns detalhes. A regra básica é: um título, uma descrição. Cada item deve ocu-
par uma única linha de texto. Isso significa que, se uma descrição for mais longa,
mesmo assim deve ficar em apenas uma linha. Para garantir isso, no Bloco de
Notas, basta escrevê-la normalmente e só quebrar a linha com a tecla Enter no
final da descrição. Outro detalhe, que obedece ao esquema de redação do recibo
mostrado no modelo Recibog.dot: a descrição deve começar e terminar com le-
tra minúscula e não deve incluir ponto final.
Embora títulos e descrições de serviços estejam juntos no arquivo Rtip-
serv.lst, são apresentados em separado na orelha principal do aplicativo. Os tí-
tulos são exibidos como opções na caixa de combinação Tipo de Recibo. Ao es-
colher um título nessa caixa, o usuário provoca o preenchimento da caixa de
texto Descrição dos Serviços Prestados com a descrição que faz par com o item
escolhido.
A caixa Tipo de Recibo é neutra – ou seja, não participa diretamente da
confecção dos recibos. Ela serve apenas para preencher a caixa Descrição dos
Serviços Prestados. Esta, sim, está ligada à construção do documento. Por isso,
se o usuário precisar emitir um recibo especial cuja descrição não esteja cadas-
trada, basta escrever o texto desejado diretamente na caixa Descrição.
Depois de alterar, incluir ou apagar um item nos arquivos de configuração,
o usuário deve clicar no quarto botão da orelha Clientes, Recebedores e Servi-
ços. Esse botão força a atualização das informações nas caixas de combinação da
orelha principal, Dados para o Recibo. Assim, um item incluído passa a estar
disponível imediatamente. De outra forma, ele só estaria listado na próxima
abertura do Gerador de Recibos.
Já conhecemos todo o funcionamento externo do programa. Vejamos,
agora, o que é o Gerador de Recibos por dentro, do ponto de vista do pro-
gramador.

O aplicativo por dentro


Em linhas gerais, você já sabe qual a estrutura de trabalho do Gerador de Reci-
bos. Resta-nos apenas revelar quais os fios condutores que garantem esse fun- 279
cionamento. Em primeiro lugar, é bom dizer que o tanto o texto do recibo
como a lógica de seu preenchimento estão contidos no mesmo modelo – Reci-
bog.dot.
Assim, a primeira tarefa é criar um recibo e salvá-lo como modelo (Reci-
bog.dot). O texto do recibo deve conter as palavras-chave que serão substituídas
pelas variáveis escolhidas pelo usuário. Essas palavras-chave são as seguintes:

PALAVRA-CHAVE REFERE-SE A

SubValorPago Valor do recibo

SubCidadeDaTransação Nome da cidade em que o recibo é emitido

SubDataDoRecibo Data de emissão do recibo

SubPronomeDeTratamento Tratamento para o pagador: senhor,


senhora etc.

SubNomeDoPagador Nome do pagador

SubExtensoDoValorPago Valor do recibo, escrito por extenso

SubMêsDoPagamento Mês de referência do recibo

SubAnoDoPagamento Ano de referência do recibo

SubDescriçãoDosServiçosPrestados Descrição dos serviços pagos

SubNomeDaEmpresaQueRecebe Nome do recebedor

SubNomeDaPessoaQueAssina Nome do responsável pela emissão do


recibo

SubCargoDaPessoaQueAssina Cargo do responsável pela emissão do


recibo

As palavras-chave são, de propósito, estranhas e longas. Isso evita que,


na operação de busca e troca, outras palavras do texto sejam confundidas
com elas. Ao elaborar o seu modelo de recibo, você pode modificar e perso-
nalizar, livremente, o modelo que acompanha este projeto. No entanto, se
você alterar essas palavras-chave, deverá também fazer as alterações perti-
nentes no código.

O formulário
Agora, vamos ao formulário. Com o modelo Recibog.dot aberto, passe para a
janela do Visual Basic (Alt+F11) e selecione o projeto Recibog. Agora, acione o
comando Inserir/UserForm, para criar o formulário frmReciboGeral. Neste, in-
280 clua um objeto Multipágina dotado de três orelhas, ou guias: Dados para o Reci-
bo; Empresa e Cidade; e Clientes, Recebedores e Serviços. Veja, agora, a lista
dos controles que cada uma dessas guias deve conter:

TIPO DE CONTROLE LEGENDA NOME

Guia Dados para o Recibo

Caixa de combinação Nome do Pagador cboPagador

Caixa de combinação Tratamento cboTratamento

Caixa de texto Valor Recebido txtValor

Caixa de combinação Pessoa Que Assina o Recibo cboQuemAssina

Caixa de combinação Mês do Recibo cboMês

Caixa de combinação Ano do Recibo cboAno

Caixa de combinação Tipo de Recibo cboTipos

Caixa de texto Descrição dos Serviços Prestados cboDescrição

Botão de comando OK cmdOK

Botão de comando Cancelar cmdCancelar

Botão de comando Ajuda cmdAjuda

Rótulo - labPróximoRecibo

Guia Empresa e Cidade

Caixa de texto Sua Cidade txtCidade

Caixa de texto Sua Empresa txtEmpresa

Caixa de texto Pasta para Armazenamento dos txtPastaDoc


Arquivos

Botão de comando Salvar Configurações cmdSalvar

Botão de comando Procurar cmdProcurar

Caixa de verificação Confirmar definições ao emitir chkConfirmar


recibos

Guia Empresa e Cidade

Botão de comando Lista dos Clientes Mais Comuns cmdClientes

Botão de comando Lista das Pessoas Que Assinam cmdPessoas


Recibos
281
TIPO DE CONTROLE LEGENDA NOME

Botão de comando Tipos de Recibos e Descrição dos cmdTipos


Serviços

Botão de comando Atualizar Configurações cmdAtualizar

Rótulo - labListaClientes

Rótulo - labListaPessoas

Rótulo - labTipos

Rótulo - labAtualizar

O código
Muito bem. O formulário está desenhado e você já conhece como o programa
funciona. Falta colocá-lo em funcionamento. Vamos pensar no que é preciso fa-
zer. A operação básica consiste em pegar os valores indicados pelo usuário e
substituir, com eles, as palavras-chave que estão no texto do documento. Esse é
o núcleo do problema, que é relativamente simples. Mas, para tornar o progra-
ma universal, é necessário garantir a execução de uma série de operações que
devem ocorrer antes e depois que o usuário clique no botão OK. Nelas é que es-
tão os detalhes e as verdadeiras dificuldades deste projeto.
Vamos destacar algumas operações que vêm antes do clique. O primeiro
bloco delas, naturalmente, deve acontecer logo durante a inicialização do for-
mulário. É preciso, por exemplo, dizer onde estão os arquivos com os quais o
programa irá trabalhar. Todos eles estão localizados no diretório-padrão para
armazenamento de modelos do Word, cuja localização exata varia conforme a
versão do programa. Para simplificar, é a mesma pasta onde fica o modelo Nor-
mal.dot. Em código, ela é dada por:

Options.DefaultFilePath(wdUserTemplatesPath)

Outra providência que ocorre durante a inicialização do programa é o pre-


enchimento das caixas de combinação. Comecemos pelas mais simples. A caixa
cboTratamento recebe sua coleção de itens da seguinte maneira:

With cboTratamento
.AddItem “de”
.AddItem “da”
.AddItem “do”
.AddItem “da empresa”
.AddItem “do Sr.”
.AddItem “da Sra.”
282
.AddItem “da Srta.”
.ListIndex = 0
End With

Apenas para lembrar: esses itens têm o formato “do Sr.”, “da Sra.” etc.
porque devem combinar na frase que abre o recibo: “Recebemos do Sr. Fulano
de Tal”... Incluir, aí, a preposição é uma forma de já passar o tratamento com o
gênero correto, a fim de evitar coisas como “do senhora”.
Outras caixas de combinação fáceis de preencher são as que abrigam o mês
e o ano de referência do recibo. Para o mês, vale destacar um pequeno truque.
Poderíamos muito bem usar o método AddItem e incluir uma lista de janeiro a
dezembro. No entanto, há um jeito mais esperto de fazer isso:

With cboMês
For n = 1 To 12
.AddItem Format$(“1/” & n & “/2000", ”mmmm")
Next n
.ListIndex = Month(Now) - 1
End With

Observe: fizemos um loop de 1 a 12, e forçamos a montagem de uma data


com o primeiro dia do mês correspondente (o ano poderia ser qualquer um). Em
seguida – ou, melhor dizendo, no mesmo passo –, usamos a função Format para
que o VBA inclua na caixa de combinação o nome do mês correspondente àque-
la data. Assim, com três linhas resolvemos uma questão que, da primeira forma
pensada, consumiria pelo menos doze. Preenchida a caixa Mês do Recibo,
usa-se a sua propriedade ListIndex para exibir o mês corrente, que equivale a:

Month(Now) - 1

O -1, aí, tem apenas o objetivo de compatibilizar a série de meses (1 a 12)


com os índices dos itens da caixa de combinação, que tem base zero. A caixa
Ano do Recibo recebe outro tratamento. Ela exibe 21 anos: o atual, dez anterio-
res e dez posteriores. Se você achar esse número excessivo, pode trocar o núme-
ro 10 por outro menor – por exemplo, 5. O código é o seguinte:

With cboAno
For n = Year(Now) - 10 To Year(Now) + 10
.AddItem n
Next n
.ListIndex = 10
End With

Agora, passemos à leitura das configurações já feitas pelo usuário. Primei-


ro, as fixas: empresa, cidade e pasta para armazenamento dos recibos como ar- 283
quivos DOC. Essas configurações estão armazenadas no arquivo Recibog.ini.
Então, a primeira tarefa é tentar ler essas informações. Para isso, usa-se a propri-
edade PrivateProfileString, do objeto System:

txtEmpresa = System.PrivateProfileString(m_strArqIni, _
“Configs”, “Empresa”)

Se o arquivo INI não existir (ou existir, mas sem um valor para a chave
Empresa), a propriedade PrivateProfileString vai retornar uma string vazia.
Nesse caso, não há problema, pelo menos, por enquanto — pois o usuário será
avisado para informar o nome de sua empresa ao tentar emitir qualquer recibo.
O mesmo vale para o item cidade.
Para a pasta de documentos e a opção Confirmar Definições ao Emitir Re-
cibos, adota-se procedimento diferente. Se o nome da pasta não existir, adota-se
como padrão c:\meus documentos. Se não houver no arquivo INI uma opção re-
gistrada (Sim ou Não) para a exibição de confirmações, adota-se como padrão o
Sim, que será transferido como uma marca na caixa de verificação.
Ainda na sub UserForm_Initialize, garante-se que o nome da empresa do
usuário (se já estiver registrado no arquivo INI) seja exibido na barra de título
do formulário. Com isso, cada usuário fica com um Gerador de Recibos como se
tivesse sido feito sob medida para ele.
Passemos, agora, às configurações móveis – ou seja, à leitura dos arquivos
LST (Rclients, Rpessoas e Rtipserv), que vão fornecer informações para as cai-
xas de combinação cboPagador, cboQuemAssina e cboTipos. Portanto, é preci-
so ler, linha a linha, cada um desses arquivos e preencher as caixas de combina-
ção correspondentes. Neste caso, essa operação não é feita na rotina User-
Form_Initialize.
O motivo é simples: se um desses arquivos não for encontrado, é preciso
emitir um aviso ao usuário, informando-o. Mas se esse aviso partir do evento
Initialize, ele será exibido antes do formulário – uma esquisitice que é bom evi-
tar. Por causa disso, transferimos a abertura dos arquivos LST para o evento
UserForm_Activate, que ocorre depois de Initialize, quando o formulário passa
a ser o objeto ativo e, portanto, já está visível.
Observe, porém, que esse recurso só se tornou legítimo porque o projeto
tem apenas um formulário. Num projeto com múltiplos forms, as operações
comandadas a partir do evento Activate seriam disparadas toda vez que outro
formulário se fechasse e o foco voltasse para frmReciboGeral. Mesmo que as
operações fossem silenciosas e não envolvessem avisos ao usuário, não deveri-
am ser colocadas aí, visto que seriam realizadas muitas vezes, desnecessaria-
mente.
Na sub UserForm_Activate, as caixas de combinação cboPagador, cboQu-
emAssina e cboTipos ganham, cada uma, um trecho de código como este:

284
If ArqExiste(m_strArqClientes) Then
PreencheCombos cboPagador
Else
indMsg = 2
End If

A primeira linha testa se existe o arquivo LST correspondente. Em caso


afirmativo, recorre à rotina PreencheCombos, passando o objeto a ser preenchi-
do. Se o arquivo não existir, a variável inteira indMsg assume um valor. Para as
duas outras caixas de combinação, se o arquivo também não existir, indMsg
acumulará valores (2 para o primeira, 4 para a segunda e 8 para a terceira). No
final, o número assim obtido será passado para a rotina Mensagens, que exibirá
o aviso adequadamente, dizendo quais arquivos estão faltando.
O preenchimento da caixa de combinação cboTipos é diferente dos de-
mais. Ele envolve duas partes. Na primeira, a caixa é povoada da mesma forma
que as outras. Mas isso significa que ela passa a conter não somente os títulos
(ou tipos) de serviços, mas também as descrições. Então, quando se trata da cai-
xa cboTipos, a rotina PreencheCombos chama a sub AjustaCboTipos para fazer
a segunda parte.
AjustaCboTipos encarrega-se de eliminar da caixa cboTipos as descrições
de serviços. Para isso, faz o seguinte. Primeiro, divide por dois o número de itens
na caixa cboTipos e dimensiona uma matriz para conter esse número de elemen-
tos. Essa matriz vai conter as descrições. Em seguida, entra num loop For/Next.
Em cada volta desse loop uma descrição é selecionada, armazenada como um
elemento da matriz e, em seguida, apagada da caixa de combinação. O código
que faz isso é o seguinte:

‘ Matriz de descrições
intMatriz = cboTipos.ListCount \ 2
ReDim m_sDescrição(1 To intMatriz)

‘ Preenche a matriz
For n = 0 To intMatriz - 1
cboTipos.ListIndex = n + 1
m_sDescrição(n + 1) = cboTipos
cboTipos.RemoveItem n + 1
Next n

Ao final, a caixa de combinação contém apenas títulos dos serviços, en-


quanto as descrições correspondentes ficam guardadas na matriz. Quando o
usuário escolher uma opção na caixa Tipo de Recibo, a descrição associada será
inserida na caixa de texto txtDescrição, graças à seguinte linha na sub cboTi-
pos_Click:

txtDescrição = m_sDescrição(cboTipos.ListIndex + 1) 285


Ainda na sub UserForm_Activate são chamados dois procedimentos: Veri-
ficaAno e CapturaNúmero. Ambas referem-se ao nome do arquivo do recibo —
algo que irá acontecer depois que o usuário clicar no botão OK para emitir o re-
cibo. Contudo, precisam ser disparadas desde já, até porque esse nome é infor-
mado previamente ao usuário, na etiqueta labPróximoRecibo.
Esclareçamos. Para permitir o armazenamento dos recibos como um docu-
mento do Word, decidimos nomear cada um deles com um sistema de numera-
ção crescente, que adota o seguinte formato:
R0001-00.doc, R0002-00.doc, R0003-00.doc (...) R9999-00.doc.
Essa denominação do arquivo envolve três partes. O R provém de recibo.
Depois, vem o número, ue pode crescer, mantendo o padrão, até 9999. Por fim,
vem o ano, em dois dígitos, antecedido por um hífen. Quando ocorre uma vira-
da de ano, a numeração recomeça e o ano é também ajustado: R0001-01.doc.
Para que isso aconteça, o arquivo INI é utilizado para armazenar o ano atual e o
número utilizado na emissão do último documento. Quando completo, o arqui-
vo Recibog.ini tem o seguinte formato:

[Configs]
Empresa=Neves & Naves Ltda.
Cidade=São Paulo
RecNum=2
Ano=2000
Confirmar=Sim
PastaDoc=c:\meus documentos

As chaves referentes ao nome do documento do recibo são RecNum e Ano.


Pois bem. A rotina VerificaAno tenta ler no arquivo INI o valor armazenado na
chave Ano. Se não existir, ela consulta a data no relógio do sistema e escreve
Ano=<ano atual>. Se o ano existe, a rotina o compara com o ano fornecido
pelo PC. Se este for maior que o registrado no arquivo INI, então conclui-se que
estamos num novo ano. Então, chama-se a rotina ZeraContagem, que escreve o
novo ano no arquivo INI e faz RecNum=0.
A outra rotina, CapturaNúmero, também tenta ler o número do último
recibo emitido. Se não existe, ela, imediatamente, escreve RecNum=0, para dar
início à numeração. Com isso, o próximo recibo já pode ter número: 1. Número e
ano agora estão garantidos, de modo que é possível montar o nome do arquivo.
Você deve estar se perguntando: por que tanto trabalho para fazer essa nu-
meração seqüencial se o Windows 95/98, o NT e o 2000 suportam nomes lon-
gos? A resposta é simples. Além de um exercício de programação, os arquivos
com nomes de igual comprimento facilitam a organização. Você vai saber que o
documento R0036-00.doc foi escrito antes de R0041-00.doc. Além disso, no
Explorer, os arquivos são exibidos em ordem numérica (e, em conseqüência,
cronológica), o que não aconteceria se não houvesse a numeração com os zeros
286
marcando as posições de milhar, centena e dezena.
Um detalhe: a rotina UserForm_Activate começa definindo a variável
m_blnProgIni como verdadeira e termina trocando o seu valor para falso. Com
o primeiro valor, ela evita que, durante a inicialização, seja disparado o evento
clique da caixa de combinação cboTipos, produzindo um erro. O mesmo recur-
so é usado durante a atualização do conteúdo das caixas de combinação, provo-
cada pelo botão Atualizar Configurações.
A rotina associada a este último botão simplesmente recorre à sub Preen-
cheCombos para todas as caixas de combinação ligadas aos arquivos LST.
Assim, as caixas são esvaziadas e repovoadas, agora incluindo as mudanças in-
troduzidas nos arquivos.
Quando, enfim, o usuário clica no botão OK, começam os procedimentos
que preparam a emissão do recibo. Inicialmente, a rotina cmdOK_Click verifica
se todas as caixas necessárias estão preenchidas. Em caso negativo, o processa-
mento é interrompido e o usuário recebe um aviso. Um exemplo dessa verifica-
ção: se o campo Empresa ou Cidade não estiver preenchido, o usuário é remeti-
do para a orelha Empresa e Cidade. Para exibir a segunda orelha do objeto Mul-
tipágina, o comando é:

MultiPage1.Value = 1

Como se vê, o índice das orelhas desse controle opera com base zero.
Duas outras verificações são feitas antes de deflagrar o preenchimento do reci-
bo. Uma testa a validade do diretório, indicado na caixa txtPastaDoc. A outra
é o pedido de confirmação, exibido se a caixa de verificação chkConfirmar es-
tiver marcada.
Concluídos os testes, entramos na reta final para a emissão do recibo.
Então a rotina oculta o formulário e chama a função de extenso na biblioteca
Extens32.dll (arquivo que acompanha o projeto), passando-lhe o valor do reci-
bo. Obtém, assim, esse valor por extenso, em reais, e armazena numa variável.
Depois, determina a data. No Word 2000, fica assim:

strData = Format(Now, “d \de mmmm \de yyyy”)

No Word 97, a linha acima não funciona. Use, então, a linha abaixo, que
também funciona no Word 2000:

strData = Day(Now) & “ de ” & Format(Now, “mmmm”) & _


“ de ” & Year(Now)

Por fim, o procedimento monta a matriz strVars, de duas dimensões, a pri-


meira para os valores definidos no formulário e a outra para a palavra-chave no
documento. Exemplo:
strVars(7, 1) = strMes
strVars(7, 2) = “subMêsDoPagamento” 287
strVars(8, 1) = strAno
strVars(8, 2) = “subAnoDoPagamento”

O uso da rotina facilita a montagem da operação de busca das pala-


vras-chave e sua substituição pelos valores definidos no formulário.
For n = 1 To iTotalVars
With Selection.Find
.ClearFormatting
.Replacement.ClearFormatting
.Text = strVars(n, 2) ‘ texto a localizar
.Replacement.Text = strVars(n, 1) ‘novo texto
.Forward = True
.Wrap = wdFindContinue
.Execute Replace:=wdReplaceAll
End With
Next n

O resultado é o recibo, tal como mostrado na Figura 31.6. Depois de pre-


encher o documento, a rotina cmdOK_Click salva o arquivo, nomeando-o con-
forme o esquema de numeração seqüencial já discutido anteriormente.

F I G U R A 3 1 . 6 O documento final: preenchido e salvo com um


número seqüencial

Por fim, é preciso relembrar que todo projeto do Gerador de Recibos está
alojado no modelo Recibog.dot. A idéia é exibir o formulário do programa sem-
pre que um novo documento seja criado com base nesse modelo. Então, é neces-
sário escrever uma rotina que abra o formulário frmReciboGeral, no momento
288
da criação de um novo documento. Para isso, dê um duplo clique na pasta This-
Document, dentro do projeto Recibog. Abre-se uma janela de código, vazia. Na
caixa Geral, escolha Document. Automaticamente, o VBA cria um procedimen-
to chamado Document_New. Nele escreva a linha para abrir o formulário. A ro-
tina, completa, ficará assim:

Private Sub Document_New()


frmReciboGeral.Show
End Sub

Comentários finais
Aqui concluímos a apresentação deste projeto. O resto, como sempre, são deta-
lhes espalhados aqui e acolá dentro do programa. A caixa txtValor, por exem-
plo, só aceita a digitação de números, ponto, vírgula e retrocesso. Isso é garanti-
do pelo seguinte código, no evento KeyPress:
Select Case KeyAscii
Case 8, 44, 46, 48 To 57
‘OK
Case Else ‘ anula a digitação
KeyAscii = 0
End Select

Mais detalhes. Quando o usuário abre o programa e aciona o botão Cance-


lar, fecha o formulário e também o arquivo do recibo que o contém. Na orelha
Clientes, Recebedores e Serviços, quando o cursor do mouse passa em cima de
um botão, aparece, à direita, uma explicação do que faz aquele botão. Essas ex-
plicações estão em rótulos ocultos (propriedade Visible=False).
Quando o cursor está sobre o botão, um código no evento MouseMove
desse botão torna visível o rótulo correspondente. Ao mesmo tempo, o evento
MouseMove do objeto Multipágina torna invisíveis todas as quatro etiquetas
com explicações. Assim, quando o cursor sai de cima do botão e cai na área da
multipágina, a etiqueta desaparece.
Esse recurso é interessante, mas apresenta um senão: em certos casos,
quando se passa o cursor muito rapidamente sobre um botão, e logo depois, so-
bre outro, duas etiquetas ficam visíveis. Isso ocorre porque a área do controle
multipágina é pequena entre os botões e o evento MouseMove não é disparado.

Para ir mais além


1. Uma das modificações óbvias que você pode fazer neste projeto é rede-
senhar o modelo do recibo para adaptá-lo ao seu gosto ou ao layout dos
documentos de sua empresa. Aja livremente, preservando apenas as pa-
lavras-chave.
289
2. O armazenamento das listas de variáveis deste programa em arquivos
texto obedeceu à idéia de manter o projeto simples, resolvido apenas
com recursos do próprio Word. No entanto, se você quiser, pode guar-
dar essas variáveis em tabelas de bancos de dados. Outros projetos neste
livro mostram como acessar bases de dados Access.
3. Uma das falhas do armazenamento de variáveis em arquivos texto é
mostrada no caso do arquivo Rtipserv.lst. Ele armazena dois tipos de
listagem que precisam, obrigatoriamente, estar associados, dois a dois.
Se essa condição falhar (por exemplo, o usuário digitar o título e não
inserir a descrição correspondente na linha seguinte), o programa,
obviamente, passará a operar com erro. E, como se trata de um arquivo
texto, não há como evitar isso. A solução com banco de dados, sugerida
no item 2, sanaria essa falha. De todo modo, o projeto, tal como é
apresentado aqui, serve bem aos propósitos de pequenos escritórios e
de usuários que têm o controle de seu próprio trabalho.
4. Em vez de formatar a data no código VBA e depois inseri-la no recibo, você
pode deixar tudo a cargo do Word. Para isso, use o comando Inserir/Cam-
po, categoria Data e Hora, nome de campo CreateDate. Para mais deta-
lhes, veja o projeto Controle de Aluguéis, no Capítulo 30.

Arquivos de inicialização
Os arquivos INI, uma herança do Windows 3.x, e o Registro do
Windows representam recursos práticos para o armazenamento de
variáveis de configuração que precisam ser “lembradas” entre uma e
outra execução de um aplicativo. Sempre que você pensar em usar
esses recursos, tenha em conta que eles impõem a criação de dois tipos
de rotinas. Primeiro, um ou mais procedimentos para ler as confi-
gurações durante a inicialização do programa ou em outros mo-
mentos, quando necessário. Depois, outros procedimentos para dar ao
usuário a oportunidade de modificar as definições gravadas.

290
32
Façam as
suas apostas!

Como construir um jogo de dados gráfico


com três modalidades de apostas

Ficha do projeto

Projeto:

Jogo gráfico Álea, baseado em dois dados e três


modalidades de apostas

O que faz:

Oferece um painel gráfico com faces de dados em 3D. O


jogador aposta em dois dados e escolhe um tipo de jogo.
O programa apura e exibe os resultados conforme a
modalidade escolhida.

Arquivos e requisitos do projeto:

Formulário frmDados e código interno.

Conhecimento técnico:

Trabalho com imagens e cálculo com números randômicos.

Nível de programação:

Intermediário
Em geral, quem gosta de computador tende a gostar, e muito, dos games eletrô-
nicos. Nesse item sou uma exceção. Confesso que não tenho nenhuma paciência
para os jogos – nem mesmo para o inevitável Paciência. Mas reconheço que a
construção de jogos constitui um excelente exercício para programadores. Nes-
te capítulo, vamos desenvolver um jogo de dados. Trata-se de uma adaptação de
um programa que escrevi, há muito tempo, com o Visual Basic 1.0 ou 2.0.
Primeiro, o problema. A idéia é criar um jogo no qual as apostas são feitas
com dois dados. O jogador precisa ter uma forma de indicar as duas faces de da-
dos em que deseja apostar. Feita a aposta, ele manda rolar os dados. O programa
deve exibir os dados da banca, compará-los com a aposta e indicar o resultado.
Os dados são o jogo de azar, por excelência. Portanto, o aplicativo deve incluir
uma forma de tornar os resultados aleatórios, como num jogo real.
Agora, a solução. Para representar os dados, vamos usar seis pequenos
bitmaps (27´ 27 pixels) com imagens de dados em 3D, um para cada face. Cada
um dos dois dados do jogo será representado por uma coleção desses seis
bitmaps. Para apostar, o jogador usará o mouse e clicará numa face do dado 1 e
numa face do dado 2 (veja a Figura 32.1).

FIGURA 32.1 A tela do jogo: três modalidades de apuração


dos resultados

Para dar a idéia de conjunto, as imagens dos dois dados são mostradas den-
tro de molduras. Quando o jogador escolhe as faces desejadas no dado 1 e no
dado 2, essas faces são copiadas para a área sob a legenda Sua Aposta. Assim, fi-
cam visíveis os números em que ele apostou. Rolados os dados, o programa
apresenta os números finais na área chamada Mesa da Banca. O resultado é exi-
bido no painel Placar.
Em Álea, cada partida está definida como uma seqüência de treze lances.
Usei treze para acentuar o aspecto cabalístico do jogo, mas poderia também
usar sete. O programa vai acumulando os resultados e, no final, encerra a parti-
da, informando o percentual de acertos do jogador. A apuração é feita de três
formas diferentes, conforme a modalidade de jogo escolhida na caixa de combi-
292
nação Modalidade. Há três: Comum (padrão), Ordem e Soma. Veja na tabela a
seguir como funciona cada uma delas. Os números de cada lance, na aposta ou
no resultados, são expressos como um par ordenado: (d1, d2). Ou seja, os nú-
meros no dado 1 e no dado 2.

MODALIDADE APURAÇÃO DOS PONTOS

Comum Conta 1 ponto, não importa a ordem da aposta e do


resultado. Se você apostar (1, 4), marcará 1 ponto se der
(1, 4) ou (4, 1). Em comparação com as outras duas
variantes, oferece nível médio de dificuldade.

Ordem A marcação de 1 ponto positivo só ocorre quando o resultado


da mesa reproduz a ordem dos dados da aposta. É a
modalidade mais difícil do jogo.

Soma O jogador conquista 1 ponto quando a soma dos dados da


mesa é igual à soma dos dados da aposta. Por exemplo:
(3, 4) na aposta e (6, 1) na mesa. É a variante mais fácil do
jogo.

FIGURA 32.2 Desenho ampliado de uma das faces do dado

293
Desenho da interface
Em primeiro lugar, você precisa ter as imagens dos dados. Elas são seis bitmaps
desenhados com o Paint, do Windows. Para representar o dado 1, usamos uma
moldura (fraDado1) e, dentro dela, seis objetos Image, nomeados seqüencial-
mente como imgDado11, imgDado12, e assim por diante, até imgDado16. De
forma idêntica, criamos outra moldura (fraDado2), com seis imagens: imgDa-
do21, imgDado22 etc. Aqui, um detalhe: para tornar o programa mais leve, car-
regamos apenas as imagens no dado 1. As imagens do dado 2 são copiadas du-
rante a inicialização do programa.
O carregamento do bitmap para um controle Image é feito mediante a defi-
nição da propriedade Picture. Para o dado 1, as imagens foram definidas, manu-
almente, na caixa de propriedades de cada objeto. Se fosse o caso, também po-
deriam ser configuradas em código. Por exemplo:

imgDado11.Picture = “c:\meus documentos\dado1.bmp”

No dado 2, as imagens são cópias das existentes no dado 1. A cópia é feita


igualando-se os valores da propriedade Picture dos dois objetos:

imgDado21.Picture = imgDado11.Picture

F I G U R A 3 2 . 3 O formulário, mostrado pelo ponto de vista do


desenvolvedor

Na moldura que exibe os dados apostados (fraAposta), incluímos três ima-


gens: imgAposta1, imgAposta2 e imgVazio. As duas primeiras recebem cópias das
faces dos dados que representam a aposta do jogador. A última serve apenas como
objeto auxiliar. Trata-se de um controle sem nenhuma imagem. Quando é preciso
zerar o jogo (no final da partida ou por escolha antecipada do jogador), usa-se
imgVazio para limpar as imagens da mesa da banca e da área de apostas. Assim:
imgAposta1.Picture = imgVazio.Picture
294
A moldura fraBanca abriga duas imagens de dados: imgBanca1 e imgBan-
ca2. Por fim, os resultados são exibidos em outra moldura, fraPlacar. Nela estão
seis caixas de texto, que exibem os acertos, os erros e o número de jogadas, em
valores absolutos e em números percentuais. Essas caixas são txtAcertoA,
txtAcertoP, txtErroA, txtErroP, txtTotalA e txtTotalP. Ainda na área dos resul-
tados, encontra-se o botão de comando Zerar (cmdZerar), que limpa todos os
resultados do placar e as imagens de Sua Aposta e da Mesa da Banca, preparan-
do o programa para o início de nova partida.
O botão Rolar os Dados (cmdRolar) dá início a todo o processo. Ou, para
não perder o trocadilho, ele é que dispara o verdadeiro processamento de dados.

A lógica do programa
Agora que já vimos o funcionamento do programa por fora, passemos para o
lado de dentro. A primeira coisa que o jogador deve fazer é colocar sua aposta,
clicando com o mouse numa face do dado 1 e numa face do dado 2. O programa
precisa executar três ações com base nesse clique do jogador.
n armazenar a informação da aposta: qual face do dado 1 foi escolhida?
n controlar se o usuário de fato já apostou nos dois dados. Isso é
obrigatório, porque não será possível apurar o resultado se a aposta não
estiver completa;
n copiar a imagem escolhida para a área de aposta.
Para executar essas operações, criamos duas rotinas sub, CliqueDado1 e
CliqueDado2. Elas recebem o número índice da imagem clicada e são chamadas
a partir do evento Click do controle. A seguir, um exemplo que começa com o
clique na face 2 do dado 1:

Private Sub imgDado12_Click()


CliqueDado1 2
End Sub

Sub CliqueDado1(idx As Integer)


‘ Processa o clique em qualquer face do dado 1
blnClicouDado1 = True
intAposta1 = idx
imgAposta1.Picture = Controls(“imgDado1" & idx).Picture
Me.Repaint
End Sub

A rotina CliqueDado1 recebe o valor 2. Primeiro, marca como verdadeira


a variável booleana blnClicouDado1, definida na área de declarações do for-
mulário e, portanto, válida para todo o módulo. Outra variável válida para todo
o formulário é intAposta1. Ela indica que o jogador apostou na face 2 do dado 1. 295
A propriedade Picture da imagem imgAposta1 é definida, usando-se a coleção
Controls e concatenando o nome do controle escolhido:

imgAposta1.Picture = Controls(“imgDado1" & idx).Picture

No exemplo, “imgDado1” & idx resultará em imgDado12. O método


Repaint provoca o redesenho do formulário. Talvez não seja desnecessário, no
caso, mas é interessante que fique aí. Em muitos casos de redefinição da
propriedade Picture, a tela não se repinta e não se obtém o resultado visual
desejado .
Se o usuário não completar a aposta (ou seja, escolher somente uma face
num dos dados) e clicar no botão Rolar os Dados, o processo será interrompido.
O programa exibirá uma mensagem orientando o jogador. Esse controle é feito
com o valor das variáveis booleanas blnClicouDado1 e blnClicouDado2. A ação
só prossegue se ambas forem verdadeiras.
Para que o lance de dados seja autêntico, é necessário obter, para cada um
dos dois dados, um número randômico – ou seja, aleatório. Aqui cabe um pouco
de etimologia. O jogo de dados é um dos mais antigos de que se tem notícia. É
classificado como um jogo de azar, visto que depende exclusivamente da sorte, e
não da estratégia ou experiência do jogador. Azar e sorte, aliás, são faces dife-
rentes de um mesmo dado. A palavra azar, segundo os dicionaristas, provém do
árabe yásara – termo que também está ligado ao jogo de dados. Em espanhol,
azar significa um lance de dados malsucedido.
Essa idéia de má sorte foi a que passou mais fortemente para o português.
Mas azar também significa acaso. Ao longo da História, os dados têm sido o sím-
bolo por excelência da casualidade. Não por acaso, alea, palavra latina, significa
jogo de dados. Quando César cunhou a conhecida frase Alea jacta est, queria di-
zer que a sorte estava lançada. Mas, na verdade, o lance era de dados. De alea
vem aleatório, adjetivo usado para indicar aquilo que não obedece a nenhuma
regra predefinida, senão ao acaso. Ou ao azar, tanto faz. Aliás, também existe a
palavra álea em português. Segundo o dicionário DicMaxi Michaelis Português,
ela significa “sorte, risco, acaso”.
Na linguagem Basic, a instrução Randomize, combinada com a função
Rnd, gera números aleatórios. Em nosso caso, elas são utilizadas da seguinte for-
ma:

Randomize
intDado1 = Int(6 * Rnd + 1)
intDado2 = Int(6 * Rnd + 1)

Os valores obtidos para intDado1 e intDado2 são números inteiros randô-


micos, situados na faixa de 1 a 6 – os valores das faces de um dado. A próxima
tarefa é comparar esses números com os números apostados pelo jogador. Para
296 isso, é preciso primeiro verificar qual a modalidade de jogo vigente e chamar a
rotina que implementa a forma específica de apuração. Há três rotinas de apura-
ção: ApuraComum, ApuraOrdem e ApuraSoma.

Modalidade Comum
Nos três casos de apuração, o algoritmo baseia-se na idéia de somar dois pontos,
um para cada coincidência de valores dos dados. Assim, o resultado pode ser 0
(nenhuma coincidência), 1 (uma coincidência) ou 2 (duas coincidências). Esse
número será passado ao placar e, naturalmente, o número 2 valerá um acerto,
enquanto os outros marcarão erros.
Em termos de código, a apuração da modalidade Comum é a mais engano-
sa. Não é longa nem complicada, mas exige atenção. Em princípio, basta verifi-
car se os dois pares de dados são iguais, não importando a ordem. Ou seja, se a
aposta é (2, 5) e a mesa produz (2, 5) ou (5, 2), em ambos os casos o jogador ven-
ceu. E como fica em código?

If (intAposta1 = intBanca1) Or (intAposta1 = intBanca2) _


Then Ponto = 1
If (intAposta2 = intBanca1) Or (intAposta2 = intBanca2) _
Then Ponto = Ponto + 1

Na modalidade Comum, basta verificar se cada número da aposta tem um


correspondente no resultado da mesa. Isso funciona bem, na maioria das vezes,
mas pode produzir um erro em casos como (4, 4) na aposta e (4, 3) na mesa.
Comparado com a aposta, o primeiro 4 obtém um ponto. O segundo, também.
Então, corre-se o risco de passar essa aposta como vencedora, quando, clara-
mente, não é. Daí a necessidade de outro If:

If Ponto = 2 Then
If (intAposta1 = intAposta2) And _
(intBanca1 <> intBanca2) Then Ponto = Ponto - 1
End If

Assim, garante-se que uma aposta com dois números iguais (4, 4) só será
vencedora se os dois números da mesa também forem iguais.

Modalidade Ordem
A modalidade Ordem é a mais difícil de jogar, porém bem mais simples de apu-
rar. Ela se resolve em uma linha. O dado 1 da aposta deve ser igual ao dado 1 da
mesa. O dado 2 da aposta deve ser igual ao dado 2 da mesa.
If (intAposta1 = intBanca1) And (intAposta2 = intBanca2) _
Then Ponto = 2
297
Modalidade Soma
Na modalidade Soma, o código também não apresenta problemas. A soma dos
pontos apostados deve ser igual à soma dos pontos rolados na mesa:

If (intAposta1 + intAposta2) = (intBanca1 + intBanca2) _


Then Ponto = 2

Em termos estatísticos, cada modalidade de jogo apresenta um grau de di-


ficuldade diferente. Refiro-me, aqui, não à programação, mas à probabilidade
de ganhar do acaso em cada lance de dados. No modo Comum, o jogador tem 2
chances em 36, ou seja, 5,6 %. O modo Ordem, que é o mais difícil, oferece ape-
nas uma chance em 36, ou 2,8 %. O modo Soma é o mais fácil, porque, embora
sob o comando do acaso, admite certa esperteza do jogador. As chances nessa
modalidade variam de 1 em 36 (2,8%) a 6 em 36 (16,7%). E é nessa variação
que entra a malícia do jogador: ele ganhará mais se apostar sempre para o lados
das maiores chances. Como? É matemático.
O quadro abaixo mostra todas as possibilidades de resultados quando se
jogam dois dados. Os pares de números representam os resultados no primeiro e
no segundo dado:

1, 1 1, 2 1, 3 1, 4 1, 5 1, 6

2, 1 2, 2 2, 3 2, 4 2, 5 2, 6

3, 1 3, 2 3, 3 3, 4 3, 5 3, 6

4, 1 4, 2 4, 3 4, 4 4, 5 4, 6

5, 1 5, 2 5, 3 5, 4 5, 5 5, 6

6, 1 6, 2 6, 3 6, 4 6, 5 6, 6

F I G U R A 3 2 . 4 Resultados possíveis num lance de dois dados

A tabela acima representa o conjunto total de possibilidades em qualquer


jogo com dois dados. Em outras palavras, esse é o espaço de apostas possíveis,
não importa a modalidade do jogo.
Se você observar bem, verá que essa tabela – na verdade, um quadrado,
6x6 – distribui, nas linhas paralelas à diagonal que vai do canto (6, 1) ao canto
(1, 6), todas as jogadas vencedoras da modalidade Soma.
Comece pela diagonal destacada na tabela: ali, a soma dos pares de núme-
ros sempre dá 7. Portanto, se você apostar em qualquer arranjo de dados que
some 7, terá seis chances de ganhar sobre um total de 36. Suba para a linha para-
lela (5, 1) – (1 ,5) e a soma baixa para 6, em cinco quadrinhos. Suba mais ainda:
298
a soma cai para 5, e assim por diante. Se você mantiver o paralelismo com a dia-
gonal e descer, verá que o valor da soma aumenta, mas as chances serão as mes-
mas nas linhas eqüidistantes da diagonal.
Resumo: as chances crescem quando se aposta em valores centrais e dimi-
nuem quando se caminha para as extremidades, sempre tendo como eixo a dia-
gonal (6, 1) – (1, 6). Portanto, apostar na soma intermediária, 7, é sempre mais
vantajoso que apostar em qualquer outra, de 2 (1, 1) a 12 (6, 6). Aqui, como em
muitas outras situações da vida, a verdade está no meio. Ou, para ser mais mate-
mático, na média.
No mesmo quadro de possibilidades, você pode analisar as chances para os
outros dois modos de jogo. No modo padrão, o Comum, também existe uma
pequena variação de chances. Se você escolher qualquer par de números
diferentes – digamos (2, 3) –, suas chances serão 2 em 36. No exemplo, elas são
exatamente (2, 3) e (3, 2). Mas há seis casos especiais, todos localizados na outra
diagonal do quadrado: (1, 1) – (6, 6). Isso significa que se você fizer apostas
duplas (dados iguais), só terá uma chance em 36. O caso da modalidade Ordem
é mais rígido: não admite variações. Em qualquer lance, as chances são abso-
lutamente idênticas: 1 em 36.
Bem, depois dessa breve incursão probabilística, voltemos ao código. Para-
mos na apuração do lance de dados. Agora, é preciso escrever no placar o resul-
tado da apuração. Isso é feito pela rotina Sub EscreveResultado, que recebe
como parâmetro o número de pontos calculado (0, 1 ou 2). Como já vimos, so-
mente o valor 2 conta um ponto no placar. Os outros dois valores possíveis indi-
cam que o jogador fez uma aposta errada.
A rotina EscreveResultado vai acumulando o número de lances de cada
partida. Quando esse número chega a 13, o jogo é interrompido e o resultado fi-
nal é informado ao jogador, numa mensagem. A acumulação do número de lan-
ces, assim como os outros resultados, é mostrada em caixas de texto.
Nesse caso, melhor seria usar o controle label, que apenas exibe a informa-
ção sem dar nenhum acesso ao usuário. No entanto, preferimos usar caixas de
texto com a propriedade Locked=True. Isso significa que o jogador pode colo-
car o cursor na caixa de texto, mas não tem condições de editar seu conteúdo.
Outra alternativa impediria até mesmo que o controle recebesse o foco: desligar
a propriedade Enabled, fazendo-a igual a False. O defeito desse caminho é que o
texto passa a ser mostrado numa cor cinzenta, desmaiada, típica dos controles
que estão desativados.
Isso conclui o que há para dizer sobre o código. Talvez valha a pena obser-
var ainda alguns detalhes. A caixa de combinação Modalidade (cboModalidade)
tem como propriedade Style a opção 2 – fmStyleDropDownList. Isso significa
que o controle não aceita digitação: o usuário pode apenas escolher uma das op-
ções da lista. Ainda sobre a caixa Modalidade: sempre que o jogador seleciona
novo modo de apuração, o botão Zerar é acionado. Se isso não fosse feito, seri-
am computados resultados de dois ou mais tipos de jogos diferentes – um proce-
dimento que não faz sentido. 299
Em Álea, para acentuar o grau de realismo do ambiente de jogo, todas as
molduras que abrigam dados recebem um fundo verde. A intenção é imitar o te-
cido que cobre as mesas de jogo nos cassinos. A pintura de verde é definida na
sub-rotina UserForm_Initialize. Para definir aquele verde, usei um valor em he-
xadecimal (&HC000&) copiado do ambiente da linguagem Visual Basic. Mas
se você achar estranho esse valor, ele na verdade corresponde à seguinte cor
RGB:

Verde = RGB(0, 192, 0)

Para ir mais além


Como sempre, aqui vão algumas idéias que você pode tomar como ponto de
partida para melhorar o jogo de dados, ou mesmo construir outro mais sofisti-
cado.
1. Você pode criar outras modalidades de jogo, além de Comum,
Ordem e Soma. Uma delas seria, por exemplo, o Pelo Menos Um. Por
esse modo, contaria ponto em cada lance o jogador que acertasse,
pelo menos, o valor de um dos dados. Para incluir novas modalida-
des, você precisa modificar apenas a lista na caixa Modalidade e a ro-
tina cmdZerar_Click. Além disso, é claro, seria preciso criar mais
uma rotina de apuração.
2. Ao desenvolver um algoritmo para apurar essa nova modalidade, apro-
veite para analisar as probabilidades usando o quadro mostrado neste
capítulo.
3. O tipo de design que acabei encontrando para a tela do jogo me levou a
entender que não devia incluir um botão Fechar. Reconheço: esta não é
uma decisão correta. Afinal, o jogo Álea é uma caixa de diálogo do
Word. E todas as telas desse tipo têm um botão Fechar. Talvez você en-
contre um design mais adequado. Havia espaço, por exemplo, junto ao
botão Rolar os Dados. Mas acredito que ficaria confuso deixar lado a
lado o principal botão de operação do programa e o botão de encerra-
mento. Uma eventual solução seria:
a) deslocar o quadro Placar para baixo, alinhando-o com a mesa da banca;
b) transferir o botão Rolar os Dados para cima; e
c) incluir um botão Fechar, na posição antes ocupada pelo botão Rolar
os Dados.

300
O segredo está na matriz
Na rotina UserForm_Initialize do jogo Álea, você encontra um trecho
assim:

imgVazio.BackColor = Verde
imgBanca1.BackColor = Verde
imgBanca2.BackColor = Verde
imgAposta1.BackColor = Verde
imgAposta2.BackColor = Verde

Observe: os objetos são diferentes, mas a propriedade definida é


a mesma: BackColor. Nesse caso, é possível transformar o código em
algo menos repetitivo: Assim:

Dim c as Variant
For Each c In Array(imgVazio, imgBanca1, imgBanca2, _
imgAposta1, imgAposta2)
c.BackColor = Verde
Next

O segredo, aí, está na construção da matriz (Array) com os cinco


controles. Atenção: eu falei os cinco controles, e não os nomes deles.
Eis porque os nomes não estão entre aspas – não são strings. Para que
esse truque funcione, é obrigatório que a variável c seja declarada
como Variant. Conclusão: os elementos de uma matriz definida pela
função Array podem ser listados com um loop For Each/Next, da mes-
ma forma que os membros de uma coleção.

301
33
Não fique
fora do prazo!

Um calendário que faz operações com datas,


e sabe contar sábados, domingos e feriados

Ficha do projeto
Projeto:

PrazoCerto, calendário e calculador de datas, com ajuste


de prazos

O que faz:

Usa um calendário gráfico como ponto de partida para


efetuar cálculos com datas e prazos, nas seguintes
modalidades:
1) dias corridos simples;
2) dias corridos com data final em dia útil; e
3) somente dias úteis.
Nas modalidades 2 e 3, o aplicativo manipula um
banco de dados de feriados, que pode ser ajustado pelo
usuário.

Usuários potenciais:

Na parte do calendário, o interesse é geral. Nos cálculos


de prazos, advogados, juízes, contabilistas e outros
profissionais que definem ou controlam prazos em
atividades jurídicas ou comerciais.
302
Arquivos do projeto:

1. Objeto-calendário (Mscal.ocx), do Office 97 ou do Office 2000 Professional.


2. Banco de dados Prazos.mdb (incluído no disco anexo a este livro).
3. Modelo Prazos.dot, que contém todo o código do projeto.
4. Formulários frmPrazoCerto, frmFeriados, frmNovosFeriados e frmCalConfig
(embutidos em Prazos.dot)

Conhecimento técnico:

Inclusão e manipulação de objeto ActiveX num projeto VBA. Trabalho com múltiplos
formulários (forms) num mesmo projeto. Programação de bancos de dados.

Nível de programação

Avançado

O objetivo deste projeto é, mais uma vez, lidar com operações de datas para cal-
cular prazos. Mais especificamente, vamos criar uma ferramenta para calcular
prazos legais e comerciais, levando em conta se as datas de início e término caem
em finais de semana ou feriados. Para isso, vamos construir uma aplicação rela-
tivamente complexa, com um objeto ActiveX, um banco de dados Access e vári-
os formulários.
Antes de tudo, vamos esclarecer um detalhe fundamental: todos os formu-
lários de Prazo Certo residirão num modelo. Portanto, comecemos por esse ar-
quivo. No Word, crie um arquivo novo e salve-o como o modelo Prazos.dot.
Em seguida, passe para o ambiente de programação do VBA (Alt+F11), localize
o item Project (Prazos ) e selecione-o. Para criar os formulários, você deverá ir
ao menu Inserir e acionar UserForm. Assim, os formulários serão salvos dentro
do modelo Prazos.mdb. Passemos ao desenho do formulário principal, frmPra-
zoCerto. A visualização dos controles nesse formulário ajudará a entender a
proposta geral do projeto.
O formulário frmPrazoCerto contém os seguintes controles:

Objeto ActiveX Calendar (Cal)


Tem duas finalidades. A primeira, obviamente, é um calendário para consulta.
Aceita datas de janeiro de 1900 a dezembro de 2100. A segunda função é servir
de instrumento para entrada de dados. O usuário não precisa digitar (e errar)
datas: basta indicá-las com o mouse, clicando o dia no corpo do calendário e es-
colhendo mês e ano nas caixas de combinação, localizadas na parte superior do
controle. A data indicada é, imediatamente, copiada para a caixa Data Inicial.
Vale observar que esse objeto ActiveX faz parte do Office, 97 ou do 2000. Se
você tem instalado apenas o Word, é possível que o calendário não esteja dispo-
nível em sua máquina. Então, será preciso recorrer ao utilitário de instalação do
Office e acrescentar o calendário. 303
F I G U R A 3 3 . 1 O formulário frmPrazoCerto em tempo de
desenvolvimento

Etiquetas Data Inicial (labDataInicial), Data Final (labDataFinal) e Dia da


Semana (labDiaDaSemana); caixa de texto Prazo (txtPrazo); botão Calcular
Para calcular um prazo, o usuário indica uma data inicial no calendário e digita
um prazo, em dias, na caixa Prazo. Depois, aciona o botão Calcular (cmdCalcu-
lar) ou a tecla Enter. O programa oferece um resultado nas etiquetas Data Final
e Dia da Semana, que fica logo abaixo de Data Final. A primeira exibe a data cal-
culada e a outra, o dia da semana correspondente.
Os controles acima constituem o grupo básico que garante a operação do
programa. Todos os outros desempenham funções complementares.

Caixas de verificação Final: Dia Útil (chkFinalDiaÚtil) e Só Dias Úteis


(chkSóDiasÚteis)
Esses controles dão ao usuário opções para modificar o cálculo do prazo. Final:
Dia Útil, como o nome indica, pede que o prazo seja determinado de forma que
o último dia seja útil. Ou seja, os sábados, domingos e feriados que estiverem
dentro do período serão contados normalmente. Já a opção Só Dias Úteis faz a
contagem sem incluir os fins de semana, nem os feriados.

Botões de opção Dia (optDia), Semana (optSemana) e Mês (optMes)


Esses botões permitem calcular o prazo, tomando, como unidade, dias (o pa-
drão), semanas e meses.

Botão de comando cmdHoje e etiqueta labHoje


Abaixo do objeto-calendário, há ainda dois controles: o botão cmdHoje, sem le-
genda, faz o calendário exibir a data atual; e a etiqueta labHoje exibe a data atu-
304 al, em formato extenso. Por exemplo, “segunda-feira, 11 de outubro de 1999”.
O botão sem legenda revela uma das fragilidades do VBA: você só enxerga a le-
genda se o botão tiver uma altura mínima de 18. Assim, todo botão de comando
de pequena altura não pode ter a propriedade Caption. Para compensar, colo-
quei a palavra “Hoje” na propriedade ControlTipText desse botão. Assim, se
você passar o mouse sobre ele, vai ter uma dica do que ele faz.

Botões de comando Ajuda (cmdAjuda), Copiar (cmdCopiar), Feriados


(cmdFeriados), Configurar (cmdConfigurar) e Fechar (cmdFechar)
Resta-nos, apenas, indicar a função desses cinco botões no topo do formulário. O
botão Ajuda abre uma caixa de mensagem com um texto que orienta o usuário sobre
como operar o aplicativo. O botão Copiar armazena, na área de transferência, a data
final obtida num cálculo, no formato: “28/08/2000, segunda-feira”. Assim, o usuário
pode colar a informação num texto do Word ou em outro documento.
Para efetuar cálculos de prazos levando em conta os feriados, é preciso in-
formar ao programa quando caem esses feriados. O botão Feriados abre outro
formulário (frmFeriados), que exibe uma lista das datas cadastradas como feria-
dos fixos (válidos em qualquer ano) e como feriados móveis (variam, conforme o
ano). Esse form, por sua vez, permite que o usuário inclua no banco de dados no-
vos feriados, fixos e móveis, o que é feito com o formulário frmNovosFeriados.
Vem agora o botão Configurar. Clicado, ele abre o formulário frmCalCon-
fig, cuja função é definir modificações no objeto calendário Cal. Por fim, o bo-
tão Fechar (cmdFechar) dispensa comentários.

Construção do formulário principal


Esclarecidas as funções de cada objeto no formulário principal, podemos avan-
çar agora para a construção desse formulário. Naturalmente, não será necessá-
rio mostrar, passo a passo, o desenho de cada objeto. O grande destaque, nesse
formulário, é a inclusão de um objeto ActiveX, o calendário.

F I G U R A 3 3 . 2 O formulário frmPrazoCerto, em operação 305


Acione Inserir/UserForm para criar o formulário. Ajuste-o para o tamanho
que achar mais adequado e, na caixa de propriedades, mude o nome dele para
frmPrazoCerto. Veja, agora, como incluir o calendário. Clique no formulário
para garantir que o foco está nele. Deve aparecer a Caixa de Ferramentas. Se
isso não acontecer, vá ao menu e acione Exibir/Caixa de Ferramentas. Agora,
clique com o botão direito do mouse nessa caixa e escolha Controles Adicionais.
Abre-se nova janela, na qual você deve localizar e selecionar o item Calendar
Control 8.0 – ou Controle Calendário 8.0, conforme o idioma do Office.

F I G U R A 3 3 . 3 Ativação do controle calendário

O ícone do Calendário aparece na Caixa de Ferramentas. Clique nele e de-


senhe um controle no formulário. Ajuste o tamanho do calendário para que os
nomes dos meses e as datas fiquem bem visíveis. Se você usa o Office 97, vai no-
tar que existe um pequeno bug na caixa de combinação onde estão listados os
meses. O mês de maio é apresentado como “mai”, sem o “o” final.
Alguns controles, como Data Inicial e Data Final, são etiquetas cuja cor de
fundo é igual à cor do formulário. Isso foi adotado para estabelecer um contras-
te com a cor branca da caixa Prazo. Assim, o usuário já percebe, visualmente,
que é possível digitar em Prazo, mas as informações nos outros controles são
apenas para leitura.

O código
É hora de passar ao código que executa o cálculo dos prazos. Na rotina User-
Form_Initialize, definem-se alguns padrões:

306
Me.Caption = “Operações com Datas”
intUnid = 1
Cal.Today ‘ ou: Cal.Value=Date
AtualizaDataInicial
labHoje = Format$(Date, “Long Date”)
txtPrazo.SetFocus

Primeiro, o título do formulário – que também poderia ser definido na cai-


xa Propriedades. Depois, a variável intUnid, referente à unidade do prazo (1
para dia, 2 para semana e 3 para mês. Em seguida, força-se o calendário a exibir
a data atual.
Isso pode ser definido pelo método Today ou pela propriedade Value. Por-
tanto, as duas linhas abaixo são equivalentes:

Cal.Today
Cal.Value = Date

Definida a data no calendário, é preciso que a label DataInicial também


exiba essa data. Para isso chama-se a rotina AtualizaDataInicial. Essa rotina re-
solve-se em, apenas, uma linha:

labDataInicial = Format$(Cal.Value, “dd/mm/yyyy”)

Por fim, coloca-se o foco em txtPrazo, para que o usuário possa digitar um
número. Ao evento KeyPress (pressionamento de tecla) de txtPrazo está associa-
do um código que só aceita a digitação de números, do sinal menos (–) e do bo-
tão de retrocesso. Isso diminui as possibilidades de erro.
Vale lembrar que a definição da propriedade ValueIsNull do calendário para
o valor False, nos eventos NewMonth e NewYear, é de fundamental importância.
Se isso não for feito, o objeto calendário ficará sem valor quando o usuário esco-
lher um mês ou um ano nas caixas de combinação. Também é útil observar que
não funciona tentar eliminar a linha Cal.ValueIsNull = False daqueles dois proce-
dimentos e colocá-la, por exemplo, na sub UserForm_Initialize.
Muito bem. O usuário escreve um prazo e clica no botão Calcular. O que
acontece? O procedimento básico de cálculo é a função CalculaPrazo, que rece-
be a data inicial, o prazo e a unidade de prazo e devolve a data final. Em essên-
cia, essa função soma a data inicial ao prazo. Isso é obtido mediante a função in-
trínseca DateAdd. Exemplo:

DataFinal = DateAdd(“d”, n, DataInicial)

O argumento “d” indica que o número n – o prazo – é expresso em dias.


Assim, no exemplo, n dias são somados à DataInicial para se obter DataFinal.
Nesse caso, em que a unidade é dia, a operação poderia ser simplificada para:
307
DataFinal = DataInicial + n

Vale lembrar que, se n for negativo, a data final será anterior à final. Em
outras palavras, tem-se aí uma subtração. Todo o cerne do problema resume-se
a essa operação. Só que, na prática, não é tão simples. E o que complica são as
opções. Aqui, é importante discutir, com mais detalhes, os critérios de ajuste da
data final usados para cada opção. A opção Final: Dia Útil é estabelecida como
padrão. Assim, se a data calculada cair num fim de semana ou num feriado, de-
verá ser empurrada para o primeiro dia útil à frente.
Ao mesmo tempo, o prazo deve sempre ser contado a partir de um dia útil.
Por exemplo, se hoje é dia 3 e o prazo é de cinco dias, então a data final será o
dia 8. Isso é óbvio, mas atenção para o detalhe: se o dia 4, o primeiro da conta-
gem, não for útil, o início do prazo deve ser transferido para o próximo dia. Se
este também não for útil, o primeiro dia do intervalo vai sendo deslocado.
Exemplo: se 3 é sexta-feira, o dia 1 do prazo deverá ser a próxima segun-
da-feira. Se esta for feriado, terça-feira.
A sucessão de testes, no início e no fim do prazo, constitui o verdadeiro bu-
sílis desse cálculo. Há ainda outro complicador, que surge quando o usuário es-
colhe a opção Só Dias Úteis. Nesse caso, além de evitar fins de semana e feriados
no início e no fim da contagem, esses dias devem ser desconsiderados também
no meio do intervalo considerado. Vamos acompanhar, passo a passo, o traba-
lho da função CalculaPrazo.
Primeiro, ela define a string correspondente à unidade de prazo escolhida
pelo usuário: “d” para dia; “ww” para semana; e “m” para mês. Essa string é ar-
mazenada na variável sIntervalo. Em seguida, executa o cálculo para opção Só
Dias Úteis. Aqui, a estratégia é a seguinte. Para começar, determina-se qual é o
dia 1 do prazo. A partir dele, testa-se cada dia para saber se é especial (sábado,
domingo ou feriado). Coloca-se em ação um contador, que vai acumulando os
dias não especiais. Para cada dia não especial, soma-se 1 ao contador. Quando
esse contador for igual ao prazo, chegamos ao final.
Para a opção Final: Dia Útil, faz-se o teste para o primeiro dia e depois apli-
ca-se a soma normal data + prazo. Por fim, checa-se o resultado para garantir
que caia num dia útil. Em todas esses cálculos, falamos mais de uma vez em che-
car se a data cai num dia especial, ou seja, fim de semana ou feriado. Como isso é
feito? Duas funções fazem esse teste: E_DiaEspecial e E_Feriado.
Como foi dito no início, precisaríamos de um banco de dados para armaze-
nar os feriados. Para isso, criamos, no Access, o arquivo Prazos.mdb, que con-
tém duas tabelas: tabFeriadosFixos e tabFeriadosMóveis. Feriados fixos, só
para lembrar, são aqueles que ocorrem todos os anos na mesma data. São oito
no ano inteiro:

308
FERIADO FIXO DATA

1 Confraternização Universal 1o de janeiro

2 Tiradentes 21 de abril

3 Dia do Trabalho 1o de maio

4 Independência 7 de setembro

5 N.Sra. Aparecida 12 de outubro

6 Finados 2 de novembro

7 República 15 de novembro

8 Natal 25 de dezembro

A estes feriados fixos, o usuário deve acrescentar os feriados estaduais ou


municipais válidos em sua região. No Estado de São Paulo, por exemplo,
deve-se incluir o 9 de Julho, data da Revolução Constitucionalista de 1932. Já
os usuários baianos deverão incluir no banco de dados o 2 de Julho, data em que
se comemora a independência da Bahia (1823).
Os feriados móveis, como o nome sugere, mudam ano a ano e caem em da-
tas calculadas com base em eventos astronômicos e religiosos. A data básica é a
Páscoa, festa cristã que comemora a ressurreição de Jesus e cai no primeiro do-
mingo após a primeira lua cheia, a contar de 21 de março. O domingo de Carna-
val e a festa de Corpus Christi, outros feriados móveis, caem, respectivamente,
49 dias antes e 60 dias depois da Páscoa. Portanto, são três feriados móveis a
cada ano: Carnaval (terça-feira), Sexta-Feira Santa (a sexta-feira antes do do-
mingo de Páscoa) e Corpus Christi.
O cálculo dessas três datas é bastante complexo e não está incluído neste
projeto. No banco de dados Prazos.mdb você encontra todos os feriados fixos
nacionais e todos os móveis, de 1995 até 2005. Para usar o programa adequada-
mente, você precisa incluir os feriados locais de sua região.
Assim, dada uma data, a função E_DiaEspecial verifica se:
n é sábado;
n é domingo;
n é feriado fixo ou feriado móvel.
Para isso, E_DiaEspecial conta com a ajuda da função E_Feriado, que se
encarrega do terceiro item, acima. O teste para sábado e domingo é muito
simples. Basta verificar se o dia da semana corresponde a 1 (domingo) ou a 7
(sábado):

If intDia = 1 Or intDia = 7 Or E_Feriado(umaData) Then


E_DiaEspecial = True 309
A função E_Feriado, por sua vez, abre o banco de dados Prazos.mdb e veri-
fica se a data consta na tabela tabFeriadosFixos ou na tabela tabFeriadosMóveis.
Todo o resto, digamos assim, são detalhes de acabamento do programa.
Eis alguns exemplos:
Quando o usuário escolhe a opção Só Dias Úteis e, em seguida, define a
unidade de prazo como semana ou mês, automaticamente a caixa Só Dias Úteis
é desligada. Seria muito demorado executar o cálculo com combinação dessas
opções.
Observe que a label labHoje não acompanha as mudanças de data que o
usuário define no calendário. Ela mostra, sempre, a data atual.
Quando a data final obtida foi empurrada para a frente porque no primei-
ro cálculo caiu em fim de semana ou feriado, o dia da semana, abaixo da data,
exibe um asterisco.
A opção Final: Dia Útil é padrão. Se o usuário a desligar, o cálculo será feito
de modo simples. Ou seja: o número de dias corridos entre a data inicial e a final.
Quando se liga a opção Só Dias Úteis, ativa-se também, automaticamente,
a opção Final: Dia Útil. Do mesmo modo, ao se desligar a opção Final: Dia Útil,
desliga-se também a outra.
O botão Ajuda apresenta uma caixa de mensagem com um texto que resu-
me as orientações necessárias para operar o programa:

F I G U R A 3 3 . 4 Ajuda: todo o texto numa caixa de mensagem

Merece destaque a rotina associada ao clique no botão Copiar. Ela mostra


como armazenar informações na Área de Transferência do Windows (Clipbo-
ard). Observe o trecho de código a seguir. Primeiro, cria-se um objeto strCopy,
pertencente à classe DataObject. Em seguida, define-se um texto para esse obje-
to, com o uso do método SetText. No caso, o texto é uma combinação do conte-
údo da label Data Final com o da label associada, labDiaDaSemana. Por fim,
310 usa-se, então, o método PutInClipboard a fim de copiar o texto para a memória.
Dim strCopy As DataObject
Set strCopy = New DataObject
sClipboard = labDataFinal & “, ” & strDia
strCopy.SetText sClipboard
strCopy.PutInClipboard
Set strCopy = Nothing

Formulário frmFeriados
Quando o usuário clica no botão Feriados, no formulário principal, abre o for-
mulário frmFeriados. Este tem duas tarefas básicas a cumprir. A primeira é exi-
bir as listas dos feriados, fixos e móveis, cadastrados no banco de dados Pra-
zos.mdb. A segunda é permitir que o usuário cadastre novos feriados.

F I G U R A 3 3 . 5 As tabelas de feriados: fixos e móveis

A estrutura desse formulário é bastante simples. Consta apenas de duas cai-


xas de listagem e três botões. As caixas, Fixos (lstFixos) e Móveis (lstMoveis),
recebem as listas dos feriados cadastrados. Os botões são Fechar (cmdFechar),
Novo Fixo (cmdNovoFixo) e Novo Móvel (cmdNovoMóvel).
No evento de inicialização do formulário, entram em ação os procedimen-
tos ListaFixos e ListaMóveis, que abrem o banco de dados Prazos.mdb, lêem as
tabelas tabFeriadosFixos e tabFeriadosMóveis e preenchem, no formulário, as
caixas de listagem lstFixos e lstMóveis. Com isso, frmFeriados cumpre sua pri-
meira tarefa.
A outra tarefa é permitir a inclusão de novos feriados. Para isso, deve
entrar em cena o terceiro formulário do projeto, frmNovosFeriados. Este
servirá para cadastrar tanto feriados fixos como móveis. Mas há um porém:
no banco de dados, as tabelas para esses tipos de datas têm estruturas diferen-
tes. De fato, tabFeriadosFixos tem três campos: Dia, Mês e Descrição, como
mostrado a seguir.

311
Dia Mês Descrição

1 1 01/01: Confrat. Universal

1 5 01/05: Dia do Trabalho

2 11 02/11: Finados

A outra tabela, tabFeriadosMóveis, organiza-se com apenas duas colunas:

Feriado Descrição

07/03/2000 Carnaval

21/04/2000 Paixão

22/06/2000 Corpus Christi

Por causa dessas diferenças, é preciso avisar ao formulário frmNovosFeria-


dos qual o tipo a ser cadastrado, a fim de que ele ofereça os campos adequados.
Então, quando o usuário clica no botão Novo Fixo, antes de abrir o formulário
frmNovosFeriados, define-se o valor de uma variável que avisa sobre a intenção
de cadastrar um feriado fixo. Processo idêntico ocorre quando o usuário clica
no botão Novo Móvel.
Há dois caminhos para passar essa informação de um formulário para o
outro. O tradicional seria criar um módulo de programação e lá declarar três va-
riáveis públicas:

Public Const FER_FIXO As Integer = 1


Public Const FER_MOVEL As Integer = 2
Public p_intTipoFeriado As Integer

No procedimento associado ao clique no botão Novo Fixo, antes de abrir


o formulário frmNovosFeriados, seria definido o valor de p_intTipoFeriado.
Assim:

p_intTipoFeriado = FER_FIXO

No clique do botão Novo Móvel, a variável assumiria o outro valor:

p_intTipoFeriado = FER_MOVEL

Desse modo, como p_intTipoFeriado teria abrangência pública, bastaria,


ao abrir o outro formulário, verificar se essa variável teria o valor de feriado fixo
(FER_FIXO) ou de feriado móvel (FER_MOVEL).
312
Em termos de lógica e funcionamento, essa solução está perfeita. No en-
tanto, os especialistas em programação aconselham que se evite usar variáveis
globais, sempre que possível. Variáveis que criam vínculos de um módulo para
outro acabam tornando o código mais difícil de ler e de atualizar. O ideal é que
cada módulo funcione como uma entidade independente.
Veja, então, uma solução mais moderna. Para fugir das variáveis públicas,
vamos lançar mão de um recurso de orientação a objeto, tal como implementa-
do no Visual Basic. A idéia é criar uma propriedade a mais para o formulário
frmFeriados. Chamemos essa propriedade de TipoFeriado. Para criá-la, faça o
seguinte. Primeiro, na área de declarações do formulário, dimensione a variável
m_TipoFeriado:

Dim m_TipoFeriado As Integer

Agora, inclua no módulo do formulário um procedimento Property Get:

Property Get TipoFeriado() As Integer


TipoFeriado = m_TipoFeriado
End Property

Para ter certeza de que criou a propriedade, basta ir à janela Imediata e di-
gitar o nome do formulário, seguido de um ponto. Você vai ver que na lista
pop-up de métodos e propriedades aparece TipoFeriado. O valor dessa proprie-
dade é definido quando o usuário clica num dos botões Novo Fixo ou Novo
Móvel. Lá, m_TipoFeriado assume o valor 1 ou 2. Resultado: tudo se mantém,
internamente, no formulário. Ao mesmo tempo, a propriedade pode ser lida de
fora, por causa do procedimento Property Get.

Formulário frmNovosFeriados
A primeira tarefa do formulário frmNovosFeriados é verificar o valor da propri-
edade TipoFeriado do formulário que o chama, frmFeriados. Isso é feito da se-
guinte maneira. Primeiro, são declaradas duas constantes:
Const FER_FIXO As Integer = 1
Const FER_MOVEL As Integer = 2

Em seguida, os testes são feitos contra os valores dessas constantes:


If frmFeriados.TipoFeriado = FER_MOVEL Then

Conforme o valor, o formulário muda de cara, para acomodar a entrada de


dados para a tabela tabFeriadosFixos ou para a tabela tabFeriadosMóveis. Seu
título também muda: “Novo Feriado Fixo” ou “Novo Feriado Móvel”. Além
disso, na hora de salvar as informações digitadas, há dois procedimentos: Sal-
varNovoFixo e SalvarNovoMóvel. 313
Pode-se objetar que a construção de uma propriedade para o formulário
frmFeriados não é a melhor solução nesse caso. Correto. Aproveitei o exemplo
como uma oportunidade para mostrar esse recurso. Mas ele de fato não é o me-
lhor momento para a inserção de uma propriedade, criada pelo programador.
Outra solução, mais tradicional, seria a seguinte. No form frmFeriados, o clique
no botão Novo Fixo ou Novo Móvel já definiria o título (e, portanto, a configu-
ração) do form frmNovosFeriados. Assim:

Load frmNovosFeriados
frmNovosFeriados.Caption = “Novo Feriado Fixo”
frmNovosFeriados.Show

A primeira linha carrega, mas não exibe, o formulário frmNovosFeria-


dos. A segunda define um título para esse formulário: “Novo Feriado Fixo”
ou “Novo Feriado Móvel”. A terceira, por fim, exibe-o. Agora, no evento de
inicialização do formulário, a configuração da tela será definida em função
do título:

If Me.Caption = “Novo Feriado Fixo” Then

F I G U R A 3 3 . 6 O formulário, para feriados fixos

F I G U R A 3 3 . 7 O mesmo formulário, para feriados móveis

314
O formulário frmNovosFeriados contém três caixas de texto (txtDiaData,
txtMês e txtDescrição) e dois botões de comando: Salvar (cmdSalvar) e Cance-
lar (cmdCancelar). Quando o objetivo é cadastrar um feriado fixo, as três caixas
de texto aparecem, normalmente, com os rótulos Dia, Mês e Descrição. Quan-
do o feriado é móvel, opera-se a metamorfose: oculta-se a caixa de texto Mês e a
caixa Dia recebe o rótulo Data, ficando mais comprida e descendo para a posi-
ção da caixa Mês.
Na hora de salvar a informação digitada pelo usuário, executa-se um teste
para verificar a validade da data. Depois de registrada a nova informação no
banco de dados, a lista de feriados correspondente no formulário Feriados é atu-
alizada. Aqui há dois pontos a observar. Primeiro: para atualizar as caixas de lis-
ta no outro formulário, usam-se procedimentos que também estão lá:

frmFeriados.lstFixos.Clear
frmFeriados.ListaFixos

Isso não acontece por acaso. Observe que as sub-rotinas ListaFixos e Lista-
Móveis são registradas como procedimentos públicos. Somente assim elas pode-
riam ser chamadas a partir de outro módulo. O outro ponto refere-se também a
essas rotinas. No formulário frmFeriados, elas poderiam muito bem ser reuni-
das numa só. Mas, assim, quando se incluísse um novo feriado fixo, seria neces-
sário atualizar as duas caixas. Com as rotinas separadas, atualiza-se somente a
lista afetada.
O quarto formulário do projeto, frmCalConfig, não introduz nenhum tipo
de modificação nos procedimentos de cálculo. Ele tem apenas função cosmética.
Seu objetivo é definir como o objeto-calendário se apresenta. Especificamente, se
ele exibe o domingo (que é o padrão) ou a segunda-feira como o primeiro dia da
semana. Essa configuração é definida mediante a propriedade FirstDay do objeto:

frmPrazoCerto.Cal.FirstDay = vbMonday

Observe, aí, a presença das constantes intrínsecas do Visual Basic: vbSun-


day, vbMonday, vbTuesday, correspondentes aos números dos dias da semana:
1 a 7. No controle calendário, a semana pode começar em qualquer dia. No en-
tanto, o formulário frmCalConfig oferece apenas duas opções: domingo e se-
gunda-feira. Algumas pessoas preferem os calendários com a segunda-feira
como dia inicial porque, nesse layout, os dias dos fins de semana ficam provi-
dencialmente juntos.
A estrutura de frmCalConfig é bem enxuta. Tem dois botões de comando,
OK (cmdOK) e Cancelar (cmdCancelar), e dois botões de opção, Domingo
(opt1) e Segunda-feira (opt2). Além de definir a forma de apresentação do ca-
lendário, esse formulário também armazena no Registro do Windows a configu-
ração escolhida pelo usuário. Assim, na próxima vez que ele abrir o projeto, o
calendário será exibido no padrão antes selecionado. Tudo isso é feito no even-
to associado ao botão OK do formulário: 315
F I G U R A 3 3 . 8 Tela para configuração do calendário

Dim intDia As Integer

If opt1.Value = True Then


intDia = vbSunday ‘ domingo
Else
intDia = vbMonday ‘ segunda-feira
End If

If frmPrazoCerto.Cal.FirstDay <> intDia Then


frmPrazoCerto.Cal.FirstDay = intDia
SaveSetting “WordCalendar”, “Configs”, _
“DiaInicial”, Trim$(Str$(intDia))
End If
Unload Me

O que ocorre aqui? Primeiro, captura-se o dia inicial escolhido pelo usuá-
rio. Depois, verifica-se se ele não é o que já está aplicado ao calendário. Em caso
negativo, modifica-se a propriedade FirstDay do calendário e armazena-se a in-
formação no Registro do Windows, com a ajuda da instrução SaveSetting:
SaveSetting “WordCalendar”, “Configs”, _
“DiaInicial”, CStr(intDia)

A sintaxe para essa instrução é a seguinte:

SaveSetting aplicação, seção, chave, valor

O parâmetro aplicação indica o nome do programa. Em nosso caso, colo-


camos WordCalendar. Portanto, cria-se no Registro uma entrada com esse
nome. Dentro dela, cria-se também um nome de seção (“Configs”) e, dentro
dessa seção, uma chave (DiaInicial) e o seu valor – aqui representado pelo núme-
ro do dia da semana escolhido. Se houvesse outras configurações, o procedi-
mento seria idêntico. Bastaria mudar o nome da chave e, naturalmente, o valor.
As informações ficam guardadas na chave HKEY_CURRENT_USER\Softwa-
316 re\VB and VBA Program Settings\WordCalendar\ Configs.
F I G U R A 3 3 . 9 O Registro: onde fica armazenada a
configuração do calendário

Para que o calendário exiba a configuração armazenada no Registro, o for-


mulário frmPrazoCerto, que abriga o calendário, precisa saber qual é essa confi-
guração. Por isso, no procedimento de inicialização desse formulário há algu-
mas linhas de código marcadas com a observação de que estão ligadas ao form
frmCalConfig. Elas são as seguintes:

Dim sDiaIni As String


‘ Lê o arquivo Calendar.ini
sDiaIni = GetSetting(“WordCalendar”, _
“Configs”, “DiaInicial”, “1")
Cal.FirstDay = Val(sDiaIni)

Aqui entra em ação a função GetSetting, que faz o papel inverso de Save-
Setting. Ela envia os parâmetros aplicação, seção e chave e recebe de volta o va-
lor da chave. O quarto parâmetro – “1”, no exemplo – é opcional e funciona
como padrão. Ou seja, se não existir a informação, a função retorna “1”. Esse
número foi escolhido porque é também o valor-padrão do calendário. Um deta-
lhe: as informações enviadas ao Registro ou lidas nele com SaveSetting e GetSet-
ting são sempre seqüências de caracteres. Daí o “1”, entre aspas.
Agora, falta apenas um pequeno toque para fechar a aplicação. Você se
lembra: construímos um programa dentro de um arquivo modelo. Então, é bom
que, quando o usuário dê um duplo clique nesse arquivo, o programa se abra.
Como se obtém isso? É simples. Na janela de projeto, observe que, além dos for-
mulários, o projeto Prazos exibe o item ThisDocument. Dê um duplo clique
nele. Abre-se a janela do módulo ThisDocument. Nela, clique na caixa Geral e
depois na opção Document. O VBA cria, automaticamente, o espaço para o pro-
cedimento Document_New. O que você incluir nesse procedimento deverá
acontecer toda vez que for criado um novo documento com base no modelo
Prazos.dot. Como toda a aplicação está contida em três formulários, vamos en-
tão comandar para que seja aberto o formulário principal. Então, a rotina, com
apenas uma linha, fica assim:
317
Private Sub Document_New()
frmPrazoCerto.Show
End Sub

Missão cumprida. Agora, sempre que você criar um novo documento a


partir de Prazos.dot, abrirá, imediatamente, o formulário frmPrazoCerto, com
o calendário e a interface para o cálculo de prazos.

Para ir mais além


1. Prazo Certo é uma aplicação genérica e, portanto, pode ser executada
em qualquer aplicação do Office. Ou, melhor ainda, em qualquer apli-
cação que suporte as versões do VBA do Word 97 ou do 2000. Você
pode experimentá-la no Excel, por exemplo. Para isso, no ambiente do
VBA, selecione os três formulários da aplicação (um de cada vez) e ex-
porte-os (Arquivo/Exportar Arquivo) para o disco. Eles produzirão ar-
quivos FRM, com os mesmos nomes dos módulos: frmPrazoCerto.frm,
frmFeriados.frm e frmNovosFeriados.frm. Para cada um desses arqui-
vos, haverá também um homônimo com a extensão FRX. Os arquivos
FRX contêm informações binárias sobre o form. No Excel, faça a opera-
ção inversa: use o comando Arquivo/Importar Arquivo para incluí-los
numa planilha. Detalhe: a única linha de código exclusiva do Word é
ActiveDocument.Close

na rotina cmdFechar_Click. Elimine essa linha e você terá uma aplica-


ção prontinha para rodar no Excel. No Office 2000, você pode fazer o
mesmo para o Access e para o PowerPoint.
2. Ao clicar no botão Fechar do formulário principal, você fecha o
aplicativo e, ao mesmo tempo, o documento que lhe dá suporte. Agora,
a título de teste, clique no outro botão Fechar, no canto superior direito
do formulário. O que ocorre? O formulário se fecha, mas o documento
que o contém, não. Deixei essa brecha no aplicativo para que você,
enquanto o estuda, possa fechar o formulário principal sem fechar,
também, o documento (mas, para isso, não esqueça: clique no canto
do formulário). Se quiser fechar formulário e documento nos dois
botões de saída, retire a linha ActiveDocument.Close do procedimento
cmdFechar_Click e transfira-a para UserForm_QueryClose.
3. Como Prazo Certo entrega ao usuário um banco de dados com todos os
principais feriados fixos do país e todos os feriados móveis até 2010, en-
tendi que a interface de acesso ao banco de dados deveria ser mínima e
dar direito apenas a consulta e, em raros casos, à inclusão de novas da-
tas. Você pode mudar isso, criando formulários que permitam visualizar
318 e atualizar os feriados, da forma que achar mais interessante.
4. O controle Calendário tem muito mais métodos e propriedades que os
mostrados neste projeto. Para estudar melhor esse objeto, selecione-o
no formulário e acione a tecla F1. Será aberto um arquivo de ajuda com
todas as informações sobre o objeto.
5. Também é interessante acessar a página de propriedades do controle
Calendário. Selecione esse controle no formulário e, na caixa Proprie-
dades, clique na linha Personalizado. Em seguida, clique no botão que
tem três pontos como legenda. Surgirá a caixa mostrada abaixo.Ela
mostra muitas das propriedades do calendário.

F I G U R A 3 3 . 1 0 Caixa de propriedades do objeto calendário

6. Agora que você já conhece as propriedades do calendário, modifique o


formulário frmCalConfig para dar ao usuário outras opções de configu-
ração do objeto. Por exemplo, mudar cores e fontes dos nomes dos dias
e meses; ou exibir ou não as caixas de combinação com os anos e meses.
7. Remodele o formulário frmPrazoCerto e arranje lugar para incluir dois
novos botões com a finalidade de ir para o mês anterior ou para o próxi-
mo. Os métodos são muito simples: Cal.NextMonth e Cal.Previous-
Month. Se quiser, também pode fazer o mesmo para saltar anos:
Cal.NextYear, CalPreviousYear.
8. Atenção: criei os primeiros esboços iniciais deste projeto com aplicati-
vos do Office 97 – primeiro com o Access e, depois, com o Word. Nessa
versão, na caixa de combinação ao alto do calendário, Maio aparecia
como “Mai”, enquanto os outros meses exibiam a grafia por extenso. O
problema foi corrigido na versão 2000.

319
Caçando com gato perdigueiro...
Você certamente já viu: em alguns programas, quando se vai escrever
uma data numa caixa de texto, abre-se um calendário para o usuário
indicar a data com o mouse, em vez de digitá-la. Aquilo exige um
objeto específico para mostrar o calendário pop-up ou muita progra-
mação com a API do Windows. Esses recursos não estão ao nosso
alcance. Mas podemos fazer um quebra-galho. Veja como.

F I G U R A 3 3 . 1 1 Os formulários: o segundo aparece quando


se digita nas caixas Data1 e Data 2

Crie um formulário chamado frmPrincipal, que deve conter, entre


outros objetos, uma ou mais caixas de texto, representando campos de
data. Acrescente, em seguida, outro formulário, frmCalendário. O form
frmPrincipal tem vários controles, mas nos interessam somente as cai-
xas de texto txtData1 e txtData2. Para facilitar a comunicação entre os
dois forms, vamos agregar nova propriedade para frmPrincipal. Essa
propriedade se chamará CampoData e indicará qual campo de data foi
acionado para chamar o segundo formulário.
A criação dessa propriedade é dada pelos seguintes passos. Pri-
meiro, declare a variável m_CampoData:
Dim m_CampoData As Integer

Depois, adicione esta rotina ao código do formulário:


Property Get CampoData() As Integer
CampoData = m_CampoData
End Property
320
Agora, na rotina correspondente ao evento KeyPress das caixas de
texto txtData1 e txtData2, escreva:

m_CampoData = 1
frmCalendário.Show

Naturalmente, em txtData2, m_CampoData deve ser igual a 2.


Tudo pronto no primeiro form. Passemos a frmCalendário. Este deve ter
apenas o controle Calendário. Ao evento Click desse objeto faça cor-
responder a seguinte rotina:

Dim i As Integer
i = frmPrincipal.CampoData
frmPrincipal.Controls(“txtData” & i) = Calendar1.Value
Unload Me

Demonstração concluída. Abra frmPrincipal e comece a digitar


qualquer coisa numa das caixas de data. O que acontece? Ao acionar a
primeira tecla, o calendário aparece, com o título “Indique a data no
calendário”. Escolhida uma data, esta é transferida para o objeto a par-
tir do qual o calendário foi chamado e o formulário frmCalendário se
fecha. Não é a mesma coisa que o objeto calendário pop-up, mas vale
a pena. Quem não tem cão caça com gato.
Para arredondar esta demonstração, colocamos os dois formulá-
rios dentro do modelo Calendar.dot. Abra o modelo para ver como o
projetinho funciona.

Anos bissextos
Depois de toda a celeuma em torno do ano 2000 e seu famigerado
bug, agora ninguém mais tem dúvida: o ano 2000 é bissexto. Mas
como se verifica isso com um código em Visual Basic? Há várias formas
de fazer esse cálculo. A primeira atém-se à definição, estabelecida pelo
Calendário Gregoriano, de 1582: bissexto é todo ano múltiplo de 4,
exceto os múltiplos de 100 que não sejam, também, múltiplos de 400.
Exemplos: 1800, 1900, 2100 não são; mas 2000 e 2400 são bissextos.
Uma função que aplica essa definição é dada por:

Function AnoBissexto(Ano As Integer) As Boolean


If (Ano Mod 4 = 0 And Ano Mod 100 <> 0) _
Or (Ano Mod 400 = 0) Then
AnoBissexto = True
End If
End Function
321
Como essa definição já está embutida no calendário interno do
VBA, pode-se armar uma outra função ainda mais simples, com apenas
uma linha:

Function AnoBissexto1(Ano As Integer) As Boolean


AnoBissexto1 = IsDate(“29/2/” & CStr(Ano))
End Function
Neste caso, a função intrínseca IsDate checa se existe o dia 29/02
do ano dado. Se existir, o ano é bissexto. Uma terceira opção usa a fun-
ção DateSerial, partindo da idéia de que o dia 29/02 de um ano não
bissexto recai em 01/03:

Function AnoBissexto2(Ano As Integer) As Boolean


AnoBissexto2 = DateSerial(Ano, 2, 29) <> _
DateSerial(Ano, 3, 1)
End Function

O primeiro do três algoritmos acima tem a vantagem de ser uni-


versal. Pode, portanto, ser empregado, com as devidas adaptações, em
qualquer linguagem de programação. Os outros dois são específicos
do Visual Basic.

322
34
Mago de casa
também faz
milagre

Crie, você mesmo, um Assistente para extrair


informações de bancos de dados

Ficha do projeto

Projeto:

Assistente de Bancos de Dados

O que faz:

Este assistente (wizard) guia o usuário, passo a passo, para


abrir um banco de dados Access qualquer e extrair dele as
informações que desejar. As informações são apresentadas
como tabela do Word ou planilha do Excel. Portanto, este
projeto envolve o Word com dois outros integrantes do
pacote Office.

Arquivos e requisitos do projeto:

1. Os objetos de acesso a dados têm de estar instalados no


micro e ativos no Word.
2. Modelo Assistdb.dot (incluído no disco anexo a este
livro).
3. Arquivos de banco de dados Access (MDB) para testar o
assistente.
Conhecimento técnico:

Desenho e programação de formulários (forms) e controles. Molduras para exibir e


ocultar objetos. Programação de bancos de dados. Controle lógico da interface do
programa.

Nível de programação:

Avançado

O Assistente de Banco de Dados é o último e mais complexo projeto deste livro.


A maior dificuldade que ele apresenta não está exatamente no nível da progra-
mação, que é mais ou menos similar ao que você viu até agora. O grande proble-
ma, aqui, reside na lógica necessária para acompanhar a estrutura de uma apli-
cação que tem, apenas, um formulário, mas funciona como se tivesse seis.
Antes de avançar para a construção do projeto, vamos caracterizar o
problema. O que é um assistente? É um programa que ajuda o usuário a
executar determinada tarefa, guiando-o, passo a passo, por um caminho lógico.
Devido a esse caráter de programa “facilitador”, a Microsoft chamou o assis-
tente original de wizard – palavra inglesa para mago e, por extensão, espe-
cialista, mestre ou autoridade num assunto, um ás, um gênio.
Especificamente, a mágica dos assistentes consiste em dar ao usuário um
rumo ou roteiro para a execução de uma operação qualquer. Do ponto de vista da
interface, os assistentes em geral são aplicações de uma única tela. Na verdade,
mesmo os mais simples têm várias janelas, mas fazem o usuário acreditar que exis-
te apenas uma. Afinal, o objetivo é transformar a tarefa em algo fácil e rápido.
Nosso Assistente de Banco de Dados contém apenas um formulário com
seis passos lógicos, cada um representado por uma “página” – camada de obje-
tos que só são exibidos no momento adequado. Veja na Figura 34.1 a página ini-
cial do Assistente.

324 F I G U R A 3 4 . 1 Tela de abertura do Assistente de Bancos de Dados: passo 1


Basicamente, o programa vai auxiliar o usuário a realizar a seguinte lista de
tarefas:
1. Localizar e abrir um banco de dados Access.
2. Escolher, no banco de dados, a tabela da qual os dados serão extraídos.
3. Selecionar, na tabela, os campos em que estiver interessado.
4. Montar um filtro para extrair somente os registros desejados (opcional).
5. Classificar o registro por um ou mais campos (opcional).
6. Escolher o destino dos dados: tabela Word ou planilha Excel.
Observe que esta série obedece a uma lógica que vai do geral para o parti-
cular. O número de cada tarefa é também o número da página que a representa.
Até agora você deve estar perguntando o que vem a ser essa “página”. Vamos es-
clarecer. Visto por dentro – não na perspectiva do usuário, mas na do programa-
dor –, o formulário do Assistente (frmAssistente) contém, resumidamente, os se-
guintes objetos: Os botões na barra inferior (veja a Figura 34.1) e molduras (fra-
mes) na área que fica acima do traço horizontal. As molduras, que são seis, cor-
respondem às “páginas” do wizard. Elas ficam superpostas, todas na mesma po-
sição. No passo 1, mostra-se a moldura 1 e todas as outras permanecem ocultas.
No passo 2 é revelada a moldura 2, enquanto as outras são subtraídas da vista do
usuário. E assim por diante.
Em todos os passos, os botões da barra inferior continuam os mesmos. A
Ajuda é associada ao contexto. Se, no passo 3, o usuário clicar no botão Ajuda,
obterá informações específicas sobre a tarefa 3. O botão Avançar só permite
passar para a etapa seguinte se a atual já tiver sido completada. No passo 1, por
exemplo, nada acontece se o usuário clicar no botão Avançar, sem antes ter
indicado um banco de dados.
Para que ele indique o banco de dados com que deseja trabalhar, o assisten-
te exibe a caixa de diálogo Abrir, do Word (Figura 34.2). Aqui vale colocar um
parêntese importante. Se você estiver trabalhando com o Word 2000, tudo
bem. A versão do motor de bancos de dados correspondente ao Office 2000 é a
3.6 (Microsoft DAO 3.6 Object Library). Se, no entanto, você usar o Word 97, a
versão dessa biblioteca é a 3.5.
A questão é: programas que usam um motor mais antigo não conseguem
abrir bancos de dados baseados em versão mais nova. Portanto, se alguém lhe
passa um banco de dados do Access 2000, você não consegue abri-lo com o
Access 97. Para evitar esse problema, todos os bancos de dados que acompa-
nham este livro foram criados com a versão 97. Assim, poderão ser manipula-
dos, sem problemas, pelos programas da série 97 e da série 2000.
O botão Voltar dá liberdade ao operador para revisitar uma etapa já cum-
prida e modificar as escolhas que fez: incluir mais um campo, modificar a lógica
do filtro e até indicar outro arquivo MDB.
325
F I G U R A 3 4 . 2 O passo 2 do assistente: escolha da tabela de
dados

Agora, vamos pôr a mão na massa. Primeiro, a construção do formulário.


No ambiente de programação do VBA, comece desenhando um formulário com
os quatro botões inferiores. Os nomes desses botões são: cmdAjuda, cmdVoltar,
cmdAvançar e cmdCancelar. Acima deles, coloque a linha divisória horizontal.
Essa linha é, na verdade, uma caixa de imagem (controle Image). Para ter a apa-
rência de um sulco escavado no formulário, essa caixa precisa ter a seguinte pro-
priedade: SpecialEffect=2.
Acima da linha divisória, coloque a primeira moldura e chame-a de fra1.
Em seguida, desenhe fra2, fra3 etc. Para que a moldura não apareça, é necessá-
rio ajustar duas de suas propriedades: SpecialEffect=0 e Caption="" (texto va-
zio). Aqui você vai precisar de alguns truques. É fácil notar que não há espaço
nem jeito para trabalhar com um frame ocupando o mesmo espaço do outro.
Além disso, sempre vai existir o risco de, em vez de criar um frame independen-
te, você o colocar dentro de outro.
Então, invente um espaço extra: aumente a altura do formulário até ficar,
mais ou menos, duas vezes a altura do assistente. Depois, clique num dos botões
da linha inferior do assistente e acione, no menu, a opção Exibir/Ordem de Ta-
bulação. Observe que só estão listados, nessa janela, os botões do painel de co-
mando do assistente e as molduras que você já desenhou. Não aparece nenhum
dos objetos desenhados dentro das molduras. Agora, uma experiência diferente.
Clique numa moldura, deixe-a selecionada e acione outra vez o comando Exi-
bir/Ordem de Tabulação. O que aparece ? Somente os controles que estão den-
tro do frame selecionado.
Essa característica nos dá uma pista interessante. Em condições normais,
quando você torna uma moldura invisível, todos os objetos dentro dela assu-
mem o mesmo estado. Quando você a exibe, os objetos reaparecem – a não
ser, é claro, que você os programe para ficarem ocultos. Na página 1 do Assis-
tente de Banco de Dados, a etiqueta (label) labArquivoMDB, por exemplo,
326
pertence ao frame fra1 e fica invisível até quando o usuário indica um arquivo
de banco de dados.
Muito bem. Mas voltemos ao formulário com a altura ampliada. O espaço
adicional, na parte inferior de frmAssistente, vai servir para criar novas ou abri-
gar molduras antigas para serem editadas. Para fazer uma moldura antiga descer
para essa área de trabalho, faça o seguinte. Admita que todas as molduras estão
superpostas na parte superior, onde deverão ficar. Você precisa editar fra2, e ela
não é a que se encontra visível.
Desenhe um controle qualquer – por exemplo, um botão de comando –
mais ou menos na posição em que vai ficar a borda superior da moldura. Veja,
na caixa Propriedades, o valor da linha Top para esse botão. Anote-o e apague o
botão (tecla Del com o objeto selecionado).
Agora, clique num dos botões da linha inferior e acione a tecla Tab algu-
mas vezes até selecionar o frame desejado (verifique qual objeto está seleciona-
do na linha Name da caixa Propriedades, do ambiente VBA). Volte à caixa de
propriedades e digite, para fra2, o valor Top do botão apagado. A moldura des-
ce e você pode trabalhar com ela mais à vontade. Concluída a edição, devolva a
moldura para o lugar, recuperando o valor antigo de sua propriedade Top. No
Assistente, todas as molduras têm o mesmo tamanho e posição: ou seja, as mes-
mas propriedades Width, Height, Left e Top – comprimento, altura e coordena-
das esquerda e superior.

F I G U R A 3 4 . 3 Aumentar o formulário: um truque para trabalhar


com várias páginas do assistente

A lógica do Assistente
Como já foi dito anteriormente neste capítulo, a maior dificuldade que se pode
encontrar ao fazer um assistente desse tipo está em combinar as exigências da in- 327
terface com a programação. A seguir, devo destacar alguns pontos-chave desse
aspecto que estão presentes no Assistente de Bancos de Dados.
O primeiro item a ressaltar é a manutenção da ordem das tarefas. Sem que
a etapa atual esteja satisfatoriamente cumprida, o usuário não pode avançar
para a seguinte. Como garantir isso? O controle é feito a partir do evento Click
do botão Avançar. Para isso, usamos a variável m_iFrameAtual, de alcance geral
no formulário, uma função chamada Mover, que faz a troca de página, e a fun-
ção blnPodeAvançar, que verifica a possibilidade de prosseguir para o próximo
passo. A variável m_iFrameAtual contém, em cada momento, o número da mol-
dura ativa. Se m_iFrameAtual é menor que 6 – número da última etapa –, sem-
pre é possível avançar. Possível, em termos.
A função blnPodeAvançar verifica a viabilidade do avanço para cada fra-
me. Se ela dá o sinal verde, então, a página ativa passa a ser a seguinte e chama-se
a função Mover, que esconde todas as molduras, menos a atual. Quando se atin-
ge o último passo, 6, o botão Avançar muda de legenda: transforma-se em Con-
cluir. Agora, se o usuário clicar nesse botão Avançar-Concluir, chama a
sub-rotina ConcluirTudo, que cuida de ler no banco de dados as informações in-
dicadas e passá-las a uma tabela no Word ou a uma folha de cálculo do Excel.
Parte do que está descrito aqui encontra-se na sub-rotina Click do botão Avan-
çar-Concluir:

Private Sub cmdAvançar_Click()


‘ Mostra a próxima página do assistente
If m_iFrameAtual = 6 Then ConcluirTudo

If m_iFrameAtual < 6 Then


If blnPodeAvançar(m_iFrameAtual) Then
m_iFrameAtual = m_iFrameAtual + 1
Mover m_iFrameAtual
End If
End If

If m_iFrameAtual = 6 Then cmdAvançar.Caption = “Concluir>”


End Sub

Como os botões Avançar e Voltar estão ligados a todas as fases de atuação


do Assistente, o código a eles associado forma um eixo de referência. No evento
Click do botão Voltar, tudo é mais simples:

Private Sub cmdVoltar_Click()


‘ Controla o retorno à página anterior

If m_iFrameAtual > 1 Then


m_iFrameAtual = m_iFrameAtual - 1
328 Mover m_iFrameAtual
cmdAvançar.Caption = “Avançar>”
End If

End Sub

Não existem impedimentos para o retorno a uma etapa anterior. Troca-se


o valor de m_iFrameAtual e põe-se a página anterior em primeiro plano. Apenas
um cuidado: ao sair da página 6 para a 5, é preciso dar ao botão Concluir a eti-
queta original: Avançar.
Vamos, agora, acompanhar o código do Assistente de Bancos de Dados,
página a página.

Página 1
Na página 1, ao clicar no botão Procurar Banco de Dados (cmdProcurar), o
usuário traz à tela a caixa de diálogo Abrir, do Word, ajustada para mostrar ar-
quivos do tipo MDB. Indicado o arquivo, o Assistente abre o banco de dados
(rotina AbrirBancoDeDados), verifica as tabelas nele existentes e as coloca
numa caixa de lista da página 2. Como essa etapa já está cumprida, o programa
chama o evento cmdAvançar_Click, a fim de passar à tarefa seguinte.

Private Sub cmdProcurar_Click()


‘ Captura nome do arquivo MDB
Dim dlg As Dialog
Dim sDir As String

Set dlg = Dialogs(wdDialogFileOpen)


dlg.Name = “*.mdb”
If dlg.Display = -1 Then
m_sArqNomeCurto = dlg.Name
‘ elimina aspas, se houver
If Right(m_sArqNomeCurto, 1) = Chr(34) Then
m_sArqNomeCurto = Mid(m_sArqNomeCurto, 2, _
Len(m_sArqNomeCurto) - 2)
End If
‘ Elimina a barra (\), se houver
sDir = CurDir
If Right$(sDir, 1) = “\” Then _
sDir = Left$(sDir, Len(sDir) - 1)
m_sArqNomeLongo = sDir & “\” & m_sArqNomeCurto
labArquivoMDB.Visible = True
labArquivoMDB = “ ” & m_sArqNomeLongo
labTitulolstTabelas = “Tabelas em ” & m_sArqNomeCurto
AbrirBancoDeDados
329
‘ Passa para a página 2
cmdAvançar_Click
End If
End Sub

No código associado ao clique no botão Procurar, dois pontos devem ser


destacados. O primeiro é que a caixa Abrir, do Word, é apresentada com o mé-
todo Display. Esse método exibe a caixa de diálogo – qualquer uma – mas não
permite executar nenhuma ação. Em outras palavras, o arquivo selecionado na
caixa Abrir não vai ser aberto. Portanto, o método Display transforma a caixa de
diálogo num instrumento de escolha e configuração de itens, e não de ação. Para
realmente levar a termo a função da caixa de diálogo, use o método Show.

F I G U R A 3 4 . 4 Caixa Abrir (Word 2000): para exibir somente


arquivos do tipo MDB

O outro ponto de destaque é a maneira de capturar o diretório no qual se


encontra o arquivo indicado pelo usuário. A propriedade Name da caixa de diá-
logo fornece apenas o nome do arquivo, sem o diretório, e não existe outra pro-
priedade que forneça o caminho completo do arquivo. A saída existe, se você
prestar atenção para um detalhe. Ao navegar na caixa de diálogo Abrir para en-
contrar o arquivo desejado, o usuário está definindo quem é o diretório corren-
te para o Word. Esse diretório é dado pela função CurDir, do Visual Basic. Há
também outros caminhos para ele, que é usar uma das expressões:

Options.DefaultFilePath(wdDocumentsPath)
Options.DefaultFilePath(wdCurrentFolderPath)

Essa mesma expressão (Options.DefaultFilePath) retorna diferentes diretó-


rios. Para isso, basta trocar as constantes intrínsecas do Word wdDocumentsPath e
330 wdCurrentFolderPath. Por exemplo, wdUserTemplatesPath fornece o diretório onde
são armazenados os modelos, inclusive o Normal; wdProgramPath diz onde está o
arquivo executável do Word; e, por fim, wdProofingToolsPath indica a pasta que
armazena as ferramentas de correção ortográfica.
Na sub-rotina AbrirBancoDeDados, também convocada à ação a partir do
clique no botão Procurar, usa-se a instrução For Each/Next para percorrer toda
a coleção de TableDefs e listar todas as tabelas existentes no banco de dados es-
colhido. Observe, no entanto, que a coleção de tabelas do banco de dados inclui
uma série de objetos internos do Access, todos com nomes iniciados com MSys,
como MSysModules e MSysObjects. São as chamadas tabelas de sistema. Para
que elas não apareçam na caixa de listagem lstTabelas, exclui-se todo objeto
cujo nome comece com a expressão “MSys”.

Dim td As TableDef
Set m_db = opendatabase(m_sArqNomeLongo)
lstTabelas.Clear
‘ Exclui as tabelas de sistema
For Each td In m_db.TableDefs
If Left(td.Name, 4) <> “MSys” Then
lstTabelas.AddItem td.Name
End If
Next td

Em certo sentido, programar é prestar atenção a detalhes. No código


acima, antes de listar as tabelas, limpa-se o conteúdo da caixa de listagem
lstTabelas com o método Clear. Por quê? Isso evita que o usuário, depois de
avançar nas operações, volte ao passo 1 e escolha um banco de dados diferente
do primeiro. Ao fazer isso, novas tabelas vão ser listadas na caixa lstTabelas.
Sem limpar o conteúdo da caixa, novas e velhas tabelas seriam listadas,
gerando confusão e erro. Esse cuidado de fazer uma limpeza prévia de caixas
de listagem e caixas de combinação também é adotado em outros momentos
do programa.

Página 2
A página 2 exibe a lista das tabelas existentes no banco de dados escolhidos pelo
usuário. Quando o usuário escolhe um item na lista, entra em ação a sub-rotina
LerCamposNaTabela, que se encarrega de preencher a caixa lstCamposDispo-
níveis (passo 3) com os nomes dos campos. Aqui, a validação da passagem à eta-
pa seguinte é muito simples. Basta verificar se uma tabela foi escolhida na lista.
Ou seja, se o valor de lstTabelas é diferente de uma string vazia:

If lstTabelas.Value <> “” Then


blnPodeAvançar = True

331
O trecho de código acima foi retirado da função blnPodeAvançar – que,
como vimos, é o centro de validação para a passagem de uma página à próxima.

Página 3
Na página 3, a ação se concentra nos botões de comando inseridos na moldura.
Quatro deles – cmdVaiUm, cmdVaoTodos, cmdVoltaUm e cmdVoltamTodos –
ocupam-se da tarefa de movimentar itens da lista lstCamposDisponíveis para a
lista lstCamposSelecionados. Mover um campo da esquerda para a direita
(cmdVaiUm) significa adicioná-lo à caixa de destino e removê-lo da caixa de
origem. A operação inversa, com o botão cmdVoltaUm, obedece à mesma lógi-
ca. Naturalmente, a transferência só ocorre se houver um campo selecionado.

F I G U R A 3 4 . 5 Escolha dos campos que o usuário deseja


importar

Para auxiliar a operação dos botões de transferência total (cmdVaoTodos e


cmdVoltamTodos), a sub-rotina LerCamposNaTabela armazena os nomes dos
campos disponíveis na matriz TheFields( ), válida para todos os procedimentos
do formulário. Portanto, a ação de mover todos os campos, para a direita ou
para a esquerda, resume-se em apagar a caixa de origem e preencher a caixa de
destino com os itens guardados na matriz.
No troca-troca de campos entre as caixas Campos Disponíveis e Campos
Selecionados, falta apenas destacar um aspecto. Trata-se do elo deste passo, 3,
com o seguinte. Todo item adicionado à lista Campos Selecionados é também
adicionado às seis caixas de combinação Campo1, Campo2 até Campo6, da
moldura fra4. Do mesmo modo, todo item subtraído da lista deve também ser
subtraído das caixas de combinação. Isso faz a ligação entre os passos 3 e 4. Os
campos selecionados são também transferidos nessa rotina para as caixas de
combinação da página 5.
332
Os dois outros botões da página 3 chamam-se cmdCampoSobe e cmdCam-
poDesce. Esses controles permitem redefinir a ordem dos campos na lista
lstCamposSelecionados. A ordem ali definida será aquela com que os campos
serão apresentados no documento final – ou seja, a tabela do Word ou a planilha
do Excel.
Uma dica de design: as setas para cima e para baixo nos botões cmdCam-
poSobe e cmdCampoDesce correspondem, respectivamente, aos caracteres ñ e
ò (N minúsculo com til e O minúsculo com acento grave), na fonte Wingdings,
padrão do Windows, desde a versão 3.1. Pontas de seta para a esquerda/direita e
cima/baixo também podem ser obtidas com os caracteres 3, 4, 5 e 6 da fonte
Marlett, que também é padrão no Windows 95, 98, NT e 2000. Outra alternati-
va para pontas de seta – nesse caso ainda mais vistosas – é oferecido pela fonte
Wingdings 3, com os caracteres P, Q, T e U, todos minúsculos. Resta apenas sa-
ber se essa fonte tem a mesma universalidade das outras duas.
Fazer um campo subir uma posição na lista significa apagá-lo do lugar
onde está e inseri-lo, de novo, uma linha acima. É isso que faz o procedimento
associado ao evento Click do botão cmdCampoSobe:

Private Sub cmdCampoSobe_Click()


Dim n As Integer
Dim sTxt As String

With lstCamposSelecionados
n = .ListIndex

If n > 0 Then
sTxt = .Value
.RemoveItem n
.AddItem sTxt, n - 1
.ListIndex = n - 1
End If
End With
End Sub

Observe, no código, o uso da instrução With/End With, evitando a repeti-


ção da referência ao objeto lstCamposSelecionados. Dentro dos limites dessa
instrução, tudo que aparece precedido por um ponto corresponde a uma pro-
priedade de lstCamposSelecionados ou a um método aplicado a esse objeto. A
rotina que faz o campo descer é idêntica. Por fim, o requisito básico para a pas-
sagem da página 3 para a 4 é que a caixa Campos Selecionados não esteja vazia.
Ou, em código:

lstCamposSelecionados.ListCount > 0

333
Página 4
A etapa número 4 é, talvez, a mais complexa do projeto. Ela oferece ao usuário
uma interface na qual ele pode indicar critérios para a seleção de um subconjun-
to dos registros armazenados no banco de dados. Em linguagem mais técnica,
nessa etapa o usuário tem a opção de criar uma consulta para trazer do banco de
dados somente os resultados dessa consulta. Ele pode querer listar, por exem-
plo, somente os clientes das cidades de São Paulo e do Rio de Janeiro.
O uso dos controles nessa etapa é idêntico ao empregado na manipulação
de dados nas malas diretas do Word. Aliás, o jeitão dessa página foi copiado de
lá. O objetivo é criar linhas lógicas como:

E/OU Campo: Comparação: Comparar Com:


Cidade Igual a São Paulo
OU Cidade Igual a Rio de Janeiro

Atenção para as conjunções E/Ou. “E” indica uma condição que pode ser
aplicada simultaneamente ao mesmo registro: “o cliente é do sexo masculino E
mora em Salvador”. Neste exemplo, o E faz sentido. No entanto, “o cliente mora
no Rio E mora em São Paulo” produz um resultado vazio, porque certamente a fi-
cha do cliente só apresenta um local de residência. Portanto, para reunir no resul-
tado da consulta os clientes do Rio e de São Paulo, use OU. Nos bastidores, o
Assistente transformará as duas linhas acima numa declaração SQL do tipo:

SELECT * FROM <BancoDeDados> WHERE Cidade=’São Paulo’ OR Cidade=’Rio de Janeiro’

F I G U R A 3 4 . 6 Passo 4: aqui, o usuário dá indicações para a


filtragem dos dados

334
Se o usuário quiser importar todos os registros do banco de dados, basta
clicar no botão Avançar, sem preencher nenhum campo. Se preencher algum e
quiser anular o preenchimento, basta clicar no botão Limpar. No início, apenas
o primeiro campo da tabela se mostra ativado. À medida que o usuário os vai
preenchendo, os campos seguintes também se tornam disponíveis.
O sinal verde para a página seguinte é dado após duas seqüências de testes.
A primeira testa, digamos assim, aspectos burocráticos. Ou seja, se o preenchi-
mento dos dados foi feito corretamente. Então, o teste é positivo se: 1) nenhum
dos campos foi preenchido; ou 2 ) pelo menos a primeira linha do quadro está
completamente preenchida: Campo, Comparação e Comparar Com.
O segundo teste é mais complicado. Ele verifica se o preenchimento faz
sentido do ponto de vista do banco de dados. Para isso, é convocada a função
TestaRecordset, que retorna o número de registros existentes no conjunto de
dados formado pelas indicações do usuário. Se esse número for zero, não adi-
anta prosseguir. O programa avisa ao usuário e não avança para o passo se-
guinte.

F I G U R A 3 4 . 7 Aviso ao usuário: não há registros

Caso o teste seja positivo, o usuário passará à etapa 5 e lá verá o número de


registros encontrados pela pesquisa. A complexidade da etapa 4 reside no fato
de que as indicações feitas são a base para a montagem da cláusula WHERE – a
parte das declarações SQL que indica o critério de seleção dos registros.

Página 5
O preenchimento dos três campos da página 5 é opcional. As caixas cboOr-
dem1, cboOrdem2 e cboOrdem3 permitem classificar os registros segundo os
campos nelas escolhidos. O usuário pode escolher de zero a três campos. O bo-
tão Limpar anula escolhas feitas anteriormente.
O avanço a partir da página 5 é completamente livre, porque nessa etapa o
usuário não define nenhum item obrigatório.

335
F I G U R A 3 4 . 8 Passo 5: escolha de campos para classificação
dos registros importados

Página 6
Chegamos, enfim, à última página. Aqui, o usuário precisa apenas indicar se o
documento de saída para os dados será uma tabela do Word (o padrão) ou uma
planilha do Excel e clicar no botão Concluir, também conhecido como Avançar.

F I G U R A 3 4 . 9 A página final do Assistente: escolha do


documento de saída

Aqui, as coisas começam, realmente, a acontecer. O clique no botão Con-


cluir põe em ação a rotina ConcluirTudo. Esta importante senhora, sem exage-
ro, é a alma do Assistente. Vejamos o que ela faz:
1. Chama a função MontaSQL. Esta lê os campos selecionados no passo 3
e, por sua vez, chama a função MontaWhere. Esta última constrói a
336 cláusula WHERE e a fornece a MontaSQL. No final, MontaSQL reúne
tudo e agrega a cláusula ORDER BY, que define a classificação dos re-
gistros. Desse emaranhado de operações, resulta que MontaSQL forne-
ce a ConcluirTudo uma declaração SQL completa. Exemplo:
SELECT NomeCliente, Empresa, Endereço, CEP, Cidade, Estado
FROM <BancoDeDados>
WHERE Cidade=’São Paulo’ OR Cidade=’Rio de Janeiro’
ORDER BY NomeCliente, Empresa

Com o comando SQL em mãos, a rotina ConcluirTudo abre o banco de


dados e retira de lá o que está indicado. Conforme o documento de saí-
da escolhido pelo usuário, os registros resultantes são direcionados para
o Word ou para o Excel.

Saída para o Word


No caso padrão (Word), ConcluirTudo lança mão de um conhecido recurso do
processador de texto: converter texto em tabela. Para isso, ela lê o valor de cada
campo no registro do banco de dados e acumula tudo numa string, colocando
sempre, entre um campo e outro, um espaço de tabulação (constante intrínseca
vbTab). No final da linha, coloca-se um sinal de parágrafo (vbCrLf).
Cada uma dessas linhas é escrita num documento Word, antes vazio. No fi-
nal, ConcluirTudo fecha o banco de dados e passa à formatação da tabela:
ActiveDocument.Select
Selection.ConvertToTable

O Word consome algum tempo na operação, mas afinal exibe uma tabela
formatada, com os nomes dos campos no cabeçalho das colunas. Tarefa cumpri-
da para o Assistente.

F I G U R A 3 4 . 1 0 Tabela final, transferida do banco de dados


Northwind.mdb para o Word 337
Durante a criação do documento, observe a frenética atividade do Word
indicada na barra de status. As mensagens na barra de status são produzidas por
comandos como:

StatusBar = “Registro ” & nLinha & “...”

Saída para o Excel


Falta-nos ver o que acontece quando o usuário define que o documento final é
uma planilha Excel. Nesse caso, depois de verificar se a sentença SQL produz al-
gum resultado, a poderosa rotina ConcluirTudo passa a bola para o procedi-
mento ExportarParaXL. Este recebe a declaração SQL e entra em atividade.
Ela abre o banco de dados, seleciona os registros segundo os critérios defi-
nidos na declaração e salva-os num arquivo TXT do tipo separado por vírgula,
chamado Xlimport.txt. Trata-se de um arquivo com o seguinte formato:

“Cliente”,"Empresa","Endereço","CEP","Cidade","Estado"
“Antonio Gomes”,"Sol e Mar","Rua da Horta, 12","21213-009", “Santos”,"SP"
“Maria Alves”,"Alves & Cia.","Rua Nova, 17","01213-000", “Campos”,"RJ"

Fechado o banco de dados, ExportarParaXL abre o objeto Excel.Applicati-


on e comanda que ele importe o arquivo TXT e o salve no formato de planilha,
com o nome Xlimport.xls. Mais uma vez, tarefa cumprida.

F I G U R A 3 4 . 1 1 Tabela final: do Northwind.mdb para o Excel

Note que foram usadas estratégias diferentes para tratar com o Word e o
Excel. A solução com a planilha é, sensivelmente, mais rápida. Boa parte do
tempo consumido na geração da tabela no Word destina-se a escrever os regis-
338 tros linha a linha no documento e, depois, transformá-lo em tabela. No caso do
Excel, a gravação do arquivo texto é bastante rápida e a importação, idem. Além
disso, a tabela não precisa ser construída.

Detalhes finais
Basicamente, isso é tudo que precisa ser dito a respeito do Assistente de Bancos
de Dados. No entanto, sempre sobram alguns detalhes que demandam esclareci-
mento. Ao listar os campos de dados na rotina LerCamposNaTabela, deixamos
de fora, de propósito, os campos do tipo Binário Longo (Objeto OLE) e Memo-
rando. O primeiro refere-se a imagens, sons e demais itens de multimídia. Os
outros, aos conhecidos campos de memorando, que nos bancos de dados do
Access 2000 suportam textos de até 1,2 gigabytes.
Mesmo com esse cuidado de afastar potenciais fontes de erro, o Assistente
de Bancos de Dados pode gerar importações incorretas até em campos de texto
comuns. Isso ocorre quando o conteúdo do campo contém um parágrafo – ca-
ractere ASCII 13. Veja um exemplo no banco de dados Northwind, do Access,
no campo Endereço (Figura 34.12).

F I G U R A 3 4 . 1 2 O campo Endereço, que contém quebra de


linha, pode causar erro no Assistente

Outro detalhe refere-se às matrizes de controles. Uma das diferenças entre


o produto Visual Basic – o pacote autônomo da linguagem – e o VBA – embuti-
do em aplicativos – são as matrizes de controles. No VB, pode-se ter, por exem-
plo, cinco caixas de texto, todas com o mesmo nome e índice diferente: txtCam-
po (1), txtCampo(2) etc. Esse recurso facilita bastante a construção do código,
quando, por exemplo, se deseja apagar o conteúdo de todas as caixas de texto:
For n = 1 to 5
txtCampo(n) = “”
Next n
339
No VBA isso não é possível. Pode-se, no entanto, inventar um que-
bra-galho. Retomando o exemplo, você pode nomear as caixas de texto com no-
mes seqüenciais: txtCampo1, txtCampo2, e assim por diante. Numa rotina lo-
calizada dentro de um módulo de formulário, o código VB, acima, pode assumir
o seguinte perfil em VBA:

For n = 1 to 5
Controls(“txtCampo” & n).Value = “”
Next n

O truque consiste em recorrer à coleção Controls, do form, que reúne to-


dos os controles existentes no form. Os objetos desejados – no caso, as caixas de
texto – são indicados pela concatenação da string inicial do nome, “txtCampo”,
com o número final. Essa pequena malandragem é usada em vários procedimen-
tos do Assistente do Banco de Dados. Quem não tem cão caça com gato. E, de
repente, o bichano se revela um ótimo perdigueiro...
Outro ponto de destaque no código está na função FiltraApostrofo. Essa
função, válida somente para strings, recebe o valor de um campo de dados e ve-
rifica se ele contém um apóstrofo – o sinal de aspa única. Em caso positivo, tro-
ca-o por dois apóstrofos e devolve a string recebida com essa modificação. Para
quê? Quando se montam comandos SQL, é comum encontrar trechos do tipo:

strSQL = “... WHERE Cidade=’São Paulo’ ... ”

As aspas únicas são usadas para delimitar o valor fornecido (São Paulo) .
Na atribuição da variável strSQL, servem também para não criar confusão com
as aspas comuns, delimitadoras da string total. Mas as aspas únicas produzem
um erro quando a string que elas abraçam já contém um apóstrofo. É o caso de
expressões em inglês como Baby’s Paradise e Alfredo’s. Nesse caso, o valor do
campo analisado pelo motor de banco de dados é algo assim:

‘Alfredo’s’

O erro se configura porque o VBA não consegue analisar onde a string aca-
ba. Para eliminar a ambigüidade, troca-se o sinal interno por dois:

‘Alfredo’’s’

Para o analisador de SQL, os dois sinais juntos valem por um. Dá para en-
tender, agora, o significado da linha a seguir:

varValor = “’” & FiltraApostrofo(varValor) & “’”

340
Trata-se de uma linha que modifica o valor de um campo de texto antes de in-
tegrá-lo a uma declaração SQL. Observe que a variável original varValor recebe um
apóstrofo inicial e outro final e, ao mesmo tempo, é submetida à função FiltraApos-
trofo para corrigir a eventual existência de um ou mais apóstrofos internos.
Observe, também, o trabalho da função GetRecordsetTemp. Ela recebe
uma consulta (QueryDef) e verifica se existem registros que correspondam a
essa consulta. Em outras palavras, se o número de registros é maior que zero. Se
a pesquisa proposta pelo usuário não trouxer de volta nenhum registro, então
encerra-se todo o processamento e emite-se um aviso: “não há registros corres-
pondentes ao filtro indicado”.

Para ir mais além


Você pode fazer uma série de mudanças no Assistente de Bancos de Dados para
melhorá-lo e torná-lo mais completo, ou apenas como exercício de programa-
ção. Eis algumas delas:
1. Em lugar de salvar um arquivo texto com os dados e fazer o Excel abrir
esse arquivo, tente escrever o conteúdo de cada linha do registro numa
linha da planilha. Com certeza, esse processo será mais lento que o mos-
trado aqui, mas vale como exercício. Aliás, isso elimina o problema das
quebras de linha, citado acima, já que o conteúdo inteiro de um campo
será escrito numa célula específica da planilha.
2. Nos campos de texto, elimine o problema da quebra de linha. antes de
escrever no documento Word ou no arquivo-texto para o Excel, verifi-
que se o conteúdo do campo contém o caractere Chr(13) e troque-o por
um espaço ou uma barra (/). Para implementar isso, você pode recorrer
a uma função semelhante à já discutida FiltraApostrofo.
3. Pense na hipótese de incluir, no passo final do Assistente, uma caixa de
texto na qual o usuário possa digitar um título para a tabela que será im-
portada do banco de dados. Esse título deverá ser inserido como um ca-
beçalho no documento Word ou na planilha Excel.
4. Inspirado nesse assistente, tente elaborar outros que resolvam pro-
blemas diversos.
5. Muitos bancos de dados têm consultas do tipo seleção. Em vez de traba-
lhar com tabelas, você pode trabalhar com essas consultas. A vantagem é
que elas dão mais flexibilidade e podem produzir resultados com dados
originários de mais de uma tabela.
6. Em certos casos, o usuário trabalha apenas com um banco de dados.
Nesse caso, você pode simplificar as coisas, fazendo um assistente que
vá direto a esse banco de dados. Com isso, ele poderia começar no passo
2 ou no 3. 341
7. Se o banco de dados a ser aberto exige senha de acesso, modifique a roti-
na AbrirBancoDeDados para acomodar essa situação. Talvez seja neces-
sário incluir no assistente um novo passo, que peça ao usuário para digi-
tar a senha.
8. Se você usa mais o Excel do que o Word, considere a possibilidade de
transpor este projeto para o Excel. A diferença básica é que, aqui, o
Word está “em casa” e o Excel é o objeto externo. Nessa proposta acon-
tecerá o inverso. Afora isso, a maior parte do código não precisará so-
frer alteração.

Atenção para os detalhes!


Programar, em grande parte, equivale a prestar atenção aos detalhes.
Uma prova disso você pode encontrar no projeto do Assistente de
Banco de Dados. Quando você abre, via VBA, uma caixa de diálogo do
Word para que o usuário escolha um arquivo ou diretório, o retorno
vem entre aspas se a pasta ou arquivo contém espaço (por exemplo,
Meus Documentos). Se você constrói seu programa, usando apenas
exemplos que não contêm o tal espaço, corre o risco de enfrentar erros
depois. Por isso, antes de usar uma string retornada de caixas de
diálogo, teste para ver se ela não contém aspas. Veja um exemplo no
procedimento cmdProcurar_Click, de frmAssistente.

O macete dos colchetes


Cuidado ao trabalhar com variáveis que representam nomes de cam-
pos e nomes de tabelas no banco de dados. Envolva-os sempre com
colchetes para evitar erros, aparentemente, inesperados. Esses erros
sempre ocorrem quando o nome do campo ou o nome da tabela
contém espaço. Admita, por exemplo, uma tabela chamada Turma 1.
Para montar com ela uma sentença SQL que selecione todos os seus
registros, escreva:

strSQL = “SELECT * FROM ” & “[” & strTabela & “]”

Disso vai resultar uma sentença correta:

SELECT * FROM [Turma 1]

Sem os colchetes, a expressão Turma 1, solta, provoca um erro. O


mesmíssimo princípio vale para os nomes de campos:

SELECT [Nome do Aluno], [Código] FROM [Turma C]


342
35
Instale e
desinstale seus
programas

Monte um instalador de aplicações


num documento do Word

Ficha do projeto

Projeto:

Instalador de Aplicações

O que faz:

Instala a aplicação Gerador de Recibos no Word.


Com adaptações, pode ser usado para instalar outros
programas no ambiente do processador de texto.

Arquivos e requisitos do projeto:

Modelo Instalgr.dot, contendo:


Texto explicativo para a instalação do Gerador de
Recibos.
Módulo modInstala, com a lógica de instalação do
aplicativo.
Módulo modReciboGeral, que deve ser copiado para o
modelo Normal.
Modelo Recibog.dot, contendo o formulário frmReciboGeral
Arquivo Rc_Ajuda.txt, documento de ajuda.
Arquivo Rclients.lst, texto com a lista de clientes.
Arquivo Rtipserv.lst, texto com os tipos e descrições de serviços prestados.
Arquivo Rpessoas.lst, texto com a lista de pessoas que assinam os recibos.
Arquivo Recibog.ini, que armazenas as variáveis Empresa e Cidade.
Biblioteca Extens32.dll (© 1996 Antonio Augusto Ferreira), programa que fornece
valores monetários por extenso.

Conhecimento técnico:

Abertura e gravação de arquivos texto.


Manipulação de arquivos INI.
Acesso a bibliotecas da API do Windows.
Cópia de módulos de um modelo do Word para outro.
Criação de um algoritmo para numeração seqüencial de arquivos.
Automatização do preenchimento de documentos com o uso do objeto
Selection.Find.

Nível de programação:

Avançado

Você acabou de desenvolver seu projeto, em casa ou na empresa, e precisa dis-


tribuí-lo aos usuários. Em geral, as pessoas não têm a menor idéia de como desli-
gar certas automações inconvenientes do Word. Então você não vai esperar que
elas saibam como fazer para instalar seu aplicativo, colando subs e funções no
ambiente do VBA ou importando módulos nos formatos BAS e FRM.
Está claro que é preciso facilitar a vida deles. Ainda mais se o projeto que
você está oferecendo é algo que envolve módulos, arquivos de modelos, arquivos
texto e outros, sendo que cada um deve ser instalado numa localização específica.
É mais do que justo, portanto, que você crie um mecanismo de instalação para o
seu programa. A boa notícia que tenho para lhe dar é que esse recurso pode ser
construído com o próprio Word. Duvida? Este capítulo vai fazê-lo acreditar.
Para isso, vamos trabalhar com um exemplo concreto. Que tal construir
um utilitário de instalação para o Gerador de Recibos, tema do Capítulo 31? A
escolha recai sobre esse projeto por uma razão bem simples: ele trabalha com
um número de arquivos relativamente grande – oito – e envolve a criação de
uma barra de ferramentas e de um módulo VBA no modelo Normal do usuário.
O primeiro passo para a construção do Instalador de Aplicações é criar um
modelo novo, chamado Instalgr.dot. No documento desse modelo (veja a Figu-
ra 35.1), você deve escrever as orientações para ajudar o usuário a instalar o
programa. Com certeza, você só vai conseguir dar uma forma final a esse texto
depois de concluir todo o projeto de instalação. Passemos, então, para a parte
344 interna de Instalgr.dot.
F I G U R A 3 5 . 1 O documento de instalação: texto informativo e
botões de comando
345
Antes de escrever qualquer linha de código, vamos determinar o que preci-
samos fazer. Para instalar a aplicação Gerador de Recibos, é necessário:
n copiar os diferentes arquivos para os locais adequados;

n criar no modelo Normal uma rotina sub que funcione como dispara-
dora do aplicativo;
n criar um botão numa barra de ferramentas que ative essa rotina sub.
Concretamente, precisamos copiar sete arquivos, para diferentes locais no
disco do usuário, conforme mostrado na tabela abaixo.

ARQUIVO COPIAR PARA

Recibog.dot c:\solucoes\modelos

Recibog.ini Idem

Rc_ajuda.txt Idem

Rclients.lst Idem

Rpessoas.lst Idem

Rtipserv.lst Idem

Extens32.dll Diretório de sistema do Windows

Para iniciar a construção do utilitário de instalação, vamos criar dois


módulos, dentro do modelo Instalgr.dot: modInstala e modReciboGeral. O
primeiro conterá o código de instalação propriamente dito. Quer dizer, toda a
lógica para copiar arquivos e estabelecer as necessárias configurações no Word.
O outro contém código que não entra na instalação: lá está, apenas, para ser
transferido para o ambiente VBA, da máquina de destino.
A rotina principal em modInstala é a sub InstalaAplicativos. Essa rotina vai
funcionar como uma centralizadora dos trabalhos, delegando tarefas específicas
a outros procedimentos. A primeira tarefa é copiar os arquivos para os respecti-
vos diretórios. Para executá-la, convoca-se a rotina CopiaArquivos.
A estrutura do instalador parte do pressuposto de que todos os arquivos da
aplicação estão reunidos na mesma pasta. Assim, a sub CopiaArquivos trabalha
com duas matrizes. Numa, strArq, estão os nomes dos arquivos do diretório de
instalação. Na outra, strDest, estão os diretórios para onde os arquivos serão co-
piados. O trecho básico do processo de cópia é o seguinte:
m_strDirAtual = ActiveDocument.AttachedTemplate.Path

For n = 1 To iNumArqs - 1
strOrigem = m_strDirAtual & “\” & strArq(n)
strDestino = strDest(n) & “\” & strArq(n)
346 ‘ se não existe, copia
If Not ArquivoExiste(strDestino) Then
FileCopy strOrigem, strDestino
Else
‘ programa: copia em qualquer caso
If n = 1 Then
Kill strDestino
FileCopy strOrigem, strDestino
End If
End If
Next n

Para saber em qual diretório estão os arquivos (o usuário pode disparar o


utilitário a partir de qualquer ponto no disco), usa-se a propriedade Attached-
Template.Path, do documento ativo, que contém o instalador. O caminho com-
pleto do arquivo de origem é montado, combinando o nome desse diretório
com o nome do arquivo. Do mesmo modo, o caminho do arquivo de destino é
dado pela concatenação de um item da matriz que contém os diretórios com os
mesmos nomes de arquivos.
O próximo passo da rotina principal é chamar a sub DesinstalaAplicativos.
Não estranhe. O VBA não aceita a criação de dois formulários ou dois módulos
com o mesmo nome. Além disso, o Word também apontará erro se você tentar
criar duas barras de ferramentas homônimas. Para evitar isso, DesinstalaAplica-
tivos elimina do ambiente todos os vestígios de uma instalação anterior do Gera-
dor de Recibos. Como se trata de um procedimento independente, essa rotina
dá ao utilitário, também, o papel de desinstalador. Mas isso só pode acontecer
se ela for declarada como um código de abrangência pública. A mesma caracte-
rística vale para InstalaAplicativos.
Feita a desinstalação – se for o caso –, a rotina InstalaAplicativos, coorde-
nadora do processo, chama agora a sub CopiaMódulos. Esse procedimento vai
copiar formulários e módulos de programação VBA, contidos no modelo
Instalgr.dot, para o modelo Normal no Word do usuário. Na instalação do Ge-
rador de Recibos, só é preciso copiar um módulo, modReciboGeral. Não há for-
mulários, uma vez que toda a lógica do aplicativo encontra-se, internamente, no
modelo Recibog.dot. O módulo modReciboGeral tem apenas uma rotina, cha-
mada NovoRecibo, cujo papel é abrir um novo documento com base em Reci-
bog.dot, iniciando o aplicativo. O procedimento NovoRecibo deve ser de
abrangência pública, para poder ser chamado de fora do módulo:

Public Sub NovoRecibo()


Dim ArqModelo As String
ArqModelo = “c:\solucoes\modelos\recibog.dot”
Documents.Add Template:=ArqModelo
End Sub

347
A cópia de modReciboGeral para o Normal.dot do usuário é feita com o
método OrganizerCopy, que envolve o nome do modelo de origem, o modelo
ou documento de destino, o nome do objeto (módulo ou formulário) e a nature-
za do objeto. Módulo e formulário pertencem à mesma categoria, wdOrgani-
zerObjectProjectItems. Mas há outros objetos que também podem ser copiados
com esse mesmo recurso – as barras de comando, por exemplo, identificadas
pela constante wdOrganizerObjectCommandBars. O comando para copiar um
módulo, aqui identificado por strNomeMod1, é o seguinte:

Application.OrganizerCopy Source:= _
ActiveDocument.AttachedTemplate.FullName, _
Destination:=NormalTemplate.FullName, _
Name:=strNomeMod1, _
Object:=wdOrganizerObjectProjectItems

Até aqui, já copiamos os arquivos para os lugares devidos e instalamos no


VBA uma rotina para abrir o aplicativo. O que há mais para fazer? Agora, para
facilitar a vida do usuário, vamos criar uma barra de ferramentas chamada Reci-
bos e colocar nela um botão de comando que vai chamar a rotina NovoRecibo e,
portanto, executar o Gerador de Recibos. A adição dessa nova barra à coleção
de barras de comando do Word se faz com o seguinte código:

CustomizationContext = NormalTemplate
Set BarraFer = CommandBars _
.Add(Name:=strBarraFer, Position:=msoBarFloating)
With BarraFer
.Controls.Add Type:=msoControlButton
.Controls(1).Caption = strBarraFer
.Controls(1).FaceId = 139
CustomizationContext = NormalTemplate
.Controls(1).OnAction = “NovoRecibo”
.Left = 0.8 * System.HorizontalResolution
.Top = 0.25 * System.VerticalResolution
.Visible = True
End With

A propriedade CustomizationContext, na primeira linha do trecho aci-


ma, indica que a barra de ferramenta a ser criada (strBarraFer, que é igual a
“Recibos”) deverá ser salva no modelo Normal. Após a criação da barra, usa-se
outra vez o método Add para adicionar um botão de comando. Este recebe
como ícone (propriedade FaceID) o número 139, correspondente ao desenho
da Caixa de Texto, visível em Inserir/Caixa de Texto ou na barra de ferramen-
tas Desenho. Observe a propriedade OnAction do botão. O valor dela passa a
ser exatamente o nome da rotina sub que deve ser acionada com o clique no
348 botão de comando. Sempre que se cria uma barra de ferramentas, por defini-
ção ela está invisível. Por isso, é preciso ajustar, explicitamente, sua proprieda-
de Visible para True.
Agora podemos discutir, com mais domínio do terreno, a rotina
DesinstalaAplicativos. Ela executa duas operações. Ela varre o ambiente do
VBA, procurando por um módulo ou formulário que tenha um nome dado e,
caso o encontre, apaga-o, usando o método OrganizerDelete:

Application.OrganizerDelete “Normal.dot”, _
strNomeMod1, wdOrganizerObjectProjectItems

DesinstalaAplicativos, por sua vez, chama à ação a sub RemoveCommand-


Bar, que também lança mão do método OrganizeDelete. Nesse caso, seria possí-
vel usar, simplesmente, o método Delete, aplicado ao objeto. Assim:

cBar.Delete

No entanto, em experiências com o Word 2000, observei que ele apresen-


ta falhas com esse método. Embora não apresente nenhum erro, ele não apaga a
barra de ferramentas. E mais: estranhamente, deixa conviver duas barras com o
mesmo nome. Esse comportamento não se verifica no Word 97. Por isso decidi
usar o método OrganizeDelete, que funciona, igualmente, nas duas versões, sem
problemas no Word 2000.
Com isso, basicamente está concluída a instalação. Todo o resto são deta-
lhes, que não deixam de ser importantes. Um deles é o recurso a uma função da
API do Windows, GetSystemDirectory, para determinar o diretório de sistema.
Você pode usar a função GetSpecialFolder, ligada ao Windows Scripting Host.
Só que, nesse caso, é preciso ter certeza de que o sistema de scripting está instala-
do na máquina.
Agora, o detalhe final. Na Figura 35.1, você notou que o documento inclui
dois botões de comando. Qual a função deles? Esses botões são as portas de ins-
talação e desinstalação do Gerador de Recibos. O usuário deve receber – num
disquete, por exemplo – todos os arquivos do programa, inclusive o instalador,
Instalgr.dot. Com um duplo clique nesse arquivo, ele abre um documento,
como o mostrado na Figura 35.1. Com mais um clique no botão Instalar o Apli-
cativo, a tarefa está concluída. Se, depois, ele resolver eliminar o aplicativo de
sua máquina, volta ao modelo, abre um arquivo e clica no botão Desinstalar o
Aplicativo.
Embora não seja uma operação comum, é fácil inserir botões de comando
num documento. Para isso, siga o roteiro.
1. Acione Exibir/Barras de Ferramentas/Visual Basic.
2. Na barra, ligue o botão Modo Estrutura – aquele cujo ícone é o desenho
de um lápis, ao lado de uma régua e um esquadro. Surge a barra Caixa
de Ferramentas de Controle.
349
3. Clique no objeto botão de comando nessa caixa de ferramentas. Um
botão vai aparecer no documento, mas ainda não no tamanho, nem no
local que você deseja. Clique nele com o botão direito do mouse e
escolha Objeto Botão de Comando/Editar. O controle passa a exibir
alças que lhe permitem redimensioná-lo e arrastá-lo. Também nesse
momento você pode selecionar a legenda-padrão, CommandButton1, e
trocá-la por outra adequada ao seu projeto.
4. Ainda com o botão direito do mouse sobre o objeto, você acessa o
comando Propriedades, que abre a caixa do mesmo nome. Nela, é
possível definir todas as características do botão, incluindo fonte, di-
mensões, legenda e até uma imagem.
5. Na versão 97, assim que você coloca o botão na página, ele já está
pronto para ser deslocado para qualquer posição. Basta arrastá-lo. No
Word 2000, é preciso, antes, clicar nele com o botão direito do mouse,
acionar Formatar Controle e, na orelha Layout, escolher uma das
alternativas no quadro Disposição do Texto.
6. Para associar o clique no botão a alguma macro, acione no menu de
contexto, a opção Exibir Código. No caso do instalador para o Gerador
de Recibos, o primeiro botão chama a rotina InstalaAplicativos e o
segundo DesinstalaAplicativos.
7. Clique no botão Modo Estrutura (que, aliás, nesse momento se chama
Sair do Modo Estrutura) e o documento está pronto.

Para ir mais além


1. Para adaptar este projeto à instalação de outros aplicativos, é preciso al-
terar a área geral de declarações e mais quatro rotinas, a saber: 1) Copi-
aArquivos; 2) CopiaMódulos; 3) CriaBarraFer; e 5) DesinstalaAplicati-
vos.
2. Com algum esforço, pode-se tornar esse projeto o mais genérico possí-
vel, a fim de se tornar um instalador universal que exija o mínimo de re-
configurações.
3. Uma idéia para dar melhor acabamento ao produto é aperfeiçoar a roti-
na de desinstalação. Ela deve, por exemplo, identificar quando não há
nenhum elemento do projeto instalado e avisar ao usuário que não exe-
cutou nenhuma ação.

350
Copiar e renomear barras de ferramentas
No Capítulo 35, você viu como criar e remover barras de ferramentas.
Veja, no exemplo abaixo, como copiar uma barra de ferramentas de
um modelo para outro e como renomeá-la:
Sub CopiaRenomeiaBarraFerramentas()
‘ Copia barras de ferramentas de Normal.dot
‘ para o modelo do documento ativo.

‘ Cria um documento
Documents.Add
‘ Salva-o como modelo
ActiveDocument.SaveAs “c:\meus documentos\Testedot.dot”, _
wdFormatTemplate

‘ Copia a barra de ferramentas Teste para esse modelo


Application.OrganizerCopy _
Source:=Application.NormalTemplate.FullName, _

Destination:=ActiveDocument.AttachedTemplate.FullName, _
Name:="Teste", Object:=wdOrganizerObjectCommandBars

‘ Renomeia, no modelo, a barra de Teste para Teste T


Application.OrganizerRename _
Source:=ActiveDocument.AttachedTemplate.FullName, _
Name:="Teste", NewName:="Teste T", _
Object:=wdOrganizerObjectCommandBars

‘ Salva o documento
ActiveDocument.Save
End Sub

Os métodos OrganizerCopy e OrganizerRename fazem um trio


com o já conhecido OrganizerDelete. Para verificar, visualmente se a
barra de fato está lá, acione Formatar/Estilo e clique no botão Bibliote-
ca. Depois, traga para o primeiro plano a orelha Barra de Ferramentas.

A coleção da Correção
Se você quiser impressionar num bate-papo com seus amigos micreiros,
use esta frase: “o VBA é uma coleção de coleções”. É apenas uma meia
verdade, mas faz grande efeito. Além disso, há exemplos à beça para
prová-la. Aqui vai mais um. No Word, as strings de AutoCorreção (a
palavra errada e a que deve substituí-la durante a escrita) também são
membros de uma coleção, formada pelos objetos AutoCorrect.Entries
(entradas de AutoCorreção). Isso significa que é possível fazer um backup
de todas elas e até restaurá-las, na mesma máquina ou em outra.
351
As propriedades desses objetos que nos interessam são, no caso,
Name (o texto errado) e Value (a forma corrigida). Há ainda uma
terceira, RichText. Booleana (True/False), que indica se há formatação
armazenada junto com o texto de substituição. Quando, por exemplo,
a entrada serve apenas para corrigir uma troca de letra, a propriedade
RichText é falsa. No entanto, quando ela transforma, por exemplo, a
seqüência de caracteres --> no sinal –>, então essa propriedade é ver-
dadeira. Esse sinal não faz parte do conjunto de caracteres comuns dis-
poníveis no Windows.
Para listar todas as entradas de AutoCorreção em seu Word, use o
código:

Dim e As AutoCorrectEntry
For Each e In AutoCorrect.Entries
Selection.TypeText e.Name & vbTab & e.Value & _
vbTab & e.RichText & vbCrLf
Next e

Atenção para a sutileza: o objeto, na declaração, é AutoCor-


rectEntry. A coleção, AutoCorrect.Entries. O ponto faz a diferença. A in-
clusão de entradas é feita com o método Add, outra figurinha fácil no
universo das coleções. O exemplo abaixo adiciona o par (“náo”,
“não”):

With AutoCorrect
.Entries.Add Name:="náo", Value:="não"
End With

A eliminação de entradas se faz com o método Delete. Você pode


usá-lo para eliminar pares correspondentes a erros que você certamen-
te não vai cometer . Exemplo: (“orijen”, “origem”). Nesse caso, use a
propriedade Name como índice:

AutoCorrect.Entries(“orijen”).Delete

A linha acima pode ser digitada diretamente na janela Imediata.


Veja, no CD que acompanha este livro, no diretório relativo a este capí-
tulo, a rotina ListaAutoCorreção, que prepara um documento com a lis-
ta completa de todas as entradas existentes em seu Word.

352