Você está na página 1de 69

DATAFLEX

Capítulo 1- Introdução ao Dataflex


O Dataflex é uma linguagem de programação e acesso a banco de dados (também Dataflex), voltada
para o desenvolvimento rápido de arquivos de dados e ferramentas de consulta, cadastro, relatórios, e
muitas outras voltadas a esta base de dados. Suas principais vantagens são a facilidade de
desenvolvimento de aplicativos com grande portabilidade para diferentes sistemas operacionais
(Windows, DOS, Unix, AIX, Linux, Solaris,etc), bastando apenas a recompilação dos arquivos fontes.
Para os usúarios do sistema exitem as vantagens da facilidade de uso, rapidez de cadastro, velocidade e
confiabilidade no acesso aos dados, interface agradável podendo ser gráfica ou modo texto. Existe o
Visual Dataflex para windows, mas nesta apostila falaremos apenas do dataflex para DOS e UNIX
versões 3.0 e 2.3 usando lógica de programação procedural (a 3.0 suporta P.O.O. e procedural). Com o
dataflex vem diversos aplicativos, eis os principais deles que serão explicados com maiores detalhes
mais adiante:
DFCOMP - Compilador dataflex que compila o arquivo texto de extensão (.FRM por padrão) para um
arquivo executável de extensão .FLX. Usa-se DFCOMP <nome do programa + extensão>.
DFRUN - Executa um programa dataflex. Note que o FLX não pode rodar sozinho precisa do
programa dfrun para poder executar. Um programa dataflex só funciona numa máquina que tenha pelo
menos instalado o run-time do dataflex. Mas se a empresa precisa frequentemente mexer nos
programas ai vai precisar do dataflex versão desenvolvedor (completo e mais caro).Usa-se: DFRUN
<nome do programa sem extensão>
DFFILE - Usado para criar arquivos de dados (.DAT) , arquivos de indices (.K1,.K2,etc) e também
relacionamentos. Com este utilitário voce cria todos os campos do arquivo e depois cria os indices.
Voce também pode gerar arquivo de dados (vazio é claro!) também a partir de definições de arquivos
(.DEF) que são arquivos textos.
DFQUERY - Consultas rápidas a arquivos. Voce vê a estrutura do arquivo, campos, indices,
quantidade de registros e pode selecionar padrões de consulta comparando um ou vários campos com
faixas de valores que voce fixa (semelhante a clasula where do SQL). As consultas podem ser
direcionadas para arquivos texto, vídeo ou impressora e podem ser ordenadas por um indice
opcionalmente. É muito usado este utilitário na exportação (gerando arquivo texto) e conferência dos
dados.
READ - importa arquivos textos pra arquivo de dados em formatos separados por linhas ou ponto e
virgúla. É usado para gerar programas de importação de dados.
ENTERDEF - Gera executáveis de entrada de dados com macro enter automaticamente a partir de
arquivos texto de definição de arquivo(.DEF)
DFINDEX - Ferramenta para reindexar arquivos de dados.
DFSETUP - Utilitário para alterar configurações internas do dataflex.
AUTODEF - utilitário pra se criar uma aplicação de cadastro (macro enter) através de uma imagem.
MENUDEF - usado pra se criar menus e sub-menus. Ex: menu pricipal, menu da expedição, menu da
vendas, etc.
Note que o banco de dados dataflex (versões 3.0 e 2.3) não é relacional. Para um único arquivo de
dados (.DAT) criado são criados alguns arquivos adicionais como indices(.K1,.K2,.K3,etc) definição
de arquivo(.DEF), "apelidos" de campos de arquivos usados na compilação (.FD), arquivo de dados
compactado da versão 3.0 (.VLD), arquivo de nomes de campos de arquivos (.TAG). Veremos adiante
mais detalhes sobre estes arquivos.
Tenha em mente que o dataflex é uma exelente ferramenta multi-sistema operacinal, com grande
confiabilidade e velocidade de acesso. Eu trabalhei alguns anos com esta linguagem num ambiente
Unix com servidor RISC da IBM com a versão 2.3 com terminais e micros emulando terminias numa
firma de grande volume de cadastros e consultas, com cerca de 100 usuários, 500 arquivos alguns com
quase 1 milhão de registros e nunca tive problemas sérios com arquivos (bom o RISC ajudou muito...).
Os problemas que raramente ocorreram foram nada que não pudesse ser resolvido com simples
reindexação de arquivo. Bom ai quem gosta de horas-extras em CPD vai preferir outras tecnologias
"modernas"...
No dataflex voce trabalha com um registro por vez do arquivo em disco que é lido no buffer do arquivo
(na memória) e do buffer pra tela, segundo o esquema abaixo:
TELA(Campos de entrada ou janelas) <=> buffer do arquivo <=> arquivo disco
Quando voce edita ou grava um registro voce esta fazendo isto na tela mas através de um comando
(entry) que ja tambem edita o buffer e depois no final da entrada ou edição vem a gravação física dos
dados no HD. Isto a nível do usuário é muito pratico porque ele vai colocando os dados e apertando
enter até receber uma mensagem de confirmação (opcional) e com novo enter grava os dados. As busca
por valores são extremamente simples também. O usuário preenche uma entrada parcialmente (desde
que ele faça parte de um indice) e aperta F8 ou TAB e já vem o registro mais próximo para a tela que
esta pronto pra ser editado. Após a edição de um campo aperta F10 e salva os dados ou aperta F9 e
limpa a tela tudo sem a lentidão do mouse. Voce já percebeu como é lento cadastrar procurando os
campos com o mouse? Ou como é complicado usar aquelas barras de navegação com inúmeros botões,
tipo o dbnavigator do delphi? Pro usuário o dataflex permite uma enorme facilidade e desempenho
tanto no cadastro, na edição e na busca por registros. Outra vantagem são a versatibilidade da
linguagem que permite relatórios de qualquer tipo e também gráficos na tela ou impressos, além de
leitura e impressão de código de barras. Bom com o decorrer do tempo voce verá como o dataflex é
uma ótima ferramenta com grande produtividade e aceitação pelos usuários!
I see you later!

Capítulo 2 - Criando a base de dados


O utilitário para criação e edição de arquivos é o DFFILE. Assim o primeiro passo para a criação de um
programa é verificar quais arquivos ele vai usar e com o dffile imprimir uma listagem de cada arquivo.
A listagem de um arquivo impressa (que é o .DEF do arquivo) fica mais ou menos assim:
-----------------------------------------------------------------------------
DATA: 28/05/2002 HORA: 14:50 PAGINA: 1
DEFINICAO PARA O ARQUIVO: PRODUTOS (# 4)
-----------------------------------------------------------------------------
NOME BASE : PRODUTOS
NOME PARA USUARIO : PRODUTOS
NOME PARA DATAFLEX : PRODUTOS
-----------------------------------------------------------------------------
TAMANHO DO REGISTRO : 256 (USADO: 178 )
No. MAXIMO DE REGISTROS : 16711679 (USADO: 12520)
COMPRESSAO DO ARQUIVO : Rapida
REUTILIZAR ESPACOS EXC. : Sim
RELEITURA MULTI-USUARIA : Sim
-----------------------------------------------------------------------------
NUM NOME DO CAMPO TIPO TAM OFFST IN RELACIONA AO ARQUIVO.CAMP
--- --------------- ---- ----- ----- -- ---------------------------------
1 COD_TIPO NUM 6.0 1 1 TIPOS.CAMPO_1 (2,1)
2 COD_PRODUTO ASC 12 4 1
3 DESC_PRODUTO ASC 40 16 2
4 FLG_INATIVO ASC 1 56
5 ESTOQUE_ATUAL NUM 6.2 57
6 ESTOQUE_MINIMO NUM 6.2 61
7 ESTOQUE_MAXIMO NUM 6.2 65
8 PRECO_ATUAL NUM 8.2 69
9 PRECO_MINIMO NUM 8.2 74
10 VALOR_IPI NUM 4.2 79
11 EMBALAGEM ASC 10 82
12 UNIDADE ASC 20 92
13 CONSER ASC 9 112
14 PESO_LIQ NUM 4.4 121
15 COD_FISCAL ASC 14 125
16 DT_CAD DAT 3 139
17 DT_ULT_ALT DAT 3 142
18 QUANT_PEND NUM 6.2 145
19 COD_INT NUM 10.0 149 4
20 REF_INT ASC 15 154
21 FLG_IMPORTADO ASC 1 169
22 FORN1 NUM 6.0 170
23 FORN2 NUM 6.0 173
24 FORN3 NUM 6.0 176

INDIC# CAMPOS DES MAI TAMANHO NIVEIS SEGMENTO MODO


------ --------------- --- --- ------- ------ -------- -------
1 COD_TIPO Nao Nao 18 5 2 On line
COD_PRODUTO Nao Nao
2 COD_TIPO Nao Nao 46 7 3 On line
DESC_PRODUTO Nao Nao
RECNUM Nao Nao
3 COD_PRODUTO Nao Nao 15 5 2 On line
RECNUM Nao Nao
4 COD_INTER Nao Nao 8 5 2 On line
RECNUM Nao Nao
Bem acima está a data e hora de criação do arquivo. Depois vem sua posição no FILELIST que é um
numero que corresponde geralmente a ordem de criação do arquivo e que o dataflex utiliza
internamente, junto com o numero do campo.
Com relação aos campos temos o numero do campo que é sequencial, depois o nome do campo, depois
o tipo do campo, seu tamanho, a posição, o indice a qual ele faz parte e finalmente a qual outro campo
de outro arquivo que ele está relacionado.
O Filelist é mais ou menos assim:
1 - Produtos - arq001
2 - Unidades - arq002
3 - Embalagens - embs01
etc...
Existem os seguintes tipos de campos de arquivo:
ASCII - alpha-numérico ou string ate 255 caracteres
NUM - numéricos que pode ser inteiro ou ponto flutuante. Exemplo:
COD_INT NUM 10.0 é inteiro de dez dígitos tipo 1020400231
PRECO_ATUAL NUM 8.2 é float de 8 dígitos na parte inteira e 2 decimais tipo 12560,50
DATE - campos para data no formato "dd/mm/aaaa"
TEXT - campo para texto sem formatação (na versão 2.3 não existe)
BLOB - campo para grandes objetos tipo fotos (na versão 2.3 não existe)
OVERLAP - campo de junção de campos usado para diminuir o tamanho de indices
Logo depois dos campos vem as informações sobre indices. No caso acima o indice 1 é exclusivo
porque não aparece nele o recnum. Quando voce deseja tirar a exclusividade de um indice acrescente
no final dele o recnum.
RECNUM é um campo tipo numero inteiro (>0) que corresponde geralmente a ordem de criação do
registro, tipo o primeiro registro gravado tem recnum= 1 o segundo registro gravado tem recnum= 2 e
assim por diante. O recnum é um campo que sempre existe num arquivo e tem valor exclusivo. Mesmo
se um arquivo for criado sem indices o recnum pode ser usado como indice. Quando voce deleta um
registro aquele recnum é reutilizado pelo dataflex numa futura inserção de registro. Em arquivos onde
não se deleta registros o recnum pode ser usado como um código sequencial exclusivo.
Bom falamos no caso do arquivo já estar criado. Se não existir o arquivo que voce quer é muito fácil
cria-lo usando o DFFILE, porque ele é um utílitario que cria tudo passo a passo sem codificação.
Recomendações:
1-Use nome de campos claros tipo COD_PRODUTO e nao CPR, vai te facilitar a vida e dos outros
programadores.
2-Use o mesmo nome do campo em diferentes arquivos, exemplo: PRODUTOS.COD_PRODUTO e
MOVIMENTOS.COD_PRODUTO pois também facilita!
3-Procure colocar os campos principais que farão parte do indice principal no começo do arquivo na
mesma ordem que vão aparecer no indice.
4-Evite indices com muitos campos grandes, use overlaps.
5-Crie indices inteligentes e só os crie na medida da necessidade.
6-Não duplique informação desnecessariamente gravando a mesma informação em dois arquivos,
normalize os arquivos.
7-Não crie muitos indices exclusivos prefira indices não exclusivos.
8-Lembre que o FILELIST comporta 255 arquivos não crie arquivos desnecessariamente.
9-Crie os arquivos que não existem, imprima as definições de todos os arquivos que serão abertos no
programa e só ai comece a programar.

Capítulo 3 - Telas de um programa dataflex (procedural)


//**************************************
//programa P-001
//sistema: agencia de empregos
//finalidade: cadastro de profissionais
//feito por Paulo Miranda 17/01/2003
//atualizado por Simone 25/02/2003
//**************************************
/Tela1
Codigo: _________.
Nome: __________________________________________________
Endereco: __________________________________________________
Cidade: ___. _____________________________ UF: __
CEP: _________ Data Nasc: __/__/____ Anos: _.
Res: (__.) _________ Cel: (__.) _________
RG: _______________ CIC: _______________

E-mail: __________________________________________________
Profissao: ___. __________________________________________
Salario Pretendido: _______.__
/Telamens
___________________________________________________ _
/Aviso
Este é um exemplo de tela sem
janelas...
/*
//****Exemplo de comentário em Dataflex****
Acima temos o exemplo da declaração de 3 telas em dataflex. Observe que o nome da tela deve
começar com "/" tipo "/Nome_da_tela". A primeira etapa é desenhar as telas, claro que dá pra caprichar
mais do que no exemplo acima e fazer sombra, contorno e se for modo gráfico então nem se fala. Todo
programa começa com as telas e depois vem o simbolo "/*" colocado sempre totalmente a esquerda e
depois das telas pra iniciar o código.
Janelas são chamados os locais de entradas de dados (diferente de janela no windows). Por exemplo
"____.__" é uma janela para entrada numérica de 4 inteiros e dois decimais.
Tipos de janelas:
ASCII: ______________________
São para entradas de dados ascii
Numéricas: _________. Inteiro de 10 digitos no maximo
_________.____ Float de 10 digitos e 4 decimais
___,___.__ Float formatada
Datas: __/__/____ Para entrada de datas tipo dd/mm/aaaa
Observe que é uma boa prática dimensionar a janela com o mesmo tamanho e tipo do campo de
arquivo. Mais tarde voce vera como conectar a janela com seu campo de arquivo respectivo.
Quando voce cria uma tela as janelas tem nomes padrão que depois poderão ser redefinidos. A
nomenclatura funciona assim:
TELA1.1 seria o codigo
TELA1.2 é a primeira janela que corresponde ao nome.
TELA1.3 é o endereço
TELA1.4 é a terceira janela da direita pra esquerda e de cima pra baixo que coresponderia ao codigo da
cidade
TELA1.5 corresponderia ao nome da cidade
TELA1.6 seria a UF ou estado
E assim sucessivamente seguindo a regra: Nome_da_tela.indice_janela
Teriamos Telamens.1 e Telamens.2 na outra tela.
Obseve que nem todas telas tem janelas (pode ser uma tela apenas pra help ou aviso) mas toda janela
tem que estar definida numa tela.
Quando o usuário estiver usando o programa ele inserirá uma informação numa janela em seguida
apertará ENTER e o cursor vai prá janela seguinte pra nova entrada, isto veremos melhor depois.
IMPORTANTE: O simbolos "/" sempre deve estar encostado no inicio da linha quando se referir a
nome de tela ou "/*" inicio de programaçao.
Recomendações:
1-Capriche no layout das telas e procure seguir padrões que seus usuarios ficaram satisfeitos. Evite
telas muito carregadas de janelas e também evite programas com muitas telas pra entrada de dados.
No proximo capítulo veremos um pouco de código, calma...

Capitulo 4- Começando a programar


No capitulo anterior fizemos as telas do nosso primeiro programa. Agora vamos começar a codificar.
Logo após o simbolo "*\" começaremos código:
/*
//=======[ Inicio da Programação ]===========
// Usa-se barra barra para comentário!
//=======[ Includes de arquivos ]============
#include biblioteca.inc
#include fmar.inc
//=======[ Page set das telas ]==============
page set tela1 at 04 03 colors 05 15
page set telamens at 20 00
page set aviso at 06 15
//======[ Abertura de arquivos ]=============
open "empregados" as empregados //***[ Cadastro dos candidatos para vagas
open "cidades" as cidades //***[ Cadastro das cidades
open "profissoes" as profissoes //***[ Cadastro das profissões
Até aqui parece que dá pra entender não é? INCLUDE é para incluir bibliotecas com seus próprios
comandos. Falaremos como criar comandos depois.
PAGE SET é o comando que posiciona a tela no vídeo. Aqui estamos usando modo texto de 80 colunas
X 25 linhas.
OPEN é pra abrir o arquivo e AS é opcional.
Depois vem:
//======[ Names das janelas ]================
name tela1 cod_candidato nome_candidato endereco cod_cidade ;
desc_cidade sigla_estado cep data_nasc
name idade ddd_res tel_res ddd_cel ;
tel_cel RG CIC e_mail
name cod_profissao desc_profissao salario
name telamens mens resp
Esta parte de names é opcional mas é bom sempre colocar, procurando colocar o nome da janela igual
o nome do campo de arquivo. Observe que isto irá facilitar a programação mas a janela pode ter o
nome que voce quizer menos nome de comando ou palavras reservadas do dataflex.
Se voce é bom observador precebeu que coloquei name tela1 na primeira linha e depois acaba com
ponto e vírgula. O ponto e virgula é pra string no dataflex continuar na outra linha.
O comando name aceita uma string com um máximo de 255 caracteres por isso depois eu coloco outro
NAME pras próximas janelas pra não estourar o tamanho da string de comando, observando que não
repito o nome da tela porque o dataflex entende que estou me referindo a tela1.
Se eu não colocar names nas janelas quando precisar inserir uma janela será necessário varias
alterações no programa. Observe:
Se não tenho names os nomes padrão ficam tela1.1, tela1.2, tela1.3 até tela1.19. Imagine que eu queira
inserir uma nova janela entre tela.4 e tela.5, esta janela passará a ser a tela.5, a tela.5 passa ser a tela.6 e
assim por diante. Como no dataflex muitos comandos fazem referencias a nomes de janelas se eu tiver
muito código no programa precisarei fazer muitas alterações porque na inserção da tela.5 nova todas as
janelas seguintes mudaram seu names. Então USE SEMPRE NAMES!
Vamos continuar com nosso programa exemplo:
//=========[ definição de variaveis ]=========
integer num cont
number valor preco_unitario
string linha letra 1 frase 20 ;
outra_linha
date data data2
indicator ok existe
//============================================
TIPOS DE VARIAVEIS NO DATAFLEX:
INTEGER - Numero inteiro positivo ou negativo na faixa de +/- 2,147,483,647.
NUMBER - Numero com ponto flutuante tipo o float do C.
STRING - String de tamanho padrão 80 caracteres se voce cita o comprimento depois do nome da
string voce redefine este valor, observe que não existe o tipo char então quando se usa uma string de
tamanho 1 é como um char.
Ex: string letra 1
DATE - Data no formato dd/mm/aaaa. O dataflex suporta todas operações com datas, tipo somar data
com inteiro e outras.
INDICATOR - É o tipo booleano de valor FALSE ou TRUE, são de grande utilidade no controle do
fluxo do programa.
No proximo capítulo veremos laços e comandos básicos no dataflex.

Capitulo 5 - Laços, indicadores, operadores lógicos e mais alguns comandos


No dataflex como toda linguagem de programação que se preze existem laços, antes porém vamos
dizer mais sobre indicadores, que são importantes controladores de fluxo nos programas.
Declaramos indicadores assim:
INDICATOR meu_indicador outro_indicador
Pra mudar seu valor (quando é criado esta falso) usamos o comando indicate:
INDICATE meu_indicador TRUE
INDICATE outro_indicador FALSE
Podemos atribuir o valor de um indicador ao valor do outro:
INDICATE meu_indicador AS [ outro_indicador ]
na sentença acima o valor de meu_indicador (true ou false) será o mesmo do valor de outro_indicador.
No exemplo acima meu_indicador será false após a sentença porque ele copiou o valor de
outro_indicador que era false.
Ou atribuimos indicadores comparando de outras formas:
INDICATE dados_ok AS resp.1 EQ "S"
INDICATE salario_certo AS salario LE 300
Podemos usar também INDICATE outro_indicador AS [ ~meu_indicador ]
que o simbolo "~" significa NOT e no caso acima outro_indicador recebe o valor oposto de
meu_indicador ou not meu_indicador.
No programa o indicador aparece entre colchetes tipo [ MEU_INDICADOR ] quando esta controlando
blocos de código, laços, ou depois do AS. Falaremos deles muito mais vezes não se preoculpe. Mas
observe que um indicador SEMPRE contém um valor que é falso (false) ou é verdadeiro (true).
INDICADORES ANTES DE COMANDOS:
[ meu_indicador ] comando_x
[~meu_indicador ] comando_y
Se meu_indicador estiver true só o comando_x será excutado caso contrário só o comando_y será
executado.
INDICADORES ANTES DE BLOCOS DE COMANDOS:
[ meu_indicador ] BEGIN
comando_x
comando_y
[ outro_indicador ] BEGIN
comando_z
comando_k
END
END
INDICADORES COMBINADOS:
[ meu_indicador outro_indicador ] comando_k
[ meu_indicador ~outro_indicador ] comando_w
[~meu_indicador ] comando_x
Podemos combinar inúmeros indicadores mas o usual é usar uns 2 ou 3 no máximo numa sentença pra
evitar uma programação confusa e ilegível.
Voce acabou de ver também que os blocos de comando são delimitados por BEGIN e END como no
pascal. Vamos aos operadores lógicos agora:
EQ é o igual (= no pascal e == no C)
NE é o diferente (<> no pascal e != no C)
LT é o menor (<)
LE é o menor ou igual (<=)
GT é o maior (>)
GE é o maior ou igual (>=)
NOT é a negação e também é representado por ~ dependendo do caso.
OR é o ou (or no pascal e || no C)
Obs: infelizmente o AND não exite e tem que ser feito com if ou indicadores.
O comando MOVE é usado pra mover valores pra váriáveis, janelas e campos de arquivos. É bom
frisar que uma grande vantagem do dataflex é que podemos mover dados de inúmeras formas, como
por exemplo variavel pra uma janela, somar variavel com campo de arquivo, somar janela data com
inteiro, e muito mais.
Sintaxe do move:
MOVE valor TO variavel
MOVE valor TO janela
MOVE valor TO arquivo.campo
Exemplos:

MOVE TELA1.1 TO CODIGO


MOVE PRECO TO MENS
MOVE 10201 TO CLIENTES.CODIGO
MOVE "PAULO" TO TELA.2
MOVE TELA.1 TO TELA.2
MOVE PRODUTOS.COD_PRODUTO TO MOVIMENTOS.COD_PRODUTO
MOVE "" TO TELA.3
Agora os LAÇOS:
(1) IF - pode ser usado de várias formas mas sua lógica é IF <condiçao> comando
sua traduçao é se a condiçao for verdadeira é executado o comando.
exemplos:
IF numero LT 10 BEGIN
<COMANDOS>
END
ELSE BEGIN
<COMANDOS>
END
IF numero GE 10 IF numero LE 30 comando_x
OBS: Podemos usar no máximo 3 ifs por sentença tipo
if condição1 if condição2 if condição3 comando_ou_bloco
(2) REPEAT ... UNTIL repete comandos até a condição ser verdadeira
exemplos:
REPEAT
comando_x
comando_y
UNTIL [ MEU_INDICADOR ]
REPEAT
comando_z
UNTIL numero LE 10
(3) FOR ... LOOP
exemplos:
FOR num FROM 1 TO 50
comando_x
comando_y
comando_z
LOOP
FOR valor FROM 20 DOWN 0 STEP 2
<comandos>
LOOP
down significa que esta decrescendo e step o valor que a váriavel de controle é decrementada (o default
é 1)
FOR num FROM 0 TO 100 STEP 10
<comandos>
LOOP
se dentro do for forçarmos a variavel de controle chegar no valor limite isto é uma forma de sair do for.
Ex acima: move 100 to num
(4) WHILE .. LOOP
exemplos:
WHILE [ indicador ]
comando_x
comando_y
LOOP
WHILE valor1 LT valor2
<comandos>
LOOP
(5) REPEAT .. LOOP este é o laço infinito.
(6) GOTO Label é um recurso que existe mas deve ser usado com cuidado, procure usar os outros laços
que darão mais legibilidade e coerencia para os seus programas.
exemplos:
LB_INICIO:
<comandos>
IF resp EQ "N" GOTO LB_INICIO

(7) CASE é usado da mesma forma que o switch do C ou case do pascal


Exemplo:
CONDITIONAL
CASE MES EQ 1
<COMANDOS>
CASEEND
CASE MES EQ 2
<COMANDOS>
CASEEND
CASE MES EQ 3
<COMANDOS>
CASEEND
CASEELSE
<COMANDOS>
CASEEND
CONDITIONALEND

(8) ON variavel_inteira GOSUB sub1 sub2 sub3 ...


se a variavel inteira contém 1 vai pra rotina sub1 se contém 2 vai pra segunda rotina e assim por diante.

(9) ON variavel_inteira GOTO label1 label2 label3 ...


Mesma coisa do on gosub só que com desvio em vez de sub-rotina. Evite usar...
No próximo capitulo veremos mais comandos... não entrei em detalhes nos laços porque voce deve te-
los visto em outras linguagens espero.

Capitulo 6 - Mais comandos dataflex (os mais usados)


ABORT - este comando termina um programa dataflex e volta pro programa pai que pode ser um menu
dataflex, outro programa ou o sistema operacional.

ACCEPT - aceita uma entrada de tecaldo numa janela, a entrada é terminada com o pressionamento da
tecla enter. Exemplo:
name telamens mens resp
inicio:
<comandos>
move "Dados corretos para gravar? (S/N)" to mens //mosta a mensagem
move "S" to resp //valor padrão da resposta
accept resp {Capslock,check="SN"} //opa isso de capslock falaremos depois
if resp eq "N" goto inicio
<comandos>
abort //fim do programa

APPEND - appenda uma string ou mais na primeira.


Ex. append str tela.10 str2 cliente.nome

AUTOPAGE - pra poder dar entry's sem precisar citar a janela, mas segue a ordem das janelas. EX:
autopage tela1
entry produtos.cod_tipo
entry produtos.cod_produto
entry produtos.desc_produto
...

ASCII - usa-se ascii str to var_int, isto é, obtem o valor inteiro de um caracter ascii e guarda-o numa
variável. Veja CHARACTER.

BACKFIELD - faz o cursor voltar pra janela anterior.

BLANKFORM - limpa tela, janela, ou intervalo de janelas (usa c/THRU).Ex:


blankform tela1 //limpa todas janelas da tela1
blankform tela1.1 //limpa 1 unica janela
blankform tela.5 THRU tela.10 //limpa 6 janelas
obs: se usar CLEARFORM serão limpas as janelas mas os caracteres "_" serão mantidos.

CALC - executa um calculo no destino pra uma fonte. Exemplos:


calc ( (10.23 * tela.1) + (arquivo_taxas.IPI * valor ) / taxa ) TO tela.2
calc (10 + tela.5) to tela.5

CHARACTER - var_int to str. Obtem o caracter ascii correspondente ao inteiro e quarda-o numa
variavel string.

CIC_CHECK, CGC_CHECK testam a validade do cic e do cgc e devovlvem o resultado em ERR =


true se inválido, ERR = false se válido. Ex:
repeat
entry clientes.cgc cgc
cgc_check cgc
until [~err]

CLEAR - limpa o buffer de arquivo.

CLEARFORM - veja blankform.


CLEARSCREEN - limpa a tela de video.

CMDLINE - pega parametros do programa pai ou chamador, exemplo:


<programa pai>
string programa
move "" to programa
append programa "filho " cod_cliente " " data_cad " " cgc_cli
<programa filho>
cmdline cod_cli
cmdline data_cadastro
cmdline cgc_cliente
OBS: as variaveis que vão receber os parametros precisam ser do mesmo tipo do parametro passado
pelo pai ou chamador.

COPYFILE <nome_arq_fonte> TO <nome_arq_dest>, copia o arquivo.

CURRENT_WINDOW - variável inteira interna do dataflex que guarda o valor da janela corrente.

CURRENT_IMAGE - variável inteira interna do dataflex que guarda o valor da imagem (tela)
corrente.

DISPLAY - sintaxe: display <arquivo.campo> to janela. Mostra o conteudo do campo com


formatações diferentes do entry. (signrt,fill,float$,etc)

ENTDISPLAY - mostra os campos nas janelas com entrys, geralmente após uma busca. Ex:
entry produtos.codigo codigo
entry produtos.desc desc
entry produtos.val_unit val_unit
<comandos>
findkey eq produtos by index.1 ;
for produtos.codigo eq 11135
[ found] entdisplay produtos

ENTERMODE - impede o cusor de voltar pra janelas anteriores a sua chamada. Este comando não
deve ser usado no meior de entrys.

ENTRY - opa este é um comando importante que mostraremos com detalhes nos próximos capítulos.
Ele faz a ligação da janela com o campo de arquivo. Ele da um accept e joga o valor da janela no
buffer.
É usado na macro enter ou entergroup, nunca fora delas!
Exemplo:
ENTRY Produtos.Cod_produto Cod_produto
ENTRY Clientes.Nome Tela1.4 {Capslock}
DELETE - deleta o registro no buffer, se não tiver registro mostra erro.
Usa-se delete nome_arquivo

DIRECT_INPUT - abre um arquivo texto ou dispositivo pra leitura.CLOSE_INPUT fecha.

DIRECT_OUTPUT - abre um arquivo texto ou dispositivo pra escrita.CLOSE_OUTPUT fecha.

ENTAGAIN - impede que o cursor avance de janela.

ENTER - macro enter, proporciona um ambiente completo de entrada de dados, será vista em breve.

ENTERGROUP - será vista posteriormente.

ERASEFILE - deleta arquivo, usa-se erasefile <nome_arquivo>

ERR - indicador pré-definido do dataflex setado por alguns comandos.

ERROR - Da uma mensagem de erro pro usuário com numero e com beep.
Ex: error 200 "Codigo invalido!"

FIELDINDEX - funciona igual windowindex só que pra campo de arquivo. Ex:


arquivo:
campo1
campo2
...
campoN
usa-se:
for fieldindex from 0 to (N-1)
move valor to arquivo.campo1& //usa-se "&" pra acessar
loop

FIND, FINDKEY, SEARCHKEY - São comandos de busca de registros no dataflex que setam found e
finderr após a busca ser efetuada
Exemplos:
(1)
move "P" to clientes.nome //inicializa a chave
find gt clientes by index.2
[ found ] move clientes.codigo to tela1.3
vai mostrar o próximo nome c/valor maior que "P",por exemplo "Patricia Souza"
find pode ser find gt, find ge, find le, find le
(2)
findkey eq produtos by index.1 ;
for produtos.cod_tipo eq 10202 ;
produtos.cod_produto eq "1166665P"
findkey é usado quando o indice é exclusivo e todos campos estão preenchidos
(3)
searchkey ge produtos by index.4 ;
comparing produtos.cod_inter eq cod_inter
searchkey é usado para indices não exclusivos

FINDERR - indicador pré-definido que indica se foi achado registro numa busca. Se não acho finderr =
true. Juntamente com o found é setado após um comando de busca em arquivo
(find,findkey,searchkey).

FOUND - indicador pré-estabelecido que indica se foi achado registro ou não após um comando de
busca tipo find, findkey, searchkey etc. Quando chega no final do arquivo de dados o found = false e
finderr = true.

FORMFEED - faz a impressora avançar de folha.

GOSUB - subrotinas são muito boas pra dar legibilidade e facilitar a manutenção dos seus programas,
infelizmente na versão 2.3 elas não retornam valores, devendo trabalhar sempre com variáveis do tipo
global declarados no inicio do seu programa. Exemplo:
<comandos>
GOSUB Calcula_media
<comandos>
ABORT
//===[ Subrotinas ]====
Calcula_media:
<comandos>
RETURN
Observe que o comando RETURN volta pro ponto logo a seguir a chamada da subrotina com GOSUB.

GOTOXY - Poe o cursor numa posicao na tela, tipo gotoxy 10 15

GRAPHIC ON/OFF - Entra / sai do modo gráfico.

LEFT, RIGHT e MID - movem parte de dados de um local pra outro. Exemplo:
integer dia mes ano
string strdata 10
move clientes.data_cadastro to strdata
right strdata to ano 4
mid strdata to mes 2 4
left strdata to dia 2
Peceba que left e right usa-se com um parametro que é o tamanho a ser movido e mid tem dois
parametros um o tamanho e o segundo a posição de inicio pra mover. São comandos muito uteis.

IFCHANGE - indicador predefinido que indica se houve alteração. Ex:


ifchange tela1.1 begin
<comandos>
end

INCREMENT - incrementa de 1 uma variavel inteira. Ex: increment num


O contrário de DECREMENT que decrementa uma variável inteira.
IN - indica se uma substring é contida na string. EX:
string uf 2 regiao
if uf in "SPxRJxESxMG" move "SUL" to regiao

INKEY - captura uma tecla do teclado sem precisar apertar enter. Ex:
string letra 1
inkey letra
if letra eq "R" gosub relatorio

INKEY$ - é usado pra capturar teclas em loops, sem parar o loop, é bom pra por em loops muito
demorados pro usuario poder abortar se quizer.Ex:
string letra 1
<comandos>
repeat
<comandos>
inkey$ letra
if letra eq "A" abort
until [ found ]

INSERT - insere uma substring numa string numa posição determinada. Ex.
insert substr IN str AT 04

KEYCHECK - verifica se uma tecla foi pressinada, usado em loops. Ex:


repeat
<comandos>
until keycheck

KEYPROC OFF/ KEYPROC ON - desabilita ou habilita as keyprocs.

LENGTH - retorna o tamanho de uma string. Ex: For num from 1 to length(str)
MOVESTR, MOVE - são comandos usados pra mover dados. Só que o movestr move exatamente o
dado sem formatalo.

OPEN e OPEN .. AS - abre arquivo pra leitura/gravação. Se usarmos file_mode podemos abrir só pra
leitura. EX:
open "C:\bdados\meu_arq" as meu_arq
file_mode read_only //==só leitura

OUTFILE - prepara um arquivo ou dispositivo pra ser a saida padrão, fecha com OUTCLOSE. Ex:
outfile "arquiv1.txt"
outfile "LST:", pra impressora

OUTPUT - manda uma tela pra saida padrão que pode ser redirecionada. Ex:
outfile "LST:"
output tela1 //imprime a tela1
outclose

PAGE - mosta uma tela no video, esta embutido em comandos como accept e entry. Ex: page telamens

PAGESET - ajusta uma tela no video. Ex: page set tela1 at 05 06 colors 10 11 o colors é opcional.

PAUSE - faz uma pausa no programa esperando digitação e mostrando uma mensagem pro usuário.
Ex: pause "Pressione tecla para continuar..."

POS - posicao de uma substring numa string tipo pos substr in str to num, o pos seta o indicador found
também. (found = true se achou)

PRINT - opção de mover pra janela com formatação. Ex:


print tela.1 to tela.1 {fill="0"} //proximo capitulo tá explicado

REPLACE - muda o valor de uma substring numa string por outra string, e devolve o valor de found =
true se achou a substring e found = false se não a achou. Exemplos:
move "paula" to str
replace "a" in str with "o" //resulta str="poula"
move "paula" to str
while [ found ]
replace "a" in str with "o
loop
//resulta str= "poulo"
move "paula" to str
replacle "pau" in str with "" //resulta str="la"
REPORT - macro report proporciona grande facilidade pra relatórios, será estudada c/detalhes
posteriormente.

REREAD - rele o buffer de registro do arquivo.

RETURN - volta de um gosub, se usarmos RETURN RETURN volta da subrotina e da rotina que
chamou aquela subrotina (2 níveis).

ROUND <expressão> - arredonda o valor da expressão.

RUNPROGRAM - excuta um outro programa externo e não dataflex e volta se for acompanhado de
WAIT.Ex:
string programa
move "edit arquivo.txt" to programa
runprogram programa, executa o edit e sai
runprogram wait programa, executa o edit e volta
Se for programa dataflex use CHAIN com ou sem WAIT
move "cad001" to programa
chain programa
chain wait programa

SAVE - salva o registro no buffer, e move os dados do arquivo principal pros arquivos relacionados
secundários salvando-os em seguida. Nunca use save dentro da macro enter ou entergroup, pois os
dados não foram ainda movidos pro buffer. Use-o fora depois do enterend ou depois do endgroup.

SAVERECORD - salva o regitro no buffer mas no caso de arquivos relacionados não move os dados
do arquivo principal pros arquivos relacionados secundários. Ex: SAVERECORD CLIENTES
Não use saverecord dentro de macro enter ou entergroup pelo mesmo motivo do comando save.

SCREEMMODE - ajusta o modo de video. Ex: screenmode 31

SEQEOF - indicador pré definido que indica final de arquivo texto.


repeat
readln linha
...
until [ seqeof ]

SHOW e SHOWLN pra mostrar uma mensagem direto na tela sem janelas.

STATUS - indica se existe registro no buffer do arquivo. Ex:


indicate existe status clientes
ou
if status clientes begin
<comandos>
end

SUBTOTAL - comando usado na macro report pra totalizar. Será visto mais adinate com detalhes. Ex:
subtotal body.2 to subtotal1.1

SYSDATE - captura a data e hora do sistema em uma variavel, janela ou campo.


formato sysdate [data] {hora} {minuto} {segundo}
Ex: sysdate tela.1, sysdate clientes.dt_cadastro hora_cad min_cad

SYSTEM - sai para o sistema operacional direto.

TRIM - elimina os espacos em branco de uma string. Ex:


trim str to str

UPPERCASE - converte pra letras maiúsculas. Usa-se uppercase str

WINDOWINDEX - variavel que contém o indice da janela, seu uso facilita muito a programaçao.Ex:
/tela1
___. ___. ___. ___. ___. ___. ___. ___. ___. ___. ___. ___.
/*
<comandos>
move ( mes - 1 ) to windowindex
calc ( valor + tela1.1& ) to tela1.1&
Observe que a windowindex tem que ser acessada usando o simbolo "&", no exemplo acima se o mes é
5 ele acumula o valor na tela1.5

WRITE e WRITELN - escreve linha em arquivo texto.Veremos exemplo depois.

ZEROFILE <nome_arq_dados> apaga todos os registros de um arquivo de dados.

No próximo capítulo veremos formatação de janelas.

Capítulo 7 - Formatação de janelas, keyprocs.


No dataflex versões 2.3 e 3.0 a integridade dos dados é dependente das aplicações de cadastro. Bons
programas de cadastro resultam num bom banco de dados. Claro que voce pode criar uma ferramenta
pra atualizar a base de dados mas o ideal é os dados serem o mais coerentes possíveis já na entrada.
***FORMATAÇÕES DE JANELAS ***
São usadas após comandos como entry e accept ou no comando format. Sempre usamos os simbolos
"{" e "}" para as formatações, tipo {formatação1,formatação3,...formataçãoN}
DISPLAYONLY - quando a janela é só de leitura. O displayonly é a combinacão de noenter com
noput. Ex. ENTRY PRODUTOS.DESC DESC {DISPLAYONLY}
NOENTER - impede um enter na janela mas grava seu valor no buffer. É usado quando temos 2 ou
mais entrys numa janela, para evitar que o usuario tenha que apertar mais de uma vez a tecla enter
numa mesma janela. Ex.
ENTRY PRODUTOS.COD_PRODUTO COD_PRODUTO {AUTOFIND,FINDREQ}
ENTRY MOVIMENT.COD_PRODUTO COD_PRODUTO {NOENTER}
ENTRY NOTAS_FI.COD_PRODUTO COD_PRODUTO {NOENTER}
observe que a janela cod_produto esta relacionada com 3 arquivos.
NOPUT - impede que o conteudo da janela seja colocado no buffer do arquivo.
CAPSLOCK - faz com que tudo que o usuário digite seja convertido pra letras maíusculas. Ex. ENTRY
CLIENTES.ENDERECO ENDERECO {CAPSLOCK}
REQUIRED - impede o cursor de sair da janela sem que o usuário digite algo. Ex: ENTRY
CLIENTES.ENDERECO ENDERECO {CAPSLOCK,REQUIRED}
CHECK - checa se o conteudo da janela esta contido na string de checagem. Ex. ACCEPT RESP
{CAPSLOCK,CHECK="SN"} e resp é uma janela ascii de tamanho 1.
ACCEPT UF {CAPSLOCK,CHECK="SPxRJxMGxES"} e uf é janela de tamanho 2.
RANGE - impõe um limite inferior e superior.
Ex. ACCEPT IDADE {RANGE=18,40} //idade é janela _.
AUTORETURN - quando o usuário preeche o conteúdo da janela o cursor pula pra próxima janela,
sem precisar apertar o enter.
AUTOFIND - é usado em janelas associadas a um campo que é chave exclusiva, pra quando o usuário
digitar e apertar enter se o registro existir já é trazido pra tela. Todos os campos do indice devem estar
completos. Ex.
Exemplo1:
(index1 = codigo)
ENTRY CLIENTES.CODIGO CODIGO {AUTOFIND}
Exemplo2:
(index1 = cod_tipo + cod_produto)
ENTRY PRODUTOS.COD_TIPO COD_TIPO
ENTRY PRODUTOS.COD_PRODUTO COD_PRODUTO {AUTOFIND}
Exemplo3:
(index3 = bairro + rua + numero + apto)
ENTRY CLIENTE.BAIRRO BAIRRO
ENTRY CLIENTE.RUA RUA
ENTRY CLIENTE.NUMERO NUMERO
ENTRY CLIENTE.APTO APTO {AUTOFIND}
Quando o indice exclusivo usado possuir mais de um segmento, a opçãp autofind deve estar no ultimo
campo do índice.
Se usarmos AUTOFIND,FINDREQ será obrigatório o usuário entrar na janela com uma entrada que
seja existente no arquivo. Observe que o findreq impede o usuário de gravar novos regitros porque ele
exige que já exista o registro.
Exemplo 4:
(index2 = cod_inter + cod_material)
ENTRY MATERIAL.COD_INTER TELA.2
ENTRY MATERIAL.COD_MATERIAL TELA.3 {CAPSLOCK,AUTOFIND,FINDREQ}

AUTOFIND_GE - sua função é a mesma do autofind só que procura por um valor maior ou igual ao da
janela. Ex:
Exemplo1:
(index1 = nome + sobrenome)
ENTRY FUNCIONARIO.NOME NOME {CAPSLOCK}
ENTRY FUNCIONARIO.SOBRENOME SOBRENOME {CAPSLOCK,AUTOFIND_GE}
FILL - substitui valores em branco. Ex:
print hora_in to hora_in {fill="0"} // 09 em vez de 9...
FORCEPUT - força gravar no buffer do arquivo, usado quando por existencia de muitos autofind o
valor do campo esta sendo destruido no buffer.
FORMAT - é usado geralmente pra formatar grupos de janelas. Quando for colocar entry ou accepts
em loops use format, porque em loops a formatação individual não funciona. Ex:
format tela1.1 thru tela1.10 {capslock}
format hora_in {required,range=8,18}
for windowindex from 0 to 9
accept tela1.1& //nao adianta formatar aqui que não funciona!!!
loop
RETAIN - Mantém os dados na janela, mesmo quando apertado o F9 (key.clear). Pra limpar estas
janelas é preciso apertar duas vezes o F9.
RETAINALL - Os dados jamais serão apagados com F9, apenas usando o comando blankform eles
poderão ser apagados.
SKIPFOUND - é uma opção que aparece normalmente com um autofind ou autofind_ge. Sua função é
se caso seja achado um registro, mostrar os dados na janela e pular pra próxima, sem deixar que ela
possa ser modificada.
***KEYPROCS***
Keyprocs são teclas de atalho associadas a labels e indicadores. O dataflex possui teclas de atalho
padrão que podem ser reprogramadas com o dfsetup. Na versão 2.3 funciona assim:
F1 - key.help - ajuda
F2 - backwind - tela anteriror
F3 - superfind - superbusca
F4 - key.print - impressão
F5 - key.calculte - executa calculos na janela (5+4 retorna 9)
F6 - key.delete - deleta registro
F7 - key.user - voce define
F8 - key.user2 - voce define
F9 - key.clear - limpa tela
F10 - key.save - salvar dados
TAB - find - procura
PGUP - key.previous - registro anterior
PGDOWN - key.next - próximo registro
-> - key.right - seta pra direita
<- - key.left - seta pra esquerda
- key.up - seta pra cima
- key.down - seta pra baixo
ENTER - key.return - confirmação
Na programação no final de tudo colocamos as keyprocs, exemplos:
//====[ definição das keyprocs ]=========
keyproc key.help
page telahelp
pause ""
entagain
return
Keyproc Key.print
gosub imprime_relatorio
return
keyproc key.save //aqui desativamos key.save e o usuario só pode
entagain //salvar registro dando enter nos campos até o fim
return
keyproc key.delete
move "Deseja deletar o registro? (S/N)" to mens
move "N" to resp //defaut
accept resp {capslock,check="SN"}
if resp eq "S" begin
delete arquivo
return entrysec //label da macro enter (próximo capitulo)
end
entagain
return
Obs. O comando KEYPROC OFF desabiluta as keyprocs e KEYPROC ON as habilitam.
Mesmo sem definir estas teclas funcionam automaticamente na macro enter como veremos no próximo
capítulo.
Capítulo 8 - Algumas dicas de dataflex 2.3 e 3.0
//== usando indice por data:
clear arquivo
move data_de to arquivo.dt_cadastro //inicialização opcional
repeat
find gt arquivo by index.3 //supondo indice3 é por data
[ found ] indicate found as arquivo.dt_cadastro le data_ate
[ found ] begin
<comandos>
indicate found true //usado quando o found é alterado no bloco
end
until [ ~found ]
Esta contrução acima é muito usada no dataflex, observe que se chegar no final do arquivo dará
[ ~found ] e sairá do loop automaticamente.
OBS: sempre que voce for ler um arquivo a partir de um certo ponto não esqueça de inicializar a chave,
é muito mais rápido que ler todo o arquivo. Os campos que voce não especificar na inicialização serão
preenchidos com zeros ou string vazia.
//== percorrendo arquivo pelo recnum:
clear arquivo
repeat
find gt arquivo by recnum
[ found ] begin
<comandos>
end
until [ ~found ]
Usar o recnum como indice é muito usado em ferramentas que alteram registros mudando campos que
compõe o indice exclusivo. Lembre que normalmente não é correto ler e gravar novos registros pelo
mesmo indice.
//=== percorrendo arquivo pelo recnum e deletando registros
integer registro
clear arquivo
repeat
find gt arquivo by recnum
[ found ] move arquivo.recnum to registro
[ found ] if data_cad eq "10/10/2002" begin
delete arquivo
move registro to arquivo.recnum //ISTO É NECESSÁRIO!!!
end
until [ ~found ]
Quando voce lê pelo recnum e deleta é preciso salva-lo senão da bug (o recnum volta pro zero), mas
usando outros indices isto nao é necessario.
//=== Salvar o recnum (como no exemplo anterior) é uma técnica muito usada quando voce esta lendo
um arquivo e chama uma subrotina que lê o mesmo arquivo por outro indice. Ex:
integer registro
clear clientes
repeat
find gt clientes by index.1
[ found] begin
...
move clientes.recnum to registro //salva o recnum
gosub novo_loop_do_arquivo //loop no MESMO arquivo
findkey eq clientes by recnum ;
for clientes.recnum eq registro //recupera o recnum
indicate found true //recupera o found
end;
until [~found]
...
novo_loop_do_arquivo:
clear clientes
move data_de to clientes.dt_cad
repeat
find gt clientes by index.2 //indice por data
[ found ] indicate found as clientes.dt_cad le data_ate
[ found ] begin
...
end
until [~found]
return
//=== posicionar no primeiro registro lendo pelo indice 1
clear arquivo
find gt arquivo by index.1
//=== posicionar no ultimo registro
clear arquivo
move 99999999 to arquivo.cod_cli
find lt arquivo by index.1
//=== exportar pra um arquivo texto
integer recs
move 0 to recs
open arquivo
clear arquivo
direct_output "texto.txt"
repeat
find gt arquivo by index.1
[ found ] begin
writeln arquivo.codigo
writeln arquivo.nome
writeln arquivo.data
...
increment recs
show "*" //pra mostrar que ta processando
end;
until [~found]
clearscreen
showln recs " registros exportados"
abort
//=== pra importar de um arquivo texto o código é o mesmo só trocando direct_output por direct_input
e os writeln por readln. Observe que o utilitário READ gera este código automaticamente pra voce.
//=== usar windowindex e fieldindex na mesma expressão
move 0 to fieldindex
for windowindex from 0 to 19
tela1.1& = arquivo1.campo1&
loop
O dataflex distingue o simbolo "&" e percebe quando é windowindex ou fieldindex dependendo se ele
está associado a janela ou campo de arquivo.
//=== usar windowindex com names (muito útil!). Exemplo:
/tela1 //**** matrix 8 X 10 ****
___. ___. ___. ___. ___. ___. ___. ___. ___. ___.
___. ___. ___. ___. ___. ___. ___. ___. ___. ___.
___. ___. ___. ___. ___. ___. ___. ___. ___. ___.
___. ___. ___. ___. ___. ___. ___. ___. ___. ___.
___. ___. ___. ___. ___. ___. ___. ___. ___. ___.
___. ___. ___. ___. ___. ___. ___. ___. ___. ___.
___. ___. ___. ___. ___. ___. ___. ___. ___. ___.
___. ___. ___. ___. ___. ___. ___. ___. ___. ___.
/*
name tela1 val1 val2 val3 val4 val5 val6 val7 val8 val9 val10
// só dou names pra primeira linha
for windowindex from 0 to 79 step 10
accept val1&
accept val2&
accept val3&
...
accept val10&
loop
//=== Criar matrizes e vetores é muito fácil, estas estruturas não existem na linguagem mas podem ser
emuladas com imagens tipo esta do exemplo anterior.
EX:
/vetor_meses
jan fev mar abr mai jun jul ago set out nov dez
___. ___. ___. ___. ___. ___. ___. ___. ___. ___. ___. ___.
Obs: nem todas imagens que voce cria serão mostradas pro usuário, algumas são pra uso interno do
programa.

Capítulo 9 - A macro enter (entrada de dados) e relacionamentos


Voce lembra daquele programa exemplo da agencia de empregos do capitulo 3 e 4, agora podemos
termina-lo. Seu código será este:
//**************************************
//programa P-001
//sistema: agencia de empregos
//finalidade: cadastro de profissionais
//feito por Paulo Miranda 17/01/2003
//atualizado por Simone 25/02/2003
//**************************************
/Tela1
Codigo: _________.
Nome: __________________________________________________
Endereco: __________________________________________________
Cidade: ___. _____________________________ UF: __
CEP: _________ Data Nasc: __/__/____ Anos: _.
Res: (__.) _________ Cel: (__.) _________
RG: _______________ CIC: _______________

E-mail: __________________________________________________
Profissao: ___. __________________________________________
Salario Pretendido: ___,___.__
/Telamens
___________________________________________________ _
/Aviso
Este é um exemplo de tela sem
janelas...
/*
//=======[ Inicio da Programação ]===========
//=======[ Includes de arquivos ]============
#include biblioteca.inc
//=======[ Page set das telas ]==============
page set tela1 at 04 03 colors 05 15
page set telamens at 20 00
page set aviso at 06 15
//======[ Abertura de arquivos ]=============
open "empregados" as empregados //***[ Cadastro dos candidatos para vagas
open "cidades" as cidades //***[ Cadastro das cidades
open "profissoes" as profissoes //***[ Cadastro das profissões
//======[ Names das janelas ]================
name tela1 cod_candidato nome_candidato endereco cod_cidade ;
desc_cidade sigla_estado cep data_nasc
name idade ddd_res tel_res ddd_cel ;
tel_cel RG CIC e_mail
name cod_profissao desc_profissao salario
name telamens mens resp
//=========[ definição de variaveis ]=========
integer ultimo
date data
//=========[ page das telas ]=================
//Page tela1 não é necessario pq o entry da page automatico
Page telamens
//=========[ label de inicio ]================
Lb_inicio:
clearform tela1
gosub acha_ultimo
move (ultimo + 1) to cod_candidato
//=========[ inicio da macro enter ]==========
enter empregados
blankform telamens
entry empregados.codigo cod_candidato {autofind,range=1000,50000}

if cod_candidato gt (ultimo+1) move (ultimo+1) to cod_candidato


entry empregados.nome nome_candidato {capslock,required}
entry empregados.endereco endereco {capslock,required}
entry cidades.cod_cidade cod_cidade {autofind,findreq}
entry empregados.cod_cidade cod_cidade {noenter}
entry cidades.desc_cidade desc_cidade {displayonly}
entry empregados.uf sigla_estado {capslock,check="SPxRJxMG"}
entry empregados.cep cep
gosub cep_mask
entry empregados.data_nasc data_nasc {required}
sysdate data
calc (( data - data_nasc ) / 365.25 ) to idade
entry empregados.idade idade {noenter}
entry empregados.ddd_res ddd_res
entry empregados.tel_res tel_res
entry empregados.ddd_cel ddd_cel
entry empregados.tel_cel tel_cel
entry empregados.rg rg

repeat
entry empregados.cic cic
cic_check cic
until [~err]

entry empregados.email email {capslock}


entry profissoes.cod_profissao cod_profissao {autofind,findreq}
entry empregados.cod_profissao cod_profissao {noenter}
entry profissoes.desc_profissao desc_profissao {displayonly}
entry empregados.salario salario {range=250,5000}
print salario to salario
move "Dados corretos para gravar? (S/N)" to mens
move "S" to resp
accept resp {capslock,check="S/N"}
if resp eq "N" goto entrysec
return
entry.find:
findkey eq cidades by index.1 for;
cidades.cod_cidade eq cod_cidades
[ found ] move cidades.desc_cidade to desc_cidade
findkey eq profissoes by index.1 for;
profissoes.cod_profissao eq cod_profissao
[ found ] move profissoes.desc_profissao to desc_profissao
return
enterend
abort
//========[ subrotinas do programa ]============
acha_ultimo:

clear empregados
move 99999999 to empregados.codigo
find lt empregados by index.1
[ found ] move empregados.codigo to ultimo
[~found ] move 0 to ultimo
clear empregados
return

cep_mask:
string str 9 letra 1
integer num //mesmo definindo aqui são variáveis GLOBAIS!
move "" to str
for num from 1 to ( length(cep))
mid str to letra 1 num
if letra ge "0" if letra le "9" append str letra
loop
for num from 1 to ( 8 - length(str))
insert "0" in str at 1
loop
insert "-" in str at 6
move str to cep
return
//========[ definição das keyprocs ]============
Keyproc key.escape
abort
Keyproc key.clear
return lb_inicio
Keyproc key.save
entagain
return
Keyproc key.delete
move "Deseja deletar o registro? (S/N)" to mens
move "N" to resp
accept resp {capslock}
if resp eq "S" begin
delete empregados
return lb_inicio
end
entagain
return

//========[ fim do programa ]===================


A macro enter fornece um ambiente de entrada de dados, vamos analisar sua estrutura:
ENTER ARQUIVO_PRINCIPAL
//SECAO ENTRY DA MACRO ENTER:
ENTRY ARQUIVO_PRINCIPAL.CAMPO_1 JANELA_1 {FORMATAÇÃO}
ENTRY ARQUIVO_PRINCIPAL.CAMPO_2 JANELA_2 {FORMATAÇÃO}
ENTRY ARQUIVO_PRINCIPAL.CAMPO_3 JANELA_3 {FORMATAÇÃO}
...
ENTRY ARQUIVO_PRINCIPAL.CAMPO_N JANELA_N {FORMATAÇÃO}
//MENSAGEM DE CONFIRMAÇAO OPCIONAL PRA SALVAR O REGISTRO
RETURN //fecha o loop da macro enter
//SECOES POST-ENTRY OPCIONAIS DA MACRO ENTER:
ENTRY.FIND:
//BUSCAS EM ARQUIVOS
RETURN
ENTER.SAVE:
//PRA SALVAR OU ATUALIZAR OUTROS REGISTROS DE OUTROS ARQUIVOS ARQUIVOS
//O ARQUIVO PRINCILAL É SALVO AUTOMATICAMENTE!!!
//ACIONADA PELA KEYPROC KEY.SAVE
RETURN
ENTER.DELETE:
//PRA DELETAR OU ATUALIZAR REGISTROS EM OUTROS ARQUIVOS
//ACIONADA PELA KEYPROC KEY.DELETE

RETURN
ENTER.CLEAR:
//QUANDO LIMPA O BUFFER DO ARQUIVO PRINCIPAL
//ACIONADA PELA KEYPROC KEY.CLEAR

RETURN
ENTER.EXIT:
//QUANDO SAI DA MACRO ENTER
RETURN
ENTEREND
ABORT
A macro enter só pode ser usada uma única vez no programa. Observe que a macro enter é um loop e
as seções enter.save, entry.find e outras são opcionais não precisando ser declaradas quando não vão
ser usadas. Elas podem ser entendidas como sub rotinas padrão da macro enter e são chamadas
automaticamente (parecido com eventos) dependendo do que está acontecendo no programa ou do
pressionameto de keyprocs. Voce pode chama-las explicitamente se quizer tipo com GOSUB
ENTRY.FIND, que as vezes é necessário fazer assim. A macro enter tem alguns indicadores e labels
internos.
ENTRYSEC - label interno da macro enter. Goto entrysec impede que o registro seja gravado.
ENT$QUERY - indicador interno da macro enter que indica se o registro foi alterado. É comum usar
indicate ent$query false antes de autofinds pra evitar bugs em determinados casos.
CONTINUE - indicate continue false impede o loop da macro enter.
ENTER$.DELETE - label pré definido da macro enter, exemplo de uso:
accept resp
if resp eq "S" goto enter$.delete //deleta o registro
Existem outros: ENTER$.SAVE, ENTER$.CLEAR, etc.
RELACIONAMENTOS - Recomendo fazer todos os relacinamentos em tempo de execução usando
comandos de busca em arquivos (find,findkey,searchkey) na entry.find. Dá um pouco mais de trabalho
do que criar relacinamento de arquivos (com o dffile) mas também dá menos dores de cabeça. Lembre-
se: relacionamentos mal feitos geram bugs chatos e difíceis de serem localizados! O relacionamento
funciona do seguinte modo:
Voce cria o relacionamento no DFFILE, relacinando 2 campos iguais, que fazem parte de indices
exclusivos e de arquivos diferentes. Quando voce busca no arquivo o arquivo relacinado traz pro seu
buffer o registro correspondente.
Ex: notasfiscais.cod_cli = relacionado => clintes.cod_cli
e existe indice exclusivo de campo único formado por cod_cli nos 2 arquivos. Quando voce busca um
registro no arquivo de notas fiscais (FILHO) já traz o registro corespondente do arquivo de clientes
(PAI).
USO DE VARIAS MACRO ENTER - As vezes temos programas de ITENS E HEADER (ou itens e
cabeçalho), que são programas que voce cadastra um header e pra ele cadastra vários itens, em arquivos
distintos, tipo o cabeçalho de uma nota fiscal, que tem a razão social da firma, CNPJ, data, numero
nota, endereco, etc. E os items da nota de numero variavel que são os produtos, seus valores unitarios,
valores totais, etc. Como não podemos usar várias macro enter mas apenas uma, fazer este tipo de
programa da forma tradicional é uma coisa chata. Voce poderia usar a entergroup mas também não é o
ideal. O melhor neste caso é trabalhar com dois programas como se fosse um só, usando chain! Aí voce
ficará com uma macro enter pro header, totalmente normal, e o subprograma dos items, com outra
macro enter simples. Pro seu usuário vai parecer que é um programa só, e maior trabalho é passar
alguns parâmetros do programa chamador pro programa filho...
No próximo capítulo falaremos sobre a entergroup.

FALTA CAP 10

Capítulo 11 - A macro report


Do mesmo modo que a macro enter nos fornece várias facilidades para cadastros a macro report vai
facilitar muito a criação de relatórios simples ou complexos. Mas também poderemos fazer relatórios
sem usar a macro report, escrevendo muito mais código... Do mesmo modo que a macro enter a report
aparece uma única vez no programa.
Sintaxe:
OUTFILE "LST:" //redireciona saida pra impressora
CLEAR arquivo //sempre aparece
//INICIALIZAÇAO OPCIONAL DO ARQUIVO
//move valor1 to arquivo.campox
//move valor2 to arquivo.campoy
REPORT arquivo BY index.n { BREAK campox, campoy, ... campon }
[ SELECT ] INDICATE SELECT AS...
[ SELECT ] INDICATE SELECT AS...
[~SELECT ] RETURN END.OF.REPORT
INDICATE SELECT AS...
[ SELECT ] INDICATE SELECT AS...
SECTION HEADER
<COMANDOS>
OUTPUT HEADER
SECTION SUBHEADERX
<COMANDOS>
OUTPUT SUBHEADERX
SECTION SUBHEADERY
<COMANDOS>
OUTPUT SUBHEADERY
SECTION BODY
<COMANDOS>
OUTPUT BODY
SECTION SUBTOTALX
<COMANDOS>
SECTION SUBTOTALX
SECTION SUBTOTALY
<COMANDOS>
SECTION SUBTOTALY
SECTION TOTAL
<COMANDOS>
OUTPUT TOTAL
REPORTEND
FORMFEED //Geralmente aparece aqui, pra saltar de página
OUTCLOSE //Geralmente aparece também
A macro report é composta por sections opcionais:
SECTION HEADER - É o cabecalho da página, é impresso a header toda vez que iniciamos uma nova
página.
SECTION SUBHEADER1 - É impressa toda vez que o primeiro campo do indice inicia.
SECTION SUBHEADER2 - É impressa toda vez que o segundo campo do indice inicia.
SECTION BODY - É impressa a cada novo registro.
SECTION SUBTOTAL1 - É impressa quando ocorre quebra no indice1.
SECTION SUBTOTAL2 - É impressa quando ocorre quebra no indice2.
SECTION FOOTER - É o rodapé de cada pagina.
SECTION TOTAL - Aparece no final do relatório, só na última página.
OBS1: Observe que como um indice tem até nove campos no máximo podemos ter até a
SUBHEADER9 e SUBTOTAL9 num relatório.
OBS2: Para cada section declarado (opcionalmente) deve haver obrigatoriamente uma tela
correspondente com o mesmo nome!
Ex. Section Body ==> /BODY
Section Header ==> /HEADER
A macro report tem algumas variáveis, labels e indicadores internos, as vezes será preciso mudar seus
valores. São eles:
PAGEEND - variável inteira que contem o mumero de linhas por página.
PAGECOUNT - variável inteira que contém o numero da página atual.
LINECOUNT - variável inteira que contém o numero da linha atual.
RECCOUNT - variável inteira que contém o numero de registros selecionados.
END.OF.REPORT - label do fim do relatório. Uas-se return end.of.report pra encerrar o relatório.
SELECT - indicador interno que indica se um registro foi selecionado ou não. No final do arquivo
select fica false.
SUBTOTAL - comando pra totalizar. Ex: Subtotal body.4 to susbtota1.2
Exemplo de relatório simples com a report:
/header
|============|=============================================|
================|
| *REL001* | Nome da Empresa | Pag ___. |
| Paulo | Relatorio do Estoque de Produtos |__/__/____ _.:_.|
|============|=============================================|
================|
| Codigo | Descrição | Qt.Est.| Val. Unit |
|--------------+---------------------------------------+--------+-----------|
/subheader1
| Setor: ___. ___________________________ |
||
/body
| ____________ | _____________________________________ | _____. | __,___.__ |
/total
|---------------------------------------------------------------------------|
||
| Produtos Lidos ==> _____. |
|
=========================================================================
==|
/tela1
setor: ___. __________________________________
importados? _ (N)acionais,(I)mportados,(T)odos
copias: _.
_______________________________________ _

/*
//===Abertura arquivos=======
open "setores" as setores //===plasticos, vidros, cosméticos, etc
open "produtos" as produtos

//====Page sets==============
page set tela1 at 05 10

//====Variaveis==============
indicator imp todos
integer num
//====Names de janelas=======
name tela1 setor desc_setor impor copias mens resp
//====Loop principal=========
Inicio:
repeat
blankform tela1
gosub seleciona_dados
for num from 1 to copias
gosub imprime_relatorio
loop
loop
//=====keyprocs==============
keyproc key.escape
abort
keyproc key.clear
return inicio
//=====subrotinas============
Selecina_dados:
repeat
entegroup
entry setores.setor setor {autofind,findreq}
entry setores.desc_setor desc_setor {displayonly}
endgroup
move "N" to impor
accept impor {capslock,check="NIT"}
indicate imp as impor eq "I"
indicate todos as impor eq "T"
move 1 to copias
accept copias {range=1,10}
move "Dados corretos para gerar relatorio?" to mens
move "S" to resp
accept resp {capslock,check="SN"}
until resp eq "S"
return
Imprime_relatorio:
clear produtos
move setor to produtos.cod_setor
//indice.1 = setor + cod_produto
report produtos by index.1 break produtos.setor
[ select ] indicate select as produtos.setor eq setor
[~select ] return end.of.file
[~todos imp] indicate select as produtos.flag_impor eq "I"
[~todos ~imp] indicate select as produtos.flag_impor eq "N"

section header
print pagecount to header.1 {fill="0"}
sysdadte header.2 header.3 header.4
print header.3 to header.3 {fill="0"}
print header.4 to header.4 {fill="0"}
output header

section subheader1
print produtos.cod_setor to subheder1.1
findkey eq setores by index.1 for
setores.setor eq subheader1.1
output subheader1
section body
print produtos.cod_produto to body.1
print produtos.desc_produto to body.2
print produtos.qtd_estoque to body.3
print produtos.val_unit to body.4
output body
section total
print reccount to total.1
output total
reportend
formfeed
outclose
return
//=======fim=================
No próximo capítulo mais exemplos da report.

Capítulo 12 - Mais exemplos com a report


TEORIA:
(1) Uso do BREAK: No dataflex o comando break é opcional e significa que quando o indice quebrar,
uma imagem sera impressa.
Sintaxe: REPORT arquivo BY index.n {BREAK arquivo.campox,arquivo.campoy,...}
Vamos exemplificar: Suponha um arquivo de items de notas fiscais cujo index.3 é composto dos
campos: setor+cod_produto+val_item+recnum. Se quizermos usar report items_nfs by index.3 break
cod_produto teremos que definir uma section subtotal2 porque cod_produto é o segundo campo do
indice. Sempre seguiremos está lógica. E quando não houver breaks, não existirão sections subtotal
nem subheader.
(2) Quando criamos uma janela tipo body.1 o dataflex automaticamente aloca uma variavel body.1%
que acumula o valor dessa janela, pra que esse valor possa ser retornado com o comando subtotal, na
section subtotal1 por exemplo. A sintaxe seria SUBTOTAL body.1 TO subtotal1.1
(3) Quando voce precisar de um relatório com várias opções de formato, e leituras do arquivo com
diferentes indices, o melhor a fazer é criar varios subprogramas, usando chain pra executar cada um a
partir das opcoes selecionadas no programa principal. Assim voce pode usar várias macro report usadas
de forma simples em cada subprograma. Exemplo:
string programa parametros
move "relprod" to programa
accept opcao {capslock,check="ABCDEF"} //cada opcao é um tipo de relatorio
append programa opcao parametros
chain wait programa
...
(4) Pro programa funcionar melhor declare todas as imagens da report como RESIDENT. Exemplo
/body resident
__. ______________
/total resident
Bom acredito que a melhor forma de aprender a usar a report é vendo sua aplicação na prática, então
vamos lá:

EXEMPLO1 - Usando a section body pra acumular. Veja esta subrotina que usa a macro report:
IMPRIME_RELATORIO:
CLEAR SCOA233
[ ~TODOS ] MOVE USUARIO TO SCOA233.CODU
[ ~TODOS ] MOVE DATA_DE TO SCOA233.DATA
REPORT SCOA233 BY INDEX.2 BREAK SCOA233.CODU SCOA233.DATA ;
SCOA233.TOT_HS_DECIMAL
[ ~TODOS SELECT ] INDICATE SELECT AS SCOA233.CODU EQ USUARIO
[ ~TODOS SELECT ] INDICATE SELECT AS SCOA233.DATA LE DATA_ATE
[ ~TODOS ~SELECT ] RETURN END.OF.REPORT
[ TODOS ] INDICATE SELECT AS SCOA233.DATA LE DATA_ATE
[ TODOS SELECT ] INDICATE SELECT AS SCOA233.DATA GE DATA_DE
SECTION HEADER
PRINT PAGECOUNT TO HEADER.1
SYSDATE HEADER.2 HEADER.3 HEADER.4
PRINT HEADER.3 TO HEADER.3 {FILL="0"}
PRINT HEADER.4 TO HEADER.4 {FILL="0"}
PRINT DATA_DE TO HEADER.5
PRINT DATA_ATE TO HEADER.6
OUTPUT HEADER
SECTION SUBHEADER1
FINDKEY EQ SGSA004 BY INDEX.1 FOR ;
SGSA004.IDEN EQ SCOA233.CODU
PRINT SGSA004.NOME TO SUBHEADER1.1
FINDKEY EQ FPCE BY INDEX.1 FOR ;
FPCE.CODIGO EQ SCOA233.DEPTO
PRINT FPCE.DESCRICAO TO SUBHEADER1.2
OUTPUT SUBHEADER1
SECTION BODY
PRINT SCOA233.TOT_HS_DECIMAL TO BODY.1 //***Opa! a body não imprime
SECTION SUBTOTAL1 //***ela só acumula...
SUBTOTAL BODY.1 TO SUBTOTAL1.1
RIGHT SUBTOTAL1.1 TO MINUTOS 2
LEFT SUBTOTAL1.1 TO HORAS 3
PRINT HORAS TO SUBTOTAL1.2 {FILL="0"}
MOVE (ROUND ( MINUTOS * 60 / 100)) TO SUBTOTAL1.3
PRINT SUBTOTAL1.3 TO SUBTOTAL1.3 {FILL="0"}
OUTPUT SUBTOTAL1 //***quem imprime é a subtotal
SECTION TOTAL
SUBTOTAL SUBTOTAL1.1 TO TOTAL.1
RIGHT TOTAL.1 TO MINUTOS 2
LEFT TOTAL.1 TO HORAS 3
PRINT HORAS TO TOTAL.2 {FILL="0"}
MOVE (ROUND ( MINUTOS * 60 / 100)) TO TOTAL.3
PRINT TOTAL.3 TO TOTAL.3 {FILL="0"}
OUTPUT TOTAL
REPORTEND
OUTCLOSE
RETURN
EXEMPLO2 - Uma situação que voce quer imprimir varios items pra cada registro, como por exemplo
pra cada nota apacem os items que a compõe no relatório. Voce pode criar loops e subrotinas na report
bem como imprimir imagens sem ser as imagens padrão da report.
EMITE_RELATORIO:

MOVE 0 TO PAGECOUNT
SYSDATE DATAREL HORA MIN
CLEAR SCOLA29
BLANKFORM PRODUTOS
BLANKFORM CONFIRME
REPORT SCOLA29 BY INDEX.4 BREAK SCOLA29.COD_CLIENTE
//***(INDICE.4 = COD_CLIENTE +DATA+ RECNUM)***
[ SELECT] INDICATE SELECT AS SCOLA29.DATA GE DATA_DE
[ SELECT] INDICATE SELECT AS SCOLA29.DATA LE DATA_ATE
SECTION HEADER

PRINT PAGECOUNT TO HEADER.1 {FILL="0"}


PRINT DATAREL TO HEADER.2
PRINT HORA TO HEADER.3 {FILL="0"}
PRINT MIN TO HEADER.4 {FILL="0"}
PRINT DATA_DE TO HEADER.5
PRINT DATA_ATE TO HEADER.6

OUTPUT HEADER
SECTION BODY

FINDKEY EQ SCOLA23 BY INDEX.1 FOR SCOLA23.COD_CLIENTE EQ ;


SCOLA29.COD_CLIENTE
PRINT SCOLA23.RAZAO_CLI TO BODY.1
PRINT SCOLA23.UF_FAT TO BODY.2
PRINT SCOLA29.NF TO BODY.3
MOVE SCOLA29.NF TO NOTA
PRINT SCOLA29.DATA TO BODY.4
PRINT SCOLA29.VAL_NF TO BODY.5
MOVE 0 TO FIELDINDEX
REPEAT

IF FIELDINDEX NE 0 BLANKFORM BODY


PRINT SCOLA29.VAL1& TO BODY.6
IF SCOLA29.VAL1& EQ 0 BLANKFORM BODY.6
PRINT SCOLA29.VENC1& TO BODY.7
PRINT SCOLA29.PGTO1& TO BODY.8
CALC ( 1 + FIELDINDEX ) TO FIELDINDEX
OUTPUT BODY
UNTIL SCOLA29.VAL1& EQ 0
CLEAR SCOLA30
MOVE NOTA TO SCOLA30.NF
INDICATE SAIR FALSE

REPEAT

FIND GT SCOLA30 BY INDEX.1


[ FOUND ] INDICATE FOUND AS SCOLA30.NF EQ NOTA
[ FOUND ] BEGIN
PRINT SCOLA30.COD_PRODUTO TO PRODUTOS.1
SEARCHKEY GE PRODUTOS BY INDEX.1 COMPARING ;
PRODUTOS.COD_TIPO EQ SCOLA30.COD_TIPO ;
PRODUTOS.COD_PRODUTO EQ SCOLA30.COD_PRODUTO
PRINT PRODUTOS.DESC_PRODUTO TO PRODUTOS.2
PRINT SCOLA30.QTD_PRODUTO TO PRODUTOS.3
MOVE SCOLA30.VAL_UNIT TO PRODUTOS.4
CALC ( PRODUTOS.3 * PRODUTOS.4 ) TO PRODUTOS.5
GOSUB ACUMULA_PRODUTOS
PRINT PRODUTOS.4
PRINT PRODUTOS.5
INDICATE FOUND TRUE
END

[ ~FOUND] OUTPUT PRODUTOS

UNTIL [ ~FOUND]
SECTION SUBTOTAL1

SUBTOTAL BODY.5

SECTION TOTAL
SUBTOTAL SUBTOTAL1.1
OUTPUT TOTAL
PRINT CONFIRME.2 TO CONFIRME.2
PRINT CONFIRME.4 TO CONFIRME.4
PRINT CONFIRME.6 TO CONFIRME.6
PRINT CONFIRME.8 TO CONFIRME.8
PRINT CONFIRME.10 TO CONFIRME.10

OUTPUT CONFIRME
REPORTEND
FORMFEED
OUTCLOSE
RETURN

Capítulo 13 - Exemplo de impressão de etiquetas


Como a impressão de etiquetas é muito comum vamos dar um exemplo de impressão de etiquetas pra
mala direta de clientes em impressora de formulário contínuo.
//Cria-se uma tela de seleção como voce já sabe.
/TELA

Cliente .: _____. - ________________________________________

Formulario OK.?.(Y/N).: _

Quantidade de Etiquetas Lidas ...: _____.

Quantidade de Etiquetas Impressas: _____.

//Cria-se a tela onde vai o texto na etiqueta, isto é um pouco trabalhoso


//porque temos que ajustar o layout pra sair bom na etiqueta.
/BODY RESIDENT
________________________________________ ________________________________________
________________________________________ ________________________________________
______________________________ ______________________________
_________ ______________________________ __ _________ ______________________________
__
_____ ______________________________ _____ ______________________________

/*
#INCLUDE BIBLIOTE.INC
#INCLUDE TITULO.INC
//===Variaveis
STRING TECLA 1 CEP 9
INTEGER ETIQCORRENTE CONT CONT2
INDICATOR OK
//===Abre arquivo de clientes
OPEN "C:\DF301B\ALAMAR\SCOLA23" AS SCOLA23 //***CLIENTES
//===Redireciona pra impressora padrão
OUTFILE "LST:"
//===Page sets
PAGE SET TELA AT 17 05 COLORS 15 143

INICIO:
PAGE TELA
REPEAT
BLANKFORM TELA
CLEAR SCOLA23
ENTERGROUP
//seleciona um ou então todos clientes
ENTRY SCOLA23.COD_CLIENTE TELA.1 {AUTOFIND}
INDICATE TODOS AS [ ~FOUND]
[ TODOS] BEGIN
MOVE 0 TO TELA.1
MOVE " *** TODOS CLIENTES *** " TO TELA.2
END
ENTRY SCOLA23.FANT_RAZAO_CLI TELA.2 {CAPSLOCK,DISPLAYONLY}
MOVE "S" TO TELA.3
ACCEPT TELA.3 {CAPSLOCK,CHECK="SN"}
INDICATE OK AS TELA.3 EQ "S"
ENDGROUP
//inicializa variaveis
MOVE 1 TO ETIQCORRENTE
MOVE 0 TO PAGEEND //pra não pular de folha no formulario
MOVE 0 TO CONT
UNTIL [ OK ]

BLANKFORM BODY
CLEAR SCOLA23
[ ~TODOS] MOVE TELA.1 TO SCOLA23.COD_CLIENTE //se apenas 1 cliente
REPORT SCOLA23 BY INDEX.1 //***[ INDEX.1 = COD_CLIENTE
[ ~TODOS SELECT ] INDICATE SELECT AS SCOLA23.COD_CLIENTE EQ TELA.1
[ ~SELECT ] RETURN END.OF.REPORT
MOVE (CONT+1) TO CONT
DISPLAY CONT TO TELA.4 //pro usuário ver processando

SECTION BODY
//usa-se windowindex pra facilitar porque são 2 etiquetas
//uma do lado da outra
MOVE (ETIQCORRENTE-1) TO WINDOWINDEX
PRINT SCOLA23.RAZAO_CLI TO BODY.1&
PRINT SCOLA23.ENDER_FAT TO BODY.3&
PRINT SCOLA23.BAIRRO_FAT TO BODY.5&
MOVE ((ETIQCORRENTE-1)*3) TO WINDOWINDEX
PRINT SCOLA23.CEP_FAT_MASC TO BODY.7&
PRINT SCOLA23.CIDADE_FAT TO BODY.8&
PRINT SCOLA23.UF_FAT TO BODY.9&
MOVE ((ETIQCORRENTE-1)*2) TO WINDOWINDEX
IF SCOLA23.CONTATO_FAT NE "" BEGIN
PRINT "ATT: " TO BODY.13&
PRINT SCOLA23.CONTATO_FAT TO BODY.14&
END
ELSE BEGIN
BLANKFORM BODY.13&
BLANKFORM BODY.14&
END
INCREMENT ETIQCORRENTE //proxima etiqueta
IF ETIQCORRENTE GT 2 BEGIN //acabou as etiquetas da linha?
MOVE 1 TO ETIQCORRENTE //posiciona na primeira etiqueta
CALC ( CONT2 + 3 ) TO CONT2
OUTPUT BODY //imprime
MOVE CONT2 TO TELA.5
BLANKFORM BODY // coloca branco nas etiquetas
END

REPORTEND
IF ETIQCORRENTE NE 1 BEGIN
OUTPUT BODY //sobrou alguma etiqueta ? - imprime
IF BODY.1& NE "" MOVE (CONT2+1) TO CONT2
END
FORMFEED
MOVE CONT2 TO TELA.5
OUTCLOSE
PAUSE ""
ABORT

KEYPROC KEY.ESCAPE
ABORT
KEYPROC KEY.CLEAR
BLANKFORM TELA
RETURN INICIO
//---------------
Se fosse uma linha com 3,4 ou mais etiquetas a lógica é a mesma e o uso da windowindex facilita bem.

Capítulo 14 - Criando comandos


Bom já vimos muitos comandos do dataflex e agora chegou a hora de ver como criar nossos próprios
comandos. O comando pode ser definido no próprio programa, mas o melhor é criar uma biblioteca,
que nada mais é que um arquivo texto contendo os comandos. Depois se voce precisar daquele
comando que voce criou, voce da um include da biblioteca que deve ter extensão ".inc". Tipo nossos
programas aparece #include biblioteca.inc mas poderia ser #include sua_biblioteca.inc ou qualquer
nome.
Antes de mais nada precisamos ver algumas diretivas de compilação do dataflex. Diretivas de
compilação dão informações pro DFCOMP de como o nosso programa deve ser compilado. Outra
coisa legal do comando: ele aceita vários parâmetros (9 no maximo) e pode modificar todos estes
parametros.
Sintaxe do comando:
#COMMAND nome_do_comando
<COMANDOS>
#ENDCOMMAND
DIRETIVAS DE COMPILADOR: (sempre começam com "#")
#IF - if de compilador
#ELSE - mesma coisa do else normal
#ENDIF - usa-se pra delimitar o bloco if de compilador
#IFDEF - se já foi definida variável
#IFNDEF - se não foi definida a variável
#IFSAME - se um parametro é o memo que...
ACESSO AOS PARAMETROS:
!0 - numero de parametros
!1 - primeiro parametro
!2 - segundo parametro
!3 - terceiro parametro
e assim por diante até !9
EXEMPLO 1 - Este comando é usado pra depurar, porque mostra o conteudo de 1 a 9 variáveis na tela
e da um pause
Exemplo de uso: marbreak clientes.cod_cliente valor data
#COMMAND MARBREAK
//AUTOR: MARCIO LUIZ OLIVEIRA
GOTOXY 24 12 //posiciona o cursor
SHOW !1 " | " !2 " | " !3 " | " !4 " | " !5 " | " !6 " | " !7 " | " !8 " | " !9 //mostra os parâmetros na tela
PAUSE "" //faz uma pausa até uma tecla ser pressionada
#ENDCOMMAND
EXEMPLO 2 - Liga o cursor com CURSOR ON e desliga com CURSOR OFF
#COMMAND CURSOR
//AUTOR: MARCIO LUIZ OLIVEIRA
GOTOXY 23 77
#IFSAME !1 OFF //se o parametro 1 é igual OFF
SHOW " [?25l [.0" //sequencia de escape pra desligar o cursor
#ELSE
SHOW " [?25h [.3" //sequencia pra deixa-lo visível
#ENDIF
GOTOXY 23 77
SHOW " "
#ENDCOMMAND
EXEMPLO 3 - Exelente comando pra formatar e desmembrar datas, seu código é mais complexo que
os anteriores. Lembre-se o dataflex usa internamente a data como um inteiro que é o numero de dias
desde 01/01/0001.
#COMMAND DATA_CHECK // Sintaxe : DATA_CHECK (DATA) [DIA] [MES] [ANO]
[DESCRICAO DO MES]
//AUTOR DESCONHECIDO
#IFDEF DATA_VAR //se já esta definida a variavel DATA_VAR não faz nada
#ELSE
INTEGER DATA_VAR //senão cria a variável
#ENDIF

MOVE !1 TO DATA_VAR //move o parametro 1 pra data_var


IF (LENGTH(!1)) EQ 5 ;
IF DATA_VAR LT 693975;
IF DATA_VAR GE 10958;
CALC (DATA_VAR + 693975) TO !1
IF (LENGTH(!1)) EQ 4 ;
IF DATA_VAR LT 10958 IF DATA_VAR GT 1 ;
CALC (DATA_VAR + 730500) TO !1
IF !1 NE "" ;
IF !1 LT "01/01/1900" BEGIN
SHOW " "
SHOW " "
SHOW " "
GOTOXY 21 14
SHOW "ATENCAO !! DATA NAO PODE SER INFERIOR A 01/01/1900."
GOTOXY 21 14
PAUSE ""
SHOW " "
END
IF !1 GE "01/01/1900" BEGIN
#IF !0>1
LEFT !1 TO !2 2
#IF !0>2
MID !1 TO !3 2 4
#ENDIF
#IF !0>3
RIGHT !1 TO !4 4
#ENDIF
#IF !0>4
MOVE "" TO !5
IF !3 EQ 1 APPEND !5 !2 " de Janeiro de " !4
IF !3 EQ 2 APPEND !5 !2 " de Fevereiro de " !4
IF !3 EQ 3 APPEND !5 !2 " de Marco de " !4
IF !3 EQ 4 APPEND !5 !2 " de Abril de " !4
IF !3 EQ 5 APPEND !5 !2 " de Maio de " !4
IF !3 EQ 6 APPEND !5 !2 " de Junho de " !4
IF !3 EQ 7 APPEND !5 !2 " de Julho de " !4
IF !3 EQ 8 APPEND !5 !2 " de Agosto de " !4
IF !3 EQ 9 APPEND !5 !2 " de Setembro de " !4
IF !3 EQ 10 APPEND !5 !2 " de Outubro de " !4
IF !3 EQ 11 APPEND !5 !2 " de Novembro de " !4
IF !3 EQ 12 APPEND !5 !2 " de Dezembro de " !4
#ENDIF
#ENDIF
END
#ENDCOMMAND
OBS: Voce pode chamar comandos do dataflex e também seus próprios comandos dentro de 1
comando seu. Mas se um comando usa uma imagem ela obrigatoriamente tem que ser definida no
programa senão dá erro de compilação. Infelizemte na versão 2.3 uma imagem não pode ser definida
dentro de um comando (na 3.0 já é possivel!).
DICAS:
- Ao declarar variáveis em comandos procure usar nomes pouco prováveis de alguem querer usar tipo
confirma$_ok,ou $$$_num_x por exemplo.
- Crie comandos o mais independente possivel do seu programa assim eles poderão facilmente ser
usados em vários programas.
- Evite uso de comandos associados a imagems dentro dos seus comandos, prefira usar show, pause,
inkey que são comandos que não usam imagens.
- Tenha uma unica biblioteca pra todos os programadores, assim evita de existir comandos diferentes
pra fazer a mesma coisa.
- Comandos podem fazer tudo que é feito no programa, como abrir arquivos usar laços e tudo mais,
mas procure cria-los apenas pra resolver coisas que se repetem frequentemente, poupando seu tempo
no futuro.

FALTA CAP 15

Capitulo 16 - Outras técnicas


(1) Sysfile - É muito util deixar o primeiro arquivo de cada filelist como um sysfile, ou seja, um
arquivo de apenas um registro que contem algumas informções do sistema como número de sequencia
de notas fiscais, numero do usuário, etc.
(2) Arquivo temporário - arquivo que é usado por vários relatório pra acumular dados. Tanto seus
campos como seus indices devem ser o mais reutilizáveis possivel e deve usar nome de campos
genérico. Exemplo:
arquivo: phtemp
usuario number 6.0 //sempre o numero do usuario aqui
campo_ascii ascii 10
campo_date date
campo_float number 8.2
...
index.1 <1> <2> <3> <4>
index.2 <1> <3> ...
index.3 <1> ... //Todos indices quebram no campo do usuário
...
Cada relatorio abre o sysfile pega o numero do usuário e o incrementa salvando novamente no sysfile.

integer usuario
clear sysfile
find gt sysfile by recnum
move sysfile.usuario to usuario
if usuario eq 999999 move 0 to usuario
move (usuario + 1) to sysfile.usuario
saverecord sysfile
No final de um relatório o conteudo do temporario é apagado apenas dos registros do usuário que
terminou aquele relatório. Perceba que se não hover quebra no indice por usuário, o temporário
misturará registros gravados por diferentes aplicações.
(3) Campo usuário do sysfile - este é um campo muito util em ambientes multiusuario, que contem um
numero inteiro. Pra cada arquivo temporario a primeira quebra dos indices deve ser o usuário. Porque
assim conseguimos separar os resultados dos relatorios tanto pra consulta dos registros como pra sua
deleção. Lembre que cabe a cada aplicação limpar os registros por ela gravados. Exemplo de rotina:
Limpa_temporario:
gotoxy 20 05
showln "Limpando o temporario..."
clear phtemp
move usuario to phtemp.usuario
repeat
find gt phtemp by index.1
[ found ] indicate found as phtemp.usuario eq usuario
[ found ] delete phtemp
until [ ~found ]
return
(4) Arquivos fantasmas - cria-se com o dffile um arquivo com campos identicos ao original e na
abertura fazemos:
Exemplo:
criamos produtos e produtosfant com o mesmo .def
open "produtos" as produtos
open "produtos" as produtosfant
Isto é muito útil quando queremos ler o arquivo por dois indices diferentes numa mesma rotina.
(5) Estruturação da programação e hidentação do código - isto é bom em qualquer linguagem...
Procure separar o código em gosubs:
/*
page set ...
name ...
open ...
repeat
gosub seleciona_dados
gosub grava_temporario
gosub mostra_grafico
gosub imprime_relatorio
gosub limpa_temporario
loop
keyproc key.escape
abort
hidentação é pra deixar os loop mais visíveis:
subrotina_quaquer:
for cont from 1 to num
repeat

while [ ok]
<comando>

loop
until [~found]
loop
return
Sem hidentação ficaria menos visível e mais dificil a manutenção:
subrotina_quaquer:
for cont from 1 to num
repeat
while [ ok]
<comando>
loop
until [~found]
loop
return
(6) Uso dos indicadores associados as keyprocs. Toda keyproc tem um indicador associado a ela tipo
[ key.save ], [ key.next], [ key.return ] e outros. As vezes precisamos desabilitar as keyprocs e trabalhar
direto com estes indicadores, que indicam se a tecla foi pressionada ou não, mas com a keyproc
desabilitada eles não pulam automaticamente pra rotina da keyproc. Ex:
keyproc off
repeat
<comandos>
[ key.escape ] abort
until [ key.return ]
keyproc on
(7) Criação do efeito hi-ligth, ou seja é tipo uma caixa de seleção do windows ou uma list-box, com
varios items um em cada janela, e voce pressiona seta pra-cima e o hi-ligth vai pro item de cima
deixando ele "selecionado", se voce pressiona seta pra baixo volta pro item de baixo. Ele é feito com
windowindex e screenmode. Se alguem quizer mando esta rotina.
Ufa! por ora acho que este tutorial vai ficar por aqui... Sei que tá faltando coisas mas tenham paciência!
Vou melhorando se surgiirem duvidas.
Duvidas => phbm@webcable.com.br

Esse eh um fonte do jogo torre de hanoi feito em dataflex. Fez sucesso na firma que eu trabalhava
hehehe.
/INICIO
<F1> HELP DO JOGO

Voce pode jogar a TORRE DE HANOI com 3 a 7 discos.


O objetivo do jogo e mudar todos os discos do cone
"A" para outro cone nunca deixando cone maior sobre
cone menor. Boa sorte...
Com quantos discos deseja jogar? _.
Digite seu nome: ____________________
Deseja ver numero nos discos? (S/N) _
Jogo feito por Paulo Miranda
e-mail: phbm@webcable.com.brEste endereço de e-mail está protegido contra spambots. Você deve
habilitar o JavaScript para visualizá-lo.

/TORRE
ABC
ÚÄ¿ ÚÄ¿ ÚÄ¿
³³³³³³
_______³_³_______ _______³_³_______ _______³_³_______
³³³³³³
_______³_³_______ _______³_³_______ _______³_³_______
³³³³³³
_______³_³_______ _______³_³_______ _______³_³_______
³³³³³³
_______³_³_______ _______³_³_______ _______³_³_______
³³³³³³
_______³_³_______ _______³_³_______ _______³_³_______
³³³³³³
_______³_³_______ _______³_³_______ _______³_³_______
³³³³³³
_______³_³_______ _______³_³_______ _______³_³_______
³³³³³³
³³³³³³
ÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄ
MOVIMENTOS ===> ___.
JOGADA =======> _ PARA _
___________________________________ _
/MATRIZ
_. _. _.
_. _. _.
_. _. _.
_. _. _.
_. _. _.
_. _. _.
_. _. _.
/AUX
_______ _______ _. ___. _
/RECORD
ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
ºº
º ____________________ voce º
ºº
º conseguiu escrever um novo º
ºº
º RECORD de ___. movimentos º
ºº
º na categoria de _. discos. º
ºº
º Parabens!!! º
ºº
ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
/HELP
ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
º <F6 > Reseleciona opcoes º
º <ESC> Sai do jogo º
º <F9 > Reinicia o jogo º
ºº
º O objetivo e tirar todos º
º discos do cone "A" nunca º
º deixando cone maior sobre º
º cone menor. Aperte ENTER º
º para executar as jogadas. º
º EX: A <ENTER> B <ENTER> º
ºº
ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
/VITORIA
ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
ºº
ºº
º Voce venceu esta º
ºº
º tente outra vez... º
ºº
º Parabens!!! º
ºº
ºº
ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
/LINHA
_________________________
_________________________
_________________________
_________________________
_________________________
/RECORDES

Estes sao os recordistas:

3 discos ===> ____________________ ( ____ movimentos ) min=007

4 discos ===> ____________________ ( ____ movimentos ) min=015

5 discos ===> ____________________ ( ____ movimentos ) min=031

6 discos ===> ____________________ ( ____ movimentos ) min=063

7 discos ===> ____________________ ( ____ movimentos ) min=127

Tente quebrar os records !!!


/*
PAGE SET HELP AT 08 22
PAGE SET RECORD AT 07 22
PAGE SET RECORDES AT 04 10
PAGE SET VITORIA AT 08 22
INDICATOR OK FIM VER NOVO_RECORD
INTEGER ORIGEM DESTINO WIND VALOR_ORIGEM VALOR_DESTINO
REPEAT //***Loop do conjunto de partidas
OPCOES:
ACCEPT INICIO.1 {RANGE=3,7}
ACCEPT INICIO.2 {CAPSLOCK,REQUIRED}
ACCEPT INICIO.3 {CAPSLOCK,CHECK="SN"}
INDICATE VER AS INICIO.3 EQ "S"
BLANKFORM TORRE
BLANKFORM MATRIZ
GOSUB MOSTRA_RECORDES
REINICIA:
GOSUB INICIA_MATRIZ
GOSUB DESENHA_MATRIZ
PAGE TORRE
REPEAT //***Loop da partida
REPEAT //***Loop da jogada
ACCEPT TORRE.65 {CAPSLOCK,CHECK="ABC"}
ACCEPT TORRE.66 {CAPSLOCK,CHECK="ABC"}
GOSUB MOVIMENTO
[~OK ] BEGIN
MOVE "Erro, jogada invalida!" TO TORRE.67
PAGE TORRE
PAUSE ""
BLANKFORM TORRE.67
PAGE TORRE
END
UNTIL [ OK ]
[ FIM ] GOSUB ESCREVE_RECORDES
UNTIL [ FIM ]
LOOP
//*******TECLAS DE ATALHO********
KEYPROC KEY.ESCAPE
CLEARSCREEN //**se o chefe chegar e bom...
ABORT
KEYPROC KEY.UP
KEYPROC KEY.LEFT
BACKFIELD
RETURN
KEYPROC KEY.CLEAR
IF TORRE.64 GT 0 BEGIN
BLANKFORM TORRE
RETURN REINICIA
END
ENTAGAIN
RETURN
KEYPROC KEY.DELETE
RETURN OPCOES
KEYPROC KEY.HELP
PAGE HELP
PAUSE ""
ENTAGAIN
RETURN

MOSTRA_RECORDES:
//***Rotina que le os recordes do arquivo texto torre.dat
DIRECT_INPUT "torre.dat"
FOR WINDOWINDEX FROM 0 TO 4
READLN LINHA.1&
LOOP
OUTCLOSE
LEFT LINHA.1 TO RECORDES.2 4
LEFT LINHA.2 TO RECORDES.4 4
LEFT LINHA.3 TO RECORDES.6 4
LEFT LINHA.4 TO RECORDES.8 4
LEFT LINHA.5 TO RECORDES.10 4
MID LINHA.1 TO RECORDES.1 20 5
MID LINHA.2 TO RECORDES.3 20 5
MID LINHA.3 TO RECORDES.5 20 5
MID LINHA.4 TO RECORDES.7 20 5
MID LINHA.5 TO RECORDES.9 20 5
PAGE RECORDES
GOTOXY 23 28
PAUSE "Tecle algo para continuar..."
RETURN
ESCREVE_RECORDES:
//*****Rotina que grava o arquivo de recordes
INTEGER ANTIGO
KEYPROC OFF
MOVE ( INICIO.1 - 3 ) TO WINDOWINDEX
LEFT LINHA.1& TO ANTIGO 4
INDICATE NOVO_RECORD AS TORRE.64 LT ANTIGO
[ NOVO_RECORD ] BEGIN
MOVE INICIO.2 TO RECORD.1
MOVE TORRE.64 TO RECORD.2
MOVE INICIO.1 TO RECORD.3
PAGE RECORD
PAUSE ""
MOVE "" TO LINHA.1&
PRINT TORRE.64 TO AUX.4 {FILL="0"}
APPEND LINHA.1& AUX.4 INICIO.2
DIRECT_OUTPUT "torre.dat"
FOR WINDOWINDEX FROM 0 TO 4
WRITELN LINHA.1&
LOOP
OUTCLOSE
END
[ ~NOVO_RECORD ] PAGE VITORIA
[ ~NOVO_RECORD ] PAUSE ""
KEYPROC ON
RETURN

INICIA_MATRIZ:
//****Rotina de inicializacao
FOR WINDOWINDEX FROM 0 TO 20
MOVE 0 TO MATRIZ.1&
LOOP
INDICATE FIM FALSE
IF INICIO.1 EQ 7 BEGIN
MOVE 1 TO MATRIZ.1
MOVE 2 TO MATRIZ.4
MOVE 3 TO MATRIZ.7
MOVE 4 TO MATRIZ.10
MOVE 5 TO MATRIZ.13
MOVE 6 TO MATRIZ.16
MOVE 7 TO MATRIZ.19
END
IF INICIO.1 EQ 6 BEGIN
MOVE 1 TO MATRIZ.4
MOVE 2 TO MATRIZ.7
MOVE 3 TO MATRIZ.10
MOVE 4 TO MATRIZ.13
MOVE 5 TO MATRIZ.16
MOVE 6 TO MATRIZ.19
END
IF INICIO.1 EQ 5 BEGIN
MOVE 1 TO MATRIZ.7
MOVE 2 TO MATRIZ.10
MOVE 3 TO MATRIZ.13
MOVE 4 TO MATRIZ.16
MOVE 5 TO MATRIZ.19
END
IF INICIO.1 EQ 4 BEGIN
MOVE 1 TO MATRIZ.10
MOVE 2 TO MATRIZ.13
MOVE 3 TO MATRIZ.16
MOVE 4 TO MATRIZ.19
END
IF INICIO.1 EQ 3 BEGIN
MOVE 1 TO MATRIZ.13
MOVE 2 TO MATRIZ.16
MOVE 3 TO MATRIZ.19
END
RETURN

DESENHA_MATRIZ:
//****Desenha a matriz na tela dependendo do tipo de jogo (3 a 7 discos)
FOR WINDOWINDEX FROM 0 TO 20
IF MATRIZ.1& EQ 1 GOSUB POE1
IF MATRIZ.1& EQ 2 GOSUB POE2
IF MATRIZ.1& EQ 3 GOSUB POE3
IF MATRIZ.1& EQ 4 GOSUB POE4
IF MATRIZ.1& EQ 5 GOSUB POE5
IF MATRIZ.1& EQ 6 GOSUB POE6
IF MATRIZ.1& EQ 7 GOSUB POE7
LOOP
RETURN
MOVIMENTO:
//***Toda a logica do movimento de disco de uma torre p/outra
INDICATE OK AS TORRE.65 NE TORRE.66
[~OK ] RETURN
IF TORRE.65 EQ "A" INDICATE OK AS MATRIZ.19 NE 0
[~OK ] RETURN
IF TORRE.65 EQ "B" INDICATE OK AS MATRIZ.20 NE 0
[~OK ] RETURN
IF TORRE.65 EQ "C" INDICATE OK AS MATRIZ.21 NE 0
[~OK ] RETURN
GOSUB ACHA_ORIGEM
GOSUB ACHA_DESTINO
INDICATE OK AS VALOR_ORIGEM LT VALOR_DESTINO
[~OK ] INDICATE OK AS VALOR_DESTINO EQ 0
[~OK ] RETURN
GOSUB DESENHA_MOVIMENTO
GOSUB VERIFICA_FINAL
PAGE TORRE
CLEARFORM TORRE.65
CLEARFORM TORRE.66

RETURN

VERIFICA_FINAL:
//****Verifica se voce terminou
IF MATRIZ.19 EQ 0 IF MATRIZ.20 EQ 0 INDICATE FIM TRUE
IF MATRIZ.19 EQ 0 IF MATRIZ.21 EQ 0 INDICATE FIM TRUE
RETURN

DESENHA_MOVIMENTO:
//***Desenha o movimento do disco de uma torre p/outra
MOVE ORIGEM TO WINDOWINDEX
MOVE MATRIZ.1& TO AUX.3
MOVE 0 TO MATRIZ.1&
MOVE DESTINO TO WINDOWINDEX
MOVE AUX.3 TO MATRIZ.1&
MOVE ( ORIGEM * 3 ) TO WINDOWINDEX
MOVE TORRE.1& TO AUX.1
MOVE TORRE.2& TO AUX.5
MOVE TORRE.3& TO AUX.2
BLANKFORM TORRE.1&
BLANKFORM TORRE.2&
BLANKFORM TORRE.3&
MOVE ( DESTINO * 3 ) TO WINDOWINDEX
MOVE AUX.1 TO TORRE.1&
[~VER] MOVE "Û" TO TORRE.2&
[ VER] MOVE AUX.5 TO TORRE.2&
MOVE AUX.2 TO TORRE.3&
MOVE ( 1 + TORRE.64 ) TO TORRE.64
PAGE TORRE
RETURN
//****Rotinas auxiliares
ACHA_ORIGEM:
IF TORRE.65 EQ "A" MOVE 0 TO WINDOWINDEX
IF TORRE.65 EQ "B" MOVE 1 TO WINDOWINDEX
IF TORRE.65 EQ "C" MOVE 2 TO WINDOWINDEX
MOVE MATRIZ.1& TO VALOR_ORIGEM
WHILE MATRIZ.1& EQ 0
CALC ( WINDOWINDEX + 3 ) TO WINDOWINDEX
MOVE MATRIZ.1& TO VALOR_ORIGEM
LOOP
MOVE WINDOWINDEX TO ORIGEM
RETURN

ACHA_DESTINO:
IF TORRE.66 EQ "A" MOVE 18 TO WINDOWINDEX
IF TORRE.66 EQ "B" MOVE 19 TO WINDOWINDEX
IF TORRE.66 EQ "C" MOVE 20 TO WINDOWINDEX
MOVE 0 TO VALOR_DESTINO
WHILE MATRIZ.1& NE 0
MOVE MATRIZ.1& TO VALOR_DESTINO
CALC ( WINDOWINDEX - 3 ) TO WINDOWINDEX
LOOP
MOVE WINDOWINDEX TO DESTINO

RETURN
POE7:
MOVE WINDOWINDEX TO WIND
CALC ( WINDOWINDEX * 3 ) TO WINDOWINDEX
MOVE "ÛÛÛÛÛÛÛ" TO TORRE.1&
[~VER] MOVE "Û" TO TORRE.2&
[ VER] MOVE "7" TO TORRE.2&
MOVE "ÛÛÛÛÛÛÛ" TO TORRE.3&
MOVE WIND TO WINDOWINDEX
RETURN

POE6:
MOVE WINDOWINDEX TO WIND
CALC ( WINDOWINDEX * 3 ) TO WINDOWINDEX
MOVE " ÛÛÛÛÛÛ" TO TORRE.1&
[~VER] MOVE "Û" TO TORRE.2&
[ VER] MOVE "6" TO TORRE.2&
MOVE "ÛÛÛÛÛÛ " TO TORRE.3&
MOVE WIND TO WINDOWINDEX
RETURN

POE5:
MOVE WINDOWINDEX TO WIND
CALC ( WINDOWINDEX * 3 ) TO WINDOWINDEX
MOVE " ÛÛÛÛÛ" TO TORRE.1&
[~VER] MOVE "Û" TO TORRE.2&
[ VER] MOVE "5" TO TORRE.2&
MOVE "ÛÛÛÛÛ " TO TORRE.3&
MOVE WIND TO WINDOWINDEX
RETURN

POE4:
MOVE WINDOWINDEX TO WIND
CALC ( WINDOWINDEX * 3 ) TO WINDOWINDEX
MOVE " ÛÛÛÛ" TO TORRE.1&
[~VER] MOVE "Û" TO TORRE.2&
[ VER] MOVE "4" TO TORRE.2&
MOVE "ÛÛÛÛ " TO TORRE.3&
MOVE WIND TO WINDOWINDEX
RETURN

POE3:
MOVE WINDOWINDEX TO WIND
CALC ( WINDOWINDEX * 3 ) TO WINDOWINDEX
MOVE " ÛÛÛ" TO TORRE.1&
[~VER] MOVE "Û" TO TORRE.2&
[ VER] MOVE "3" TO TORRE.2&
MOVE "ÛÛÛ " TO TORRE.3&
MOVE WIND TO WINDOWINDEX
RETURN
POE2:
MOVE WINDOWINDEX TO WIND
CALC ( WINDOWINDEX * 3 ) TO WINDOWINDEX
MOVE " ÛÛ" TO TORRE.1&
[~VER] MOVE "Û" TO TORRE.2&
[ VER] MOVE "2" TO TORRE.2&
MOVE "ÛÛ " TO TORRE.3&
MOVE WIND TO WINDOWINDEX
RETURN
POE1:
MOVE WINDOWINDEX TO WIND
CALC ( WINDOWINDEX * 3 ) TO WINDOWINDEX
MOVE " Û" TO TORRE.1&
[~VER] MOVE "Û" TO TORRE.2&
[ VER] MOVE "1" TO TORRE.2&
MOVE "Û " TO TORRE.3&
MOVE WIND TO WINDOWINDEX
RETURN
//***********************************
//***JOGO FEITO POR PAULO MIRANDA ***
//***E-MAIL: PHBM@WEBCABLE.COM.BREste endereço de e-mail está protegido contra
spambots. Você deve habilitar o JavaScript para visualizá-lo. ***
//***********************************

Exemplo de um codigo usando a macro enter para fazer um cadastro. O arquivo deve ser salvo com a
extendão ".frm".
/TELA2
ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
ºº
º EMPRESA : __. º
ºº
º RAZAO : ________________________________________ º
ºº
º FANTASIA : ___________ º
ºº
º CGC : __________________ IE : ____________________ º
ºº
ºÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
ĺ
ºº
º ENDERECO : ________________________________________ º
ºº
º BAIRRO : _______________ º
ºº
º MUNICIPIO : ______________________ UF : __ º
ºº
º CEP : _________ º
ºº
ºÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
ĺ
ºº
º DDD : _____ FONE : __________ FAX : __________ º
ºº
º EMAIL : ______________________________ º
ºº
ºÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ
ĺ
ºº
º DATA CAD. : __/__/____ DT.ULT.ALT : __/__/____ º
ºº
ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
/RESP
_
/AUX
_____________. __________. ___0___.
/CEP
_______.
/TELAHELP
ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»
º TELA DE HELP º
ÌÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ͹
º <SHIFT+F4> Imprime <F5> -> Limpa Tela º
º <SHIFT+F2> Exclui <F2> -> Grava º
º <F8> Ä> Proximo Reg. <F7> -> Reg. Anterior º
ºº
ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ
/TELAIMP
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
Û ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ Û
Û ³ÛÛÛÛÛÛÛ MODO DE IMPRESSAO ÛÛÛÛÛÛ ³ Û
Û ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄ´ Û
Û ³ Codigo da Impressora ³ _. ³ Û
Û ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄ´ Û
Û ³ ______________________________ ³ Û
Û ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´ Û
Û ³ Formulario Ok? <___> <___> ³ Û
Û ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ Û
ÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛÛ
/*
//==========================[ INCLUSAO DE BIBLIOTECAS ]
=========================
#INCLUDE TITULO.INC
#INCLUDE BIBLIOTE.INC

//==========================[ ABERTURA DE ARQUIVOS ]


============================
OPEN "SCOLA24" AS SCOLA24 //==== EMPRESAS
OPEN "SCOLA23" AS SCOLA23 //==== CLIENTES
//==========================[ DEFINICAO DE VARIAVEIS ]
=========================
STRING NUMERO 1
INTEGER CONT
INDICATOR CEPOK EXISTE
//===========================[ PAGE SET DAS TELAS ]
============================
PAGE SET TELA2 AT 16 10 COLORS 14 15
PAGE SET RESP AT 54 55 COLORS 14 15
PAGE SET TELAHELP AT 20 14 COLORS 07 07
//===========================[ NOMES DA TELA ]============================
NAME TELA2 EMPRESA RAZAO_EMPRESA FANT_EMPRESA CNPJ IE ENDERECO BAIRRO
MUNICIPIO UF;
CEP_MASC DDD FONE FAX EMAIL DT_CAD DT_ULT_ALT

//===========================[ PROGRAMA PRINCIPAL ]


============================
TITULAR "PAULO - SCOLA24 - CADASTRO DE EMPRESAS"
ENTER SCOLA24

LB_ENTRA_TELA2:
BLANKFORM TELA2
MOVE "" TO RESP.1
CLEAR SCOLA24
ENTRY SCOLA24.EMPRESA EMPRESA {AUTOFIND}
[ ~FOUND] BLANKFORM TELA2.2 THRU TELA2.16
INDICATE EXISTE STATUS SCOLA24
ENTRY SCOLA24.RAZAO_EMPRESA RAZAO_EMPRESA {CAPSLOCK}
ENTRY SCOLA24.FANT_EMPRESA FANT_EMPRESA {CAPSLOCK}

LB_CGC:

INDICATE OK TRUE
ENTRY SCOLA24.CNPJ CNPJ
FOR CONT FROM 1 TO 18
MID CNPJ TO NUMERO 1 CONT
INDICATE OK AS NUMERO IN "0123456789 ./-"
[~OK] INDICATE OK AS NUMERO EQ ""

LOOP

[ OK ] CGC_CHECK CNPJ
[~OK ] BEGIN
MENSA "CARACTERES INVALIDOS NO CGC!!"
PAUSE ""
MENSA " "
END
[~OK ] GOTO LB_CGC
[~ERR] GOSUB LB_CNPJ_MASC
[ ERR ] BEGIN
MENSA "CGC INVALIDO,DIGITE OUTRA VEZ !!"
PAUSE ""
MENSA " "

END
[ ERR] GOTO LB_CGC

ENTRY SCOLA24.IE IE {CAPSLOCK}


ENTRY SCOLA24.ENDERECO ENDERECO {CAPSLOCK}
ENTRY SCOLA24.BAIRRO BAIRRO {CAPSLOCK}
ENTRY SCOLA24.MUNICIPIO MUNICIPIO {CAPSLOCK}
ENTRY SCOLA24.UF UF {CAPSLOCK}
ENTRY SCOLA24.CEP_MASC CEP_MASC {CAPSLOCK}
GOSUB LB_CEP_MASC
ENTRY SCOLA24.CEP CEP.1 {NOENTER}
ENTRY SCOLA24.DDD DDD {CAPSLOCK}
ENTRY SCOLA24.FONE FONE {CAPSLOCK}
ENTRY SCOLA24.FAX FAX {CAPSLOCK}
ENTRY SCOLA24.EMAIL EMAIL {CAPSLOCK}
[~EXISTE] SYSDATE DT_CAD
[ EXISTE] ENTRY SCOLA24.DT_CAD DT_CAD {NOENTER}
[ EXISTE] BEGIN
SYSDATE DT_ULT_ALT
IFCHANGE SCOLA24 ;
ENTRY SCOLA24.DT_ULT_ALT DT_ULT_ALT {NOENTER}
END

LB_CONFIRMA:
MENSA " DADOS CORRETOS S/N ? "
MOVE "S" TO RESP.1
ACCEPT RESP.1 {CAPSLOCK,CHECK="SN "}
MENSA " "
IF RESP.1 EQ "N" GOTO ENTRYSEC
RETURN

ENTEREND

ABORT

//===========================[ Teclas de Funcao ]==============================


KEYPROC KEY.HELP
PAGE TELAHELP
MENSA "AJUDA DO SISTEMA"
PAUSE ""
MENSA " "
ENTAGAIN
RETURN

KEYPROC KEY.ESCAPE
ABORT
KEYPROC KEY.SAVE
IF FONE EQ "" BEGIN
MENSA "NAO DEIXE CAMPOS EM BRANCO!"
PAUSE ""
MENSA " "
RETURN
END
RETURN LB_CONFIRMA
KEYPROC KEY.DELETE
MENSA "TECLA DE DELETAR DESATIVADA"
PAUSE ""
MENSA " "
RETURN
KEYPROC KEY.PRINT
MENSA "TECLA DE IMPRIMIR DESATIVADA"
PAUSE ""
MENSA " "
RETURN

//--------
//
LB_CNPJ_MASC:
REPLACE "." IN CNPJ WITH ""
REPLACE "." IN CNPJ WITH ""
REPLACE "/" IN CNPJ WITH ""
REPLACE "-" IN CNPJ WITH ""
PRINT CNPJ TO AUX.1 {FILL="0"}
MOVESTR AUX.1 TO CNPJ
INSERT "." IN CNPJ AT 3
INSERT "." IN CNPJ AT 7
INSERT "/" IN CNPJ AT 11
INSERT "-" IN CNPJ AT 16
RETURN

LB_CEP_MASC:

REPLACE "-" IN CEP_MASC WITH ""


PRINT CEP_MASC TO AUX.3
INDICATE CEPOK AS AUX.3 GE 100000
[CEPOK] INDICATE CEPOK AS AUX.3 LE 99999999
[CEPOK] MOVESTR AUX.3 TO CEP_MASC
[CEPOK] INSERT "-" IN CEP_MASC AT 06
RETURN
///==========================[ FIM DO PROGRAMA ]=========================

Esse exemplo usa a macro entergroup para a tela de selecao de dados do


relatorio e a macro report para imprimi-lo.
/RESP
_
/TELA

PARAMETROS DE SELE€ŽO

ÚÄÄÄÄÄÄÄÄÄÄÄÄ¿ ÚÄÄÄÄÄÄÄÄÄÄÄÄ¿
³³³³
Per¡odo ..........: ³ __/__/____ ³ at‚ ³ __/__/____ ³
³³³³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ

ÚÄÄÄÄÄÄÄÄÄÄÄÄ¿
³³
C¢digo do Produto : ³ _____. ³ ( <Enter> p/ Todos )
³³
ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ

80 COL.

/HEADER RESIDENT
ALAMAR Tecno Cient¡fico Ltda
|=========|====================================================|
==================|
| SCOLR8 | RELA€ŽO DE ENTRADA E SAIDA DOS | P gina: ___. |
|* BRUNO *| MATERIAIS DIVERSOS | __/__/____ __:__ |
|=========|====================================================|
==================|
|---------------------------------------------------------------+----------------------------------
+-------------------------------------|
||ENTRADA|SAIDA|
|CODIGO DESCRI€ŽO |----------------------------------|-------------------------------------|
| | N§ Ped. | Qtde. | Data | Dep. Dest. | Qtde. | Data |
|---------------------------------------------------------------|---------|---------|--------------|------------|---------|----
----------|
/BODY
|_____. _______________________________________________________| _____. | ____.__ |
__/__/____ | __________ | ____.__ | __/__/____ |
/TOTAL RESIDENT
||||||||
|
=========================================================================
===============================================================|
| T O T A I S .............................................. | | ____.__ | | | ____.__ | |
|
=========================================================================
===============================================================|
/*
//*************[ COMANDOS P/ CHAMAR A TELA ALAMAR E A PARTE GRAFICA ]******

GRAPHIC ON 3
#INCLUDE TITULO.INC
TITULAR "SCOLR8 - ENTRADA E SAIDA DOS MATERIAIS DIVERSOS"
//***************************************************************************
//*************[ ABERTURA DE ARQUIVOS ]************************************
OPEN "SCOLA18" AS SCOLA18 //---[ ENTRADA/SAIDA PRODUTOS ESTOQUE ]*
OPEN "SCOLA12" AS SCOLA12 //---[ MATERIAL DE ESCRITORIO ]*********
//***************************************************************************
//*************[ NOMES AS JANELAS DA TELA ]****************************
NAME TELA DATA_INI DATA_FIN CODIGO
//***************************************************************************
//*************[ PAGE DAS TELAS ]************************************
PAGE SET TELA AT 18 11 COLORS 31 112
PAGE SET RESP AT 54 50 COLORS 31 143
//***************************************************************************
//*************[ DEFINICAO DAS VARIAVEIS ]**************************
INDICATOR TODOS
//*************[ INICIO DA PROGRAMACAO ]***************************
//
LB_SELECAO:

ENTERGROUP

GOSUB LB_MONTA_TELA
SCREENMODE 31
GOTOXY 54 03
SHOW " "
BLANKFORM TELA
MOVE 0 TO PAGECOUNT
REPEAT
ACCEPT DATA_INI {RANGE=01/01/1900,31/12/2020}

GOTOXY 54 03
SHOW " "

ACCEPT DATA_FIN {RANGE=01/01/1900,31/12/2020}


IF DATA_FIN LT DATA_INI BEGIN
MENSA " A Data Final n„o Pode Ser Menor que a Data Inicial"
SHOW " "
END

UNTIL DATA_FIN GE DATA_INI


ENTRY SCOLA12.CODIGO CODIGO {AUTOFIND}
[ERR] SCREENMODE 31

IF CODIGO EQ 0 INDICATE TODOS TRUE


MENSA " Confirma Sele‡„o ? (S/N)"
MOVE "S" TO RESP.1
ACCEPT RESP.1 {CAPSLOCK,CHECK="SN"}
IF RESP.1 EQ "N" GOTO LB_SELECAO
CLEAR SCOLA18
MOVE DATA_INI TO SCOLA18.DTMOV
[~TODOS] MOVE CODIGO TO SCOLA18.COD_PROD
OUTFILE "LST:"
ENDGROUP //*********[ FIM DA ENTRADA DE DADOS ]***********
//*************[ INICIO DA MACRO REPORT ]**************************
REPORT SCOLA18 BY INDEX.2 BREAK SCOLA18.DTMOV
INDICATE SELECT AS SCOLA18.DTMOV GE DATA_INI
[ SELECT] INDICATE SELECT AS SCOLA18.DTMOV LE DATA_FIN
[~SELECT] RETURN END.OF.REPORT
[~TODOS ] INDICATE SELECT AS SCOLA18.COD_PROD EQ CODIGO

SECTION HEADER
PRINT PAGECOUNT TO HEADER.1
SYSDATE HEADER.2 HEADER.3 HEADER.4
IF HEADER.3 LT 10 INSERT "0" IN HEADER.3 AT 1
IF HEADER.4 LT 10 INSERT "0" IN HEADER.4 AT 1
OUTPUT HEADER

SECTION BODY

BLANKFORM BODY

PRINT SCOLA18.COD_PROD TO BODY.1


PRINT SCOLA12.DESCRICAO TO BODY.2

IF SCOLA18.TIPO_ES EQ "E" BEGIN


PRINT SCOLA18.NPED TO BODY.3
PRINT SCOLA18.QUANT TO BODY.4
PRINT SCOLA18.DTMOV TO BODY.5
END
IF SCOLA18.TIPO_ES EQ "S" BEGIN
PRINT SCOLA18.DEPTO_DEST TO BODY.6
PRINT SCOLA18.QUANT TO BODY.7
PRINT SCOLA18.DTMOV TO BODY.8
END

OUTPUT BODY
SECTION TOTAL
SUBTOTAL BODY.4 TO TOTAL.1
SUBTOTAL BODY.7 TO TOTAL.2
OUTPUT TOTAL
REPORTEND
FORMFEED
GOTO LB_SELECAO
ABORT
//*************[ FIM DA MACRO REPORT ]*****************************
//*************[ DEFINICAO DAS TECLAS DE FUNCAO ]****************
KEYPROC KEY.ESCAPE
GRAPHIC OFF
ABORT

KEYPROC KEY.CLEAR
BLANKFORM TELA
ENTAGAIN
RETURN LB_SELECAO
//*************[ FIM DA DEFINICAO DAS TECLAS DE FUNCAO ]*****
//*************[ SUB-ROTINAS USADAS NO PROGRAMA ]************************
//
LB_MONTA_TELA:
PAGE TELA

SET_LINE_STYLE 1 3
GRXY 134 665 // ESQUERDA E BAIXO
LINE 877 665 0 // DIREITA E BAIXO
LINE 877 298 0 // DIREITA E CIMA
LINE 134 298 15 // ESQUERDA E CIMA
LINE 134 665 15 // ESQUERDA E BAIXO
RETURN
//*************[ FIM DA PROGRAMACAO ]********************************

Você também pode gostar