É
fácil criar componentes
Por:
Dennes Tôrres de Oliveira - Dennes@infolink.com.br
Continuando a série sobre criação de componentes activex, vamos completar a criação do
componente nmcontrol.
FORMATANDO O NUNERO NA TEXBOX
Vamos agora criar o recurso de formatação do número contido na TextBox. A idéia é que quando a
TextBox perder o foco o número contido na TextBox seja formatado. Quando a TextBox ganhar o
foco a formatação deverá ser retirada para permitir a edição do número.
Este recurso está vinculado à propriedade Moeda, que determinará se deverá ou não ser utilizado
o formato monetário no número. Assim sendo, vamos primeiramente criar a propriedade Moeda. O
código ficará como abaixo :
Dim Vmoeda as boolean
Public Property Get Moeda() As Boolean
Moeda = Vmoeda
End Property
Public Property Let Moeda(ByVal vNewValue As Boolean)
Vmoeda = vNewValue
End Property
Desta forma a informação estará guardada na variável Vmoeda e devidamente encapsulada pela
propriedade Moeda.
Importante : Mesmo quando não existe validação alguma para ser realizada é importante manter o
encapsulamento, pois ele será muito útil no futuro quando você precisar dar manutenção a este
código.
Para completar a criação da propriedade precisamos alterar os eventos ReadProperties e
WriteProperties do UserControl. O novo código ficará como abaixo :
Private Sub UserControl_ReadProperties(PropBag As PropertyBag)
VcorAtiva = PropBag.ReadProperty("CorAtiva", &H80000005)
Vmoeda = PropBag.ReadProperty("Moeda", True)
End Sub
Private Sub UserControl_WriteProperties(PropBag As PropertyBag)
Call PropBag.WriteProperty("CorAtiva", VcorAtiva, &H80000005)
Call PropBag.WriteProperty("Moeda", True)
End Sub
O passo seguinte é programar os eventos LostFocus e GotFocus da caixa de texto de forma a
realizar a formatação do número. Assim sendo, o código ficará da seguinte forma :
Private Sub txtnum_GotFocus()
If txtnum.Text <> "" Then
txtnum.Text = CDbl(txtnum.Text)
End If
End Sub
Private Sub txtnum_LostFocus()
If Vmoeda Then
txtnum.Text = Format(txtnum.Text, "currency")
Else
txtnum.Text = Format(txtnum.Text, "standard")
End If
End Sub
Deve-se observar o teste feito no GotFocus : Se a caixa estiver vazia, a conversão devolveria
erro. Por isso foi feito o teste.
Observe também o teste pela variável Vmoeda na Sub LostFocus, que determina se a formatação
será em Currency ou Standard. A formatação seguirá as definições do painel de controle do
usuário.
TRATAMENTO DE ERROS EM COMPONENTES
É possível que o usuário cometa algum erro durante a digitação. Foi permitido ao usuário
digitar "." E ",". Se o usuário errar a digitação, inserindo pontos e vírgulas em excesso,
serão gerados erros na formatação e na conversão do valor, por isso ambas as Subs, tanto
GotFocus como LostFocus precisarão possuir um tratamento de erro.
O tratamento de erros em um componente difere um pouco do tratamento de erros convencional :
Evita-se ao máximo utilizar um MSGBOX no tratamento de erros de componentes. Isso porque quando
um erro ocorre, em geral o usuário do componente (que é um programador) deseja tratar esse erro
na sua aplicação, utilizando On Error. Uma MSGBOX exibida pelo componente pode se tornar um
grande inconveniente em alguns sistemas.
Desta forma, o que o componente faz quando detecta um erro é criar um objeto de erro e passá-lo
a quem o chamou. Se a rotina que chamou o componente estiver tratando o erro, ótimo, não é mais
responsabilidade do componente. Caso contrario o objeto de erro criado se encarregará de exibir
uma mensagem para o usuário.
Veja como ficará o código após a inclusão do tratamento de erro :
Private Sub txtnum_GotFocus()
On Error GoTo trataerro
If txtnum.Text <> "" Then
txtnum.Text = CDbl(txtnum.Text)
End If
Exit Sub
trataerro:
Err.Raise vbObjectError + 550, "NumControl", "Valor Inválido na caixa"
End Sub
Private Sub txtnum_LostFocus()
On Error GoTo trataerro
If Vmoeda Then
txtnum.Text = Format(txtnum.Text, "currency")
Else
txtnum.Text = Format(txtnum.Text, "standard")
End If
Exit Sub
trataerro:
Err.Raise vbObjectError + 550, "NumControl", "Valor Inválido na caixa"
End Sub
Observe a forma como o Err.Raise foi utilizado :
· O 1o parâmetro é o número do erro. Ao 1o parâmetro foi adicionada a constante
VBObjectError. Isso garante que o número do erro não irá colidir com um erro já existente no
VB. Mas só isso não basta : é necessário que o número de erro do componente esteja entre 512 e
65.535, caso contrário colidirá com algum outro erro do sistema. Neste caso, foi escolhido
aleatoriamente o valor de 550.
· O 2o parâmetro indica quem gerou o erro, no caso, o componente.
· O 3o parâmetro indica a mensagem de erro que será gerada.
Vamos agora criar a propriedade Value. Primeiramente faremos o Property Let. O Property Let
deverá receber o valor do usuário na forma de um número e atribui-lo à caixa de texto. O código
ficará como abaixo :
Public Property Let Value(ByVal vNewValue As Double)
txtnum.Text = vNewValue
End Property
Observe que este código está confiando no recurso de autoconversão de valores do VB para
converter a variável Double para String.
Já o PropertyGet fará o inverso, entregará o valor contigo na caixa de texto. Porém no Property
Get teremos que nos prevenir quanto a possibilidade da caixa estar vazia. O código ficará como
abaixo :
Public Property Get Value() As Variant
If txtnum.text<>""
Value = txtnum.Text
Else
Value=0
End if
End Property
Novamente estamos confiando na autoconversão do VB para que tudo funcione corretamente. Esse
código, porém, precisará de um tratamento de erro. Ficará como abaixo :
Public Property Get Value() As Double
On Error GoTo trataerro
If txtnum.text<>""
Value = txtnum.Text
Else
Value=0
End if
Exit Property
trataerro:
Err.Raise vbObjectError + 550, "NumControl", "Valor Inválido na caixa"
End Property
Public Property Let Value(ByVal vNewValue As Double)
On Error GoTo trataerro
txtnum.Text = vNewValue
Exit Property
trataerro:
Err.Raise vbObjectError + 550, "NumControl", "Valor Inválido na caixa"
End Property
Com a propriedade Value temos um exemplo de propriedade que não mantém seu valor diretamente em
uma variável, mas utiliza algum tipo de calculo quando o valor é gravado ou recuperado. No
nosso caso, o "cálculo" foi simplesmente a autoconversão do VB.
UTILIZANDO O ACTIVEX CONTROL INTERFACE WIZARD
Precisamos criar agora as propriedades Font, BackColor e ForeColor. São propriedades da TextBox
que precisarão ser recriadas no nosso componente. O trabalho delas no nosso componente será
apenas receber a informação do usuário e passá-la para a propriedade da TextBox e vice-versa.
Esse trabalho é um trabalho muito manual e chato, por isso foi criado um Wizard para nos ajudar
: O ActiveX Control Interface Wizard.
Para ativar este Add-In devemos utilizar o menu Add-Ins (original, não?). Caso ele não esteja
listado no menu devemos inclui-lo através da tela Add-In Manager.
A 1a tela do Wizard é apenas descritiva, clicamos Next.
Na 2a tela o Wizard nos pede para escolher a partir de uma lista das propriedades mais comuns
quais delas desejaremos em nosso componente. No lado direito da tela você observará várias
propriedades já incluidas para você. Se não desejar alguma delas, deverá retira-la.
No nosso caso específico deixaremos do lado direito da tela apenas as propriedades Font,
BackColor e ForeColor e clicaremos em Next.
Nesta 3a tela o Wizard nos pergunta quais serão as propriedades personalizadas (custom), ou
seja, as propriedades criadas apenas para o nosso componente e não derivadas dos componentes
internos como são Font, Backcolor e ForeColor.
Como já criamos propriedades no projeto, o Wizard já mostrará as 3 propriedades que criamos :
CorAtiva, Value e Moeda. Criamos estas propriedades sem utilizar o Wizard para que ficasse
claro como funciona a codificação, mas das próximas vezes vocês poderão fazer boa parte do
trabalho pelo Wizard.
Na tela seguinte o Wizard nos pede para fazer o mapeamento das nossas propriedades, ou seja,
indicar a qual propriedade dos componentes internos elas estarão vinculadas. Por exemplo, a
propriedade Font do nosso componente estará vinculada à propriedade Font da TextBox. Essa
vinculação deve ser feita para as 3 propriedades : Font, BackColor e ForeColor.
Após clicar em Next o Wizard nos perguntará quais as características das propriedades que não
estão vinculadas a componente algum, no caso, Moeda, Value e CorAtiva. Já fizemos quase tudo
pela janela de código, portanto no Wizard só nos resta criar a descrição para as propriedades.
Atribuir uma descrição é importante pois esta descrição aparecerá na parte inferior da janela
de propriedades quando algum programador estiver utilizando o nosso componente.
Enfim, finalizamos a montagem das propriedades, podemos clicar Finish no Wizard e ele montará o
código para nós.
Vocês poderão observar com facilidade o código que o Wizard criou : Além de criar
as Subs Let/Get/Set, ele inseriu também o código necessário dentro do ReadProperties e
Write Properties.
Por fim, falta acrescentarmos apenas uma funcionalidade ao nosso componente : Executar a
troca de cor quando a caixa ganhar ou perder o foco.
Quando a caixa ganhar o foco, a cor de fundo dela será trocada. Assim sendo precisaremos
de uma variável na qual possamos guardar a cor de fundo original da caixa. Chamaremos esta
variável de CorFundo. A instrução ficará na área de declarações do componente :
Dim CorFundo as Ole_Color
Após isso devemos alterar o código dos eventos gotfocus e lostfocus da caixa de texto de
forma a que executem a troca de cores. O código ficará como abaixo :
Private Sub txtnum_GotFocus()
On Error GoTo trataerro
If txtnum.Text <> "" Then
txtnum.Text = CDbl(txtnum.Text)
End If
CorFundo = txtnum.BackColor
txtnum.BackColor = VcorAtiva
Exit Sub
trataerro:
Err.Raise vbObjectError + 550, "NumControl", "Valor Inválido na caixa"
End Sub
Private Sub txtnum_LostFocus()
On Error GoTo trataerro
If Vmoeda Then
txtnum.Text = Format(txtnum.Text, "currency")
Else
txtnum.Text = Format(txtnum.Text, "standard")
End If
txtnum.BackColor = CorFundo
Exit Sub
trataerro:
Err.Raise vbObjectError + 550, "NumControl", "Valor Inválido na caixa"
End Sub
Agora só está faltando o retoque final : Fazer com que nosso componente possa ser
vinculado a um campo de um banco de dados através das propriedades DataSource e DataField.
Fazer essa vinculação é mais simples do que pode parecer. Precisamos selecionar qual das
propriedades do componente será gravada no banco de dados e isso é tarefa fácil : será a
propriedade Value.
Tendo escolhido a propriedade, devemos utilizar o menu Tools->Procedure Attributes. Caso
este menu esteja desativado posicione o cursor dentro de uma Sub na janela de código ou
posicione o cursor na área de criação do componente.
Na janela Procedure Attributes devemos selecionar a propriedade Value e clicar no botão
Advanced.
Tornaremos esta propriedade uma propriedade DataBound marcando a opção
"Property is Data Bound". Devemos também marcar a opção "This property bind to DataField",
para indicar que o valor desta propriedade estará vinculado ao campo apontado em DataField.
Podemos aproveitar que estamos nesta tela e alterar a caixa ProcedureId da propriedade Value,
selecionando o valor "(Default)". Isso fará com que a propriedade Value torne-se a propriedade
default do componente NumControl.
TESTANDO O COMPONENTE
Vamos enfim testar o nosso componente. Para isso precisaremos adicionar um projeto Standard
no Vb de forma a fazer um grupo de projetos. Utilize File->Add Project para isso.
Poderemos então inserir vários NumControls no form do projeto Standard para testarmos os
NumControls. Você lembra que só conseguirá fazer isso caso o área de criação do componente
esteja fechada, não é ? Confira isso no menu Window.
Depois de inserir vários NumControls no projeto Standard e executar o projeto você observará
que o ENTER terá o mesmo efeito do TAB, conforme nós programamos no NumControl. Já poderá
também observar o efeito da propriedade CorAtiva, que irá alterar a cor do componente sempre
que ele receber o foco.
Experimente alterar o valor da propriedade moeda e veja o componente formatando o número
que você digitar.
Por fim, vincule o componente a um campo de uma tabela e verifique a exibição dos dados.
© Búfalo Informática,
Treinamento e Consultoria -
Rua Álvaro Alvim, 37 Sala 920 - Cinelândia - Rio de Janeiro / RJ
Tel.: (21)2262-1368 (21) 9240-5134 (21) 9240-7281 e-Mail: contato@bufaloinfo.com.br