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' }