Título: Criando Um VCL
Linguagem: C++Builder
S.O.: Windows
Autor(es): Wenderson Teixeira
Se não me falha a memória, VCL significa Visual Components
Library, e vou tentar explicar como se cria o que eu acho ser
o mais simples dos Componentes, o componente não visual.
Criar um VCL requer um bom conhecimento da linguagem C/C++, pois
normalmente, eles fazem todo o trabalho sujo, deixando para quem
faz o programa a parte fácil da coisa, um bom exemplo, seria um
VCL que realiza buscas no seu HD e retorna uma lista de arquivos
encontrados, por exemplo, dá um trabalho razoável implementar uma
busca recursiva diretório por diretório, arquivo por arquivo,
conferindo e salvando em uma lista todos os possíveis candidatos,
no entanto o que o programa principal teria que fazer, no final
das contas, seria apenas chamar uma ou duas rotinas e pronto,
vc já teria a lista somente para ser visualizada.
Uma das vantagens desse tipo de recurso, é que ele tira do
programa final, toda aquela sujeira e complicação proveniente
de códigos que não dizem respeito à aplicação propriamente dita,
permitindo também a tão falada e prometida reusabibalidade da
orientação à objetos.
Chega de papo e vamos por as mãos na massa, vamos criar um VCL que
converte valores em string por extenso, como faz um preenchedor de
cheques automático.
__published:
de sua classe e deve estar definido como __property,
o acesso a esse tipo de variável é feito através das keywords 'read'
and 'write', onde se atribui uma variável ou uma função que será
responsável pela atualização daquela propriedade.
__published:
__property double Value = { read = FValue, write = SetValue };
Para que tudo funcione como esperado deve-se adicionar o código
pertinente à atualização da propriedade Value,
na função SetValue, FValue
servirá basicamente para manter uma cópia de Value
interna à classe, e que será usada para fazer as conversões.
Muitos de vocês já devem ter feito esse tipo de algorítmo de
conversão antes, pois é uma tarefa muito comum em programação, e
que costuma-se aprender como um exercício de escola, por isso não
vou entrar em detalhes no algorítmo.
Para finalizar, crie um Bitmap com o nome do seu VCL, TEXTENSO no
nosso caso e inclua-o no projeto, pode-se utilizar qualquer editor
que produza um arquivo de recursos, como por exemplo o Image Editor
que vem com o Builder, no entanto, este, só produz .RES (arquivos de
recurso binários) e não ficaria muito bem publicá-los aqui, por isso
eu utilizei o Borland C++ 5.0, que pode produzir .RC (arquivos de
recurso texto), este bitmap é o que aparecerá na paleta de componentes
do Builder, se você não fonecer um o Builder coloca um default.
//---------------------------------------------------------------------------
#ifndef ExtensoH
#define ExtensoH
//---------------------------------------------------------------------------
#include <vcl\SysUtils.hpp>
#include <vcl\Controls.hpp>
#include <vcl\Classes.hpp>
#include <vcl\Forms.hpp>
//---------------------------------------------------------------------------
class TExtenso : public TComponent
{
private:
protected:
double FValue;
AnsiString FText;
AnsiString empty;
AnsiString space;
AnsiString e;
AnsiString de;
AnsiString virg;
void __fastcall SetValue(double _value);
void __fastcall Convert();
AnsiString __fastcall Translate(int _value);
public:
__fastcall TExtenso(TComponent* Owner);
const AnsiString & __fastcall GetText();
__published:
__property double Value = {read=FValue, write=SetValue};
__property AnsiString Text = {read=GetText};
};
//---------------------------------------------------------------------------
#endif
//---------------------------------------------------------------------------
#include <vcl\vcl.h>
#pragma hdrstop
#include "Extenso.h"
//---------------------------------------------------------------------------
const char *Unidades[] =
{
"Zero", "Um", "Dois", "Três", "Quatro", "Cinco", "Seis", "Sete", "Oito",
"Nove", "Dez", "Onze", "Doze", "Treze", "Quatorze", "Quinze",
"Dezesseis", "Dezessete", "Dezoito", "Dezenove"
};
const char *Dezenas[] =
{
"", "Dez", "Vinte", "Trinta", "Quarenta", "Cinquenta", "Sessenta",
"Setenta", "Oitenta", "Noventa"
};
const char *Centenas[] =
{
"Cem", "Cento", "Duzentos", "Trezentos", "Quatrocentos", "Quinhentos",
"Seiscentos", "Setecentos", "Oitocentos", "Novecentos"
};
const char *Multi[] =
{
"", "Mil", "Milhão", "Bilhão"
};
const char *MultiPlural[] =
{
"", "Mil", "Milhões", "Bilhões"
};
const char *Separador[] =
{
"", " ", " e ", " de ", ", "
};
const char *NomeUnidade[] =
{
"Real", "Centavo"
};
const char *NomeUnidadePlural[] =
{
"Reais", "Centavos"
};
static inline TExtenso *ValidCtrCheck()
{
return new TExtenso(NULL);
}
//---------------------------------------------------------------------------
__fastcall TExtenso::TExtenso(TComponent* Owner)
: TComponent(Owner)
{
//value = 0;
empty = Separador[0];
space = Separador[1];
e = Separador[2];
de = Separador[3];
virg = Separador[4];
}
//---------------------------------------------------------------------------
namespace Extenso
{
void __fastcall Register()
{
TComponentClass classes[1] = {__classid(TExtenso)};
RegisterComponents("Additional", classes, 0);
}
}
//---------------------------------------------------------------------------
void __fastcall TExtenso::SetValue(double _value)
{
FValue = _value;
GetText();
}
const AnsiString & __fastcall TExtenso::GetText()
{
Convert();
return FText;
}
void __fastcall TExtenso::Convert()
{
if(!FValue)
{
FText = Unidades[0];
return;
}
long intPart = (long)FValue;
char str[20];
sprintf(str, "%.2lf", FValue);
char *pNum = strchr(str, '.');
long floatPart = pNum ? atol(pNum + 1) : 0;
const char **pNomeUnidade = (intPart == 1 ? NomeUnidade : NomeUnidadePlural);
double e0 = intPart % 1000;
double e3 = (long)(intPart / 1000) % 1000;
double e6 = (long)(intPart / 1E6) % 1000;
double e9 = (long)(intPart / 1E9) % 1000;
AnsiString e0Str = (e0 ? Translate(e0) : empty);
AnsiString e3Str = (e3 ? Translate(e3) + space + Multi[1] : empty);
AnsiString e6Str = (e6 ? Translate(e6) + space + (e6 == 1 ? Multi[2] : MultiPlural[2]) : empty);
AnsiString e9Str = (e9 ? Translate(e9) + space + (e9 == 1 ? Multi[3] : MultiPlural[3]) : empty);
FText = e9Str;
FText += (FText.Length() && e6Str.Length() ? virg + e6Str : e6Str);
FText += (FText.Length() && e3Str.Length() ? virg + e3Str : e3Str);
FText += (FText.Length() && e0Str.Length() ? e + e0Str : e0Str);
FText += ((e9 || e6) && !(e3 || e0) ? de : space) + pNomeUnidade[0];
pNomeUnidade = (floatPart == 1 ? NomeUnidade : NomeUnidadePlural);
FText += floatPart ? (e + Translate(floatPart) + space + pNomeUnidade[1]) : empty;
}
AnsiString __fastcall TExtenso::Translate(int _value)
{
AnsiString str;
int centena = (_value % 1000) / 100;
int dezena = _value % 100;
int unidade = (dezena < 20) ? dezena : dezena % 10;
dezena /= 10;
if(unidade)
str = Unidades[unidade];
if(dezena >= 2)
str = Dezenas[dezena] + (unidade ? e + str : empty);
if(centena == 1 && !dezena && !unidade)
str = Centenas[0];
else if(centena)
str = Centenas[centena] + ((dezena || unidade) ? e + str : empty);
return str;
}
/****************************************************************************
Extenso.RC
produced by Borland Resource Workshop
*****************************************************************************/
LANGUAGE LANG_ENGLISH,SUBLANG_ENGLISH_US
TEXTENSO BITMAP LOADONCALL MOVEABLE DISCARDABLE IMPURE
{
'42 4D 96 01 00 00 00 00 00 00 76 00 00 00 28 00'
'00 00 18 00 00 00 18 00 00 00 01 00 04 00 00 00'
'00 00 20 01 00 00 00 00 00 00 00 00 00 00 00 00'
'00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 80'
'00 00 00 80 80 00 80 00 00 00 80 00 80 00 80 80'
'00 00 C0 C0 C0 00 80 80 80 00 00 00 FF 00 00 FF'
'00 00 00 FF FF 00 FF 00 00 00 FF 00 FF 00 FF FF'
'00 00 FF FF FF 00 33 33 33 33 33 33 33 33 33 33'
'33 33 33 33 31 99 93 19 19 19 19 19 19 33 33 33'
'19 33 19 19 19 19 33 33 33 33 33 33 19 33 19 19'
'19 19 33 33 33 33 33 33 19 33 19 19 99 93 33 33'
'33 33 33 33 19 33 19 33 33 33 33 33 33 33 33 33'
'19 33 19 33 33 33 33 33 33 33 33 33 33 33 33 33'
'33 33 33 33 33 33 33 33 33 33 33 33 23 33 33 33'
'33 33 33 33 33 33 33 31 22 33 33 33 33 33 33 33'
'33 33 33 12 22 23 33 33 33 33 33 33 33 33 33 31'
'22 33 33 33 33 33 33 33 33 33 33 31 22 33 33 33'
'33 33 33 33 33 33 33 12 22 13 33 33 33 33 33 33'
'33 33 33 31 21 33 33 33 33 33 33 33 33 33 33 33'
'13 33 33 33 33 33 33 33 33 33 33 33 33 33 33 33'
'33 33 33 33 33 31 C3 1C CC C3 1C C3 33 33 33 33'
'33 31 C3 1C 33 31 C3 1C 33 33 33 33 33 31 C3 31'
'CC 33 33 1C 33 33 33 33 33 31 C3 33 31 C3 31 C3'
'33 33 33 33 33 1C C3 1C 31 C1 C3 1C 33 33 33 33'
'33 31 C3 31 CC 33 1C C3 33 33 33 33 33 33 33 33'
'33 33 33 33 33 33'
}