A transparência é a capacidade de ser transparente, ou seja, de permitir ver através, neste caso, do objecto. Esta transparência permite criar formulários que deixam ver através dele, que abrem com um efeito fade in (começar a aparecer até ficar opaco) ou fade out (do opaco ao invisível). Estas são algumas aplicações possíveis, que para além de um efeito bonito, melhoram o visual da aplicação.
O design de uma aplicação é muito importante e o seu sucesso pode também ser o sucesso da aplicação. Uma aplicação por muito boa que esteja (funcional), dificilmente vende ou convence se não tiver um bom design.
O VB.NET já inclui esta propriedade nos Forms mas o VB6 não e para a criarmos necessitamos de recorrer a alguns API’s. O API que permite este efeito é o SetLayeredWindowAttributes() embora se utilizem outros auxiliares, como é o caso das funções GetWindowLong() e SetWindowLong().
Para tornarmos um form transparente necessitamos do seguinte código (embora apenas seja usado o Sub MakeTransparent() e não o MakeOpaque() que “apenas” transforma o form em opaco):
No módulo:
' Declaração de API's necessários
Private Declare Function SetLayeredWindowAttributes Lib "user32" (ByVal hWnd As Long, ByVal crKey As Long, ByVal bAlpha As Byte, ByVal dwFlags As Long) As Long
Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
' Definição de constantes
Private Const GWL_EXSTYLE = (-20)
Private Const LWA_COLORKEY = &H1
Private Const LWA_ALPHA = &H2
Private Const ULW_COLORKEY = &H1
Private Const ULW_ALPHA = &H2
Private Const ULW_OPAQUE = &H4
Private Const WS_EX_LAYERED = &H80000
' Define o Form como transparente
Public Sub MakeTransparent(ByVal hWnd As Long, ByVal bAlpha As Integer)
Dim msg As Long
' Ignora possíveis erros
On Error Resume Next
' Caso o valor seja inferior a 255 e superior
' a 0 aplica uma nova transparência
If bAlpha > 0 Or bAlpha < 255 Then
msg = GetWindowLong(hWnd, GWL_EXSTYLE)
msg = msg Or WS_EX_LAYERED
SetWindowLong hWnd, GWL_EXSTYLE, msg
SetLayeredWindowAttributes hWnd, 0, bAlpha, LWA_ALPHA
End If
End Sub
' Define o form com opaco
Public Sub MakeOpaque(ByVal hWnd As Long)
Dim msg As Long
' Ignora possíveis erros
On Error Resume Next
msg = GetWindowLong(hWnd, GWL_EXSTYLE)
msg = msg And Not WS_EX_LAYERED
SetWindowLong hWnd, GWL_EXSTYLE, msg
SetLayeredWindowAttributes hWnd, 0, 0, LWA_ALPHA
End Sub
Depois, na inicialização do Form:
Private Sub Form_Initialize()
MakeTransparent Me.hWnd, 150
End Sub
O valor a indicar pode variar entre 0 e 255, onde 0 é o máximo de transparência.
Este exemplo mostra como iniciar um Form transparente, mas pode-se criar um efeito mais interessante onde o Form começa a aparecer até ficar opaco – fade in. Para criar este efeito é apenas necessário adicionar um Timer ao Form e utilizar o seguinte código:
' Variável que irá guardar o valor da transparência
Private i As Integer
' Inicializa o form como transparente
Private Sub Form_Initialize()
MakeTransparent(Me.hWnd, 0)
End Sub
' No intervalo definido
Private Sub Timer1_Timer()
' Incrementa o valor da transparência
i = i + 10
' Caso não tenha atingido 255 define nova
' transparência, caso contrário pára o timer
If i <= 255 Then
MakeTransparent(Me.hWnd, i)
Else
Timer1.Enabled = False
End If
End Sub
' Definição do intervalo do timer e inicialização
Private Sub Form_Load()
Timer1.Interval = 100
Timer1.Enabled = True
End Sub
Outra das aplicações que esta função permite, com umas pequenas alterações, é dizer que apenas uma cor ficará transparente. Ora isto permite colocar um controlo dentro do form e dizer que este é transparente criando uma janela ou um formato diferente.
Um exemplo engraçado para mostrar a sua implementação é criar algo parecido com um queijo. É apenas necessário colocar umas shapes no Form, formatá-las e definir no Form BorderStyle = None. Depois o código:
Private Sub Form_Load()
Dim ctrl As Control
' Definição de todas as shapes do Form com o fundo a
' verde, estilo opaco e com os limites a transparente
For Each ctrl In Me.Controls
If TypeOf ctrl Is Shape Then
ctrl.BackStyle = 1
ctrl.BackColor = vbGreen
ctrl.BorderStyle = 0
End If
Next
' Chamar a função que irá colocar
' tudo o que é verde como transparente
MakeTransparent Me.hWnd, 0
End Sub
Finalmente no Sub MakeTransparent() alterar a seguinte linha, de modo a transformar tudo o que está a verde (vbGreen) em invisível.
De:
SetLayeredWindowAttributes hWnd, 0, bAlpha, LWA_ALPHA
Para:
SetLayeredWindowAttributes hWnd, vbGreen, bAlpha, LWA_COLORKEY
São pequenos exemplos de como usar a transparência nos Forms e como criar alguns efeitos interessantes.
PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!
O namespace System.Collections.Generic
contém um conjunto de interfaces e classes que permitem criar colecções muito seguras,
simples de utilizar e com muitos bons performances. Estas colecções de Generics
são do tipo strongly typed, ou seja,
estão disponíveis no intelissense e verificadas
pelo compilador, o que evita erros e torna mais fácil a vida ao programador.
Existem diversos tipos de colecções
neste ou em outros namespaces (como por exemplo o Dictionary, SortedList, ArrayList,
etc) mas um muito utilizado é o List(Of (T)), onde se define o tipo da colecção
que se pretende.
Um exemplo simples de utilização:
' Cria uma nova lista
do tipo "string"
Dim
lstEmpreg As New
List(Of String)
' Adiciona alguns nomes
à lista
lstEmpreg.Add("João Paulo")
lstEmpreg.Add("Pedro
Sousa")
lstEmpreg.Add("Luís Nascimento")
lstEmpreg.Add("Carlos
Sousa")
lstEmpreg.Add("Nuno Luís")
Dim nomePesquisar
As String = "Pedro Sousa"
' Caso o nome a pesquisar
seja encontrado
If lstEmpreg.Contains(nomePesquisar)
Then
' Mostra
o nome e o total de nomes na lista
Dim
msg As String
= "O nome {0} foi encontrado em {1} nome(s)"
Debug.WriteLine(String.Format(msg,
nomePesquisar, lstEmpreg.Count))
Else
' Mensagem
caso não encontre o nome na lista
Debug.WriteLine("Nome
não encontrado na lista!")
End
If
Mas esta colecção
pode ser muito mais complexa, sendo necessário guardar vários dados (para além do
nome), como por exemplo o número, idade, telefone, etc. Neste caso será criada uma
estrutura e guardada na lista.
O método de pesquisa
implementa um IEquatable
e utiliza um Predicate.
Desta forma não é necessário percorrer todos os items da lista para verificar qual
o item correspondente.
Um exemplo de utilização
Construção de uma
classe simples, sem utilização de propriedades
(get/set), que implementa o IEquatable (apenas para demonstração):
Exemplo:
'
Construção de uma classe simples, sem utilização de
‘
propriedades (get/set) que implementa o IEquatable
Public
Class Empregado
Implements
IEquatable(Of Empregado)
'
Campos da classe
Public ID
As Byte
Public Nome
As String
Public Idade
As Byte
Public
Function ProcuraEmpregado(ByVal EmpID
As Empregado) _
As
Boolean Implements
System.IEquatable(Of Empregado).Equals
' Retorna o ID mas poderá ser utilizado outro campo
' para pesquisa, sendo
apenas necessário altera para
' o campo correctos (ex.
Me.Nome = EmpID.Nome)
Return Me.ID
= EmpID.ID
End
Function
End
Class
Utilização da List(Of
T) que neste caso adiciona alguns empregados e pesquisa por um campo mostrando os
resultados. O campo escolhido para o exemplo foi o ID mas pode-se pesquisar por
qualquer campo.
' Cria uma nova lista
do tipo "Empregado"
Dim lstEmpregados
As New List(Of Empregado)
' Adiciona empregados à lista
Dim Emp1 As New Empregado
Emp1.ID = 1
Emp1.Nome = "João Paulo"
Emp1.Idade = 28
lstEmpregados.Add(Emp1)
Dim Emp2 As New Empregado
Emp2.ID = 2
Emp2.Nome = "Pedro Sousa"
Emp2.Idade = 25
lstEmpregados.Add(Emp2)
Dim Emp3 As New Empregado
Emp3.ID = 3
Emp3.Nome = "Luís Nascimento"
Emp3.Idade = 41
lstEmpregados.Add(Emp3)
' Empregado a procurar
na lista
Dim Emp As New Empregado
Emp.ID = 2
' Guarda o resultado da
procura na variável EmpResult
Dim EmpResult
As Empregado
' Pesquisa na lista de
empregados usando um Predicate do tipo empregado
EmpResult = lstEmpregados.Find(New
System.Predicate(Of Empregado)(AddressOf
Emp.ProcuraEmpregado))
' Caso tenha encontrado
mostra os resultados ou a mensagem de erro
If
EmpResult IsNot Nothing
Then
Debug.WriteLine("Número: "
& EmpResult.ID.ToString)
Debug.WriteLine("Empregado: " & EmpResult.Nome.ToString)
Debug.WriteLine("Idade:
" & EmpResult.Idade.ToString)
Else
Debug.WriteLine("Número
de empregado não encontrado")
End
If
Resultado:
Número: 2
Empregado: Pedro Sousa
Idade: 25
As colecções foram completamente revolucionadas
com a versão .NET e a sua utilização vem melhorar o que, no passado com o VB6, se
fazia apenas com as Collections (muito limitadas) ou com a utilização de arrays.
São bastante simples de utilizar e
é recomendável que se verifique qual a colecção que mais se adequa às necessidades
no programa.
PS: Como sempre, qualquer dúvida,
comentário ou correcção ao artigo é sempre bem vinda!
Unhandled Exceptions
Uma boa parte do código é dedicada (ou deveria ser) para tratamento de erros, previstos ou imprevistos, de modo a mostrar ao utilizador final uma mensagem adequada a todo o tipo de situações. O normal é mostrar uma mensagem de erro mas há também quem a registe para análise, envie via e-mail, etc, etc.
No entanto existem sempre zonas do código “esquecidas” e erros que não estão previstos, por muito cuidado que se tenha e por muitas situações que se contemple.
É sempre incómodo e pouco profissional mostrar ao utilizador uma mensagem não personalizada quando ocorre um erro ou que, a aplicação encerre inexplicavelmente.
Para simplificar a vida ao programador, o Visual Studio.NET dispõe de eventos a nível da aplicação (e não específicos para um único form ou objecto) que incluem os eventos Startup, Shutdown, StartupNextInstance, NetworkAvailabilityChanged e UnhandledException (excepções não controladas). Desta forma consegue-se controlar facilmente alguns eventos gerais.
Neste exemplo será ainda mostrado como aceder a estes eventos (Visual Basic Application Model), apenas o UnhandledException, e registar no Event Log do Windows a mensagem gerada. Para implementar este exemplo seguir os seguintes passos:
1 – Menu Poject – Properties – e na Application Tab clicar no botão View Application Events;
2 – Na dropdownlist das classes seleccionar MyApplication Events
3 – Na dropdownlist dos métodos seleccionar UnhandledException
Isto irá originar um novo Sub chamado "MyApplication_UnhandledException" e também alguns comentários com informação sobre os métodos disponíveis. Finalmente utilizar o seguinte código:
Namespace My
Partial Friend Class MyApplication
Private Sub MyApplication_UnhandledException(ByVal sender As Object, ByVal e As Microsoft.VisualBasic.ApplicationServices.UnhandledExceptionEventArgs)
Handles Me.UnhandledException
' Verifica o nome da aplicação
Dim AppName As String = My.Application.Info.Title
' Define o nome do grupo a criar no event log
Dim LogName As String = AppName & "LOG"
' Cria um nova instância do EventLog
Dim log As New EventLog()
' Caso o grupo não exista, cria um novo
If Not EventLog.SourceExists(AppName) Then
EventLog.CreateEventSource(AppName, LogName)
End If
' Define o nome da fonte do log
log.Source = AppName
' Define a mensagem e escreve no ficheiro
Dim msg As String = "Ocorreu uma erro no programa." & vbCrLf & _
vbCrLf & e.Exception.Message
log.WriteEntry(msg, System.Diagnostics.EventLogEntryType.Error)
log.Dispose()
' Mosta a mensagem ao utilizador
MessageBox.Show(msg)
' Define que a aplicação não termina
e.ExitApplication = False
End Sub
End Class
End Namespace
Finalmente para testar é só executar algo do género, associado a um botão ou outro evento:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim a As Byte = 50
Dim b As Byte = 50
Dim c As Byte = a * b
End Sub
Como o Byte suporta valores numéricos de 0 a 255, e o resultado desta operação é 2500, irá originar um excepção ou erro.
NOTA: Como o Visual Studio mostra o erro, seleccionando a linha, não é possível testar este código em modo de debug (teste) mas apenas em runtime (execução).
Passar informação entre Forms
Uma dúvida frequente é a forma como passar informação entre forms. Existem diversas formas de o fazer, umas mais correctas do que outras, devido a inúmeros factores. No entanto algumas são mais “recomendadas” porque não utilizam variáveis globais/públicas em módulos ou classes. Ficam dois exemplos de como se pode fazer:
#Método 1 – Enviar / Receber
Primeiro Form (master) que irá passar uma variável e receber outra através de uma nova propriedade criada:
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
' Criação de uma nova instância
Dim frm As New frmChild
' Atribuição de um valor à propriedade
frm.myString = "vbtuga - teste"
' Mostra o frm como dialog, ou seja o resto do código
' só irá executar-se quando este for fechado
frm.ShowDialog()
' Mostra a nova mensagem
MessageBox.Show(frm.myString)
End Sub
Segundo Form (child) onde é criada uma propriedade e retornado um novo valor
' Variável auxiliar da propriedade
Private _myString As String
' Criação de uma propriedade que pode passar informação
' em ambos os sentidos (master->child, child->master)
Public Property myString() As String
Set(ByVal value As String)
_myString = value
End Set
Get
Return _myString
End Get
End Property
Private Sub frmChild_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
' Exibição da mensagem
MessageBox.Show(Me.myString)
' Definição de novo texto da propriedade
Me.myString = "Nova string"
End Sub
#Método 2 – Enviar
Primeiro Form (master) que irá passar uma variável:
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
' Criação de uma nova instância e define o texto como parâmetro
Dim frm As New frmChild("vbtuga - teste")
frm.Show()
End Sub
Segundo Form (child) onde é alterado o construtor e exibida a mensagem
Private myString As String
' Definição de um parâmetro no construtor do frm
Sub New(ByVal str As String)
InitializeComponent()
' Actribuição do valor passado à variável privada
myString = str
End Sub
Private Sub frmChild_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
' Exibição da mensagem
MessageBox.Show(myString)
End Sub
Dois exemplos simples mas muito úteis, porque este intercambio de informação entre forms é muito usual.
PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!