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

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!


Excel: Formatar Gráficos Dinamicamente

Um dos factores que determinou o grande sucesso do Microsoft Excel, para além da sua grande capacidade como folha de cálculo, foi sem dúvida a grande diversidade de representação gráfica. Os gráficos permitem mostrar de uma forma simples e visualmente muito agradável os resultados obtidos. Existem dezenas de gráficos, com diferentes tipos e formatos que permitem agradar a todos, exigindo apenas algum trabalho e bom gosto.

 

Mas no entanto, existem sempre coisas que se necessita personalizar, quer seja os formatos, os textos, as cores, etc. Muitas vezes é necessário (ou importante) alterar o gráfico de acordo com os resultados e se automatizarmos esta personalização de acordo com um determinado critério, além de simplificar o trabalho, evita também erros indesejados.

 

 

Uma das representações em gráfico muito utilizadas é a definição de um valor e o objectivo a atingir. O seguinte exemplo mostra como alterar a cor das barras de um gráfico de acordo com um objectivo. Neste exemplo as barras ficam a verdes caso o resultado seja igual ou superior a um objectivo definido (objectivo cumprido) e a vermelho caso estejam abaixo do objectivo.

 

Os gráficos funcionam com séries, e um gráfico pode ter várias séries com diferentes tipos (barras, linhas, etc). Cada série tem um conjunto de pontos que correspondem aos valores que são representados.

 

 

(figura 1)

 

Para implementarmos este exemplo é apenas necessário criar uma tabela com alguns valores para o resultado (vendas) e definir um objectivo (figura 1).

 

Depois abrir o Editor de Visual Basic (Tools – Macros – Visual Basic Editor ou ALT+F11) e definir para a Sheet1 o seguinte código:

 

' Código para a "Sheet1" que executa caso algum valor seja alterado

Private Sub Worksheet_Change(ByVal Target As Range)

 

' Caso seja alterado algum valor na área B20:H21

If Not Intersect(Target, [B20:H21]) Is Nothing Then

 

    Application.ScreenUpdating = False

   

    ' Definição de variáveis

    Dim ws As Worksheet

    Dim wsChartObject As ChartObject

    Dim wsCell As Range

       

    ' Atribuição de objectos às variáveis indicando qual é a worksheet e

    ' qual é o nome do gráfico (visível na folha de cálculo)

    Set ws = Worksheets("Sheet1")

    Set wsChartObject = ws.ChartObjects("Chart 1")

   

    ' Inicia um ciclo em todas as células da primeira linha (resultados de vendas)

    For Each wsCell In ws.[B20:H20].Cells

       

        ' Selecciona a série 1 no ponto de acordo com a coluna da célula actual

        ' pode-se alterar a coluna (column) para linha (row) caso os dados estejam

        ' na posição vertical.

        With wsChartObject.Chart.SeriesCollection(1).Points(wsCell.Column - 1).Interior

           

            ' Caso o valor da célula actual seja igual ou superior à célula que está

            ' na linha abaixo da actual, coloca diferentes cores. O valor desta célula

            ' na linha abaixo (objectivo) é adquirida com a  implementando a função

            ' OffSet que permite indicar uma posição a partir da posição actual

            If wsCell >= wsCell.Offset(1) Then

                .ColorIndex = 10 ' Verde

            Else

                .ColorIndex = 3   ' Vermelho

            End If

           

        End With

       

    Next

   

    ' Limpa as variáveis da memória

    Set ws = Nothing

    Set wsChartObject = Nothing

   

    Application.ScreenUpdating = True

End If

 

End Sub

 

 

O resultado final (figura 2) pode ser visto alterando qualquer valor no Range definido no evento Worksheet Change (que no exemplo é B20:H20)

 

 

 

(figura 2)

 

 

Este exemplo pretende mostrar como modificar dinamicamente as cores de um gráfico com base num determinado critério, mostrando de uma forma geral que é possível utilizar o VBA para efectuar modificações nos gráficos de uma forma relativamente simples.

 

 

PS: Como sempre, qualquer dúvida, comentário ou correcção ao artigo é sempre bem vinda!


VB.NET: Utilização de Ficheiros de Texto

A utilização e manipulação de ficheiros de texto (*. txt ou outra extensão) é muito comum embora existam bastantes alternativas disponíveis para guardar informação. No entanto, muitas vezes não é uma questão de alternativa (usar ou não usar) mas sim uma necessidade.

O .NET Framework 2.0 introduziu novos métodos que possibilitam um fácil e rápido acesso. Os métodos mais utilizados e mais eficazes para ler e escrever em ficheiros de texto são os namespaces IO (através da classe File, principalmente ReadAllLines, WriteAllText e AppendAllText e o StreamReader, StreamWriter) e o My (através da classe My.Computer.FileSystem, principalmente ReadAllText e WriteAllText).

Obviamente que existem diferenças entre eles, mas as principais diferenças são que o StreamReader e StreamWriter lê/escreve linha a linha e os outros métodos lêem/escrevem tudo de uma só vez, ou seja, utilizam mais recursos da aplicação. Por exemplo o StreamReader lê linha a linha enquanto o método ReadAllLines lê toda a informação para uma variável (array).

É claro que isto apenas se consegue notar em grande número de informação, mas para verem as principais diferenças e desempenhos vejam a seguinte tabela com os tempos de acesso em milisegundos.

Tempo Médio de Leitura

Método/Nº Linhas

10.000

100.000

1.000.000

IO.File.ReadAllLines

4,0

71,2

957,1

IO.StreamReader

2,6

33,9

313,1

My.Computer.FileSystem.ReadAllText

6,7

60,5

991,2

Tempo Médio de Leitura

Método/Nº Linhas

10.000

100.000

1.000.000

IO.File.WriteAllText

15,1

123,8

1.426,4

IO.StreamWriter

13,8

115,5

1.922,8

My.Computer.FileSystem.WriteAllText

15,3

116,8

1.389,1

Nota: Tempo em milisegundos com a média de 10 leitura e texto por linha de 13 caracteres

Para mostrar um pouco a utilização dos diferentes métodos serão mostrados dois exemplos da leitura e escrita. Como o IO.File e o My.Computer.FileSystem são bastante semelhantes, onde a principal diferença é que a classe IO.File tem um método que lê todas as linhas sem necessitar de utilizar uma função de Split() para as colocar num array, irá ser mostrado apenas este. O My.Computer.FileSystem tem ainda um parametro adicionar que permite adicionar, ou não, texto a um arquivo já existente (append).

Exemplo de leitura de um ficheiro através do classe IO.File (ReadAllLines)

        Dim total As Integer = 0
        Dim fileName As String = "c:\teste.txt"

        ' Guarda num Array linha a linha
        Dim lines() As String = IO.File.ReadAllLines(fileName)

        ' Ciclo que irá mostrar linha a linha
        For Each line As String In lines

            Debug.WriteLine(line.ToString)
            total += 1

        Next

        ' Mostra o total de linha lidas
        Debug.WriteLine("Total de linhas:" & total.ToString)

Exemplo de escrita de um ficheiro através do classe IO.File (WriteAllText)

        Dim total As Integer = 0
        Dim fileName As String = "c:\teste.txt"

        ' Cria um novo StringBuilder
        Dim sb As New System.Text.StringBuilder                                   

        ' Ciclo que irá inserir construir o ficheiro a gravar
        For x As Integer = 0 To 9999

            ' Cria uma linha com o formato "Linha nº 0001"
            sb.AppendLine("Linha nº " & x.ToString.PadLeft(4, "0"))
            total += 1
        Next

        ' Grava o ficheiro no disco
        IO.File.WriteAllText(fileName, sb.ToString)

        ' Mostra o resultado
   Debug.WriteLine(String.Format("Ficheiro {0} com {1} registos", fileName, total))

Exemplo de leitura de um ficheiro através do classe IO (StreamReader)

        Dim total As Integer = 0
        Dim fileName As String = "c:\teste.txt"

        ' Ciclo que irá mostrar linha a linha
        Using reader As New IO.StreamReader(fileName)

            ' Ciclo até ao fim do ficheiro
            While Not reader.EndOfStream()

                ' Mostra o resultado linha a linha
                Dim input As String = reader.ReadLine()
                Debug.WriteLine(input)
                total += 1                                   

            End While                                   

        End Using

        ' Mostra o total de linha lidas
        Debug.WriteLine("Total de linhas:" & total.ToString)

Exemplo de escrita de um ficheiro através do classe IO (StreamWriter)

        Dim total As Integer = 0
        Dim fileName As String = "c:\teste.txt"                                   

        ' Cria um nova instância de um StreamWriter
        Using writer As New IO.StreamWriter(fileName)

            ' Inicia o ciclo que irá gravar no ficheiro
            For x As Integer = 0 To 9999

                writer.WriteLine("Linha nº " & x.ToString.PadLeft(4, "0"))
                total += 1

            Next

        End Using

        ' Mostra o resultado
   Debug.WriteLine(String.Format("Ficheiro {0} com {1} registos", fileName, total))

Estes são pequenos exemplos da estrutura tipo, embora existam ainda em cada classe, uma serie de métodos que podem ser utilizados. Pelos exemplos mostrados e pelo desempenho de cada um, deverá ser utilizado aquele que mais se ajustar a cada situação. Apenas em ficheiros grandes deverá haver um mais cuidado na escolha do método a utilizar.

Todos utilizam por defeito uma codificação de UTF-8 mas por vezes é necessário ajustar para certos ficheiros. A opção System.Text.Encoding.Default é muitas vezes a melhor solução para problemas de codificação.

                                

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