Visual Basic em Português

Página pessoal de Jorge Paulino sobre o Visual Basic (VB.NET, ASP.NET, VB6, VBA) e algumas noticias de tecnologia

VB6: Forms Transparentes

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!


VB.NET: Utilizando Colecções List(Of T)

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!


VB.NET: Dicas de Programação #7

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!




Microsoft Office Especialist

Membro da Comunidade
Experts-Exchange


Administ. da Comunidade
Portugal-a-Programar



Twitter

Artigos no CodeProject

Artigos no CodeProject

Subscrever Novidades

Endereço de Email:

Delivered by FeedBurner

Seguidores

Histórico