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

Excel: Utilização de Shapes

O Excel tem um grande número de shapes disponíveis que permitem melhorar graficamente as folhas de cálculo. São muito úteis e muito utilizadas, permitindo colocar comentários, chamadas de atenção, setas, estrelas, etc.

   

São tantas vezes utilizadas que por vezes a automatização do processo é útil e importante. Por exemplo, fazer aparecer ou criar uma shape quando a célula tem um determinado valor.




Para mostrar como se pode, através do VBA, automatizar processos utilizando shapes, será criado um exemplo onde serão adicionadas/removidas dinamicamente numa folha de cálculo de acordo com determinados critérios. Neste caso, existe uma lista de produtos em que é feita uma comparação entre dois anos (2006 e 2007) e será colocada um seta a indicar se existiu uma subida ou descida de vendas.

   

Para implementarmos este exemplo devemos fazer o seguinte:

   

1 – Menu Tools – Macros – Visual Basic Editor ou ALT+F11 na folha de calculo

2 – No Editor, mais precisamente na janela de projecto, seleccionamos a nossa worksheet (Sheet1 por exemplo)
3
Colocamos o seguinte código no editor de código:

   

   

    ' Definição do tipo de seta

    Enum ArrowType

        UpArrow

        DownArrow

    End Enum

   

    ' ------------------------------------------------------------------

    ' Criar uma nova shape na célula indicada

    ' ------------------------------------------------------------------

    Private Sub CreateShape(ByVal Cell As Range, ByVal Arrow As ArrowType)

        Dim arrowWidth As Double, arrowHeight As Double

        Dim arrowTop As Double, arrowLeft As Double

        Dim sh As Shape

   

        ' Definições do tamanho e localização da seta de modo

        ' a ficar centrada na célula e com um comprimento

        ' comprimento de - 20% (para não ocupar na totalidade)

        arrowWidth = 15

        arrowHeight = Cell.Height - (Cell.Height * 0.2)

        arrowTop = Cell.Top + ((Cell.Height * 0.2) / 2)

        arrowLeft = (Cell.Left + (Cell.Width / 2)) - (arrowWidth / 2)

   

        ' Verifica qual o tipo de célula pretendido

        If Arrow = UpArrow Then

   

            ' Adiciona a shape na posição calculada

            sh = ActiveSheet.Shapes.AddShape(msoShapeUpArrow, arrowLeft, _

                     arrowTop, arrowWidth, arrowHeight)

   

            ' Define a cor do interior e linha(verde)

            With sh

                .Fill.ForeColor.RGB = vbGreen

                .Line.ForeColor.RGB = vbGreen

            End With

   

        Else

   

            ' Adiciona a shape na posição calculada

            sh = ActiveSheet.Shapes.AddShape(msoShapeDownArrow, arrowLeft, _

                    arrowTop, arrowWidth, arrowHeight)

   

            ' Define a cor do interior e linha(vermelho)

            With sh

                .Fill.ForeColor.RGB = vbRed

                .Line.ForeColor.RGB = vbRed

            End With

        End If

   

    End Sub

   

   

    ' ------------------------------------------------------------------

    ' Apaga a shape na célula indicada

    ' ------------------------------------------------------------------

    Private Sub DeleteShape(ByVal Cell As Range)

        Dim sh As Shape

   

        ' Faz um ciclo em todas as shapes na folha

        For Each sh In ActiveSheet.Shapes

   

            ' Caso a sua localização esteja na indicada, apaga-a

            If Not (Intersect(sh.TopLeftCell, Cell) Is Nothing) Then

                sh.Delete()

            End If

   

        Next

   

    End Sub

   

   

4 Finalmente no evento Worksheet Change colocamos o seguinte código que irá verificar qual o valor alterado e indicará que tipo de shape criar:

   

   

    Private Sub Worksheet_Change(ByVal Target As Range)

   

        ' Verifica se existe uma alteração no range B2:C10

        If Not Intersect(Target, [B2:C10]) Is Nothing Then

   

            Dim val1 As Integer

            Dim val2 As Integer

   

            ' Verifica os valores referentes ao ano (2006/207)

            val1 = Cells(Target.Row, 2).Value

            val2 = Cells(Target.Row, 3).Value

   

            ' Caso o valor de 2006 seja superior

            If val1 > val2 Then

   

                ' Apaga a shape (caso exista) e cria uma nova

                Call DeleteShape(Cells(Target.Row, 4))

                Call CreateShape(Cells(Target.Row, 4), DownArrow)

   

             ' Caso o valor de 2006 seja inferior

            ElseIf val1 < val2 Then

   

                ' Apaga a shape (caso exista) e cria uma nova

                Call DeleteShape(Cells(Target.Row, 4))

                Call CreateShape(Cells(Target.Row, 4), UpArrow)

   

             ' Caso o valor seja igual, apaga a shape

            Else

                Call DeleteShape(Cells(Target.Row, 4))

            End If

   

        End If

   

    End Sub

   

   

   

Este exemplo poderia ser conseguido muito mais facilmente, utilizando apenas uma formula, recorrendo a um determinada fonte, como é o caso do Wingdings, e à formatação condicional. No entanto este exemplo pretende, acima de tudo, mostrar como manipular shapes dinamicamente e como este processo pode ajudar na automatização da nossa folha de cálculo.

   

   

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


VB.NET: Sistema de Classificação numa DataGridView

O controlo DataGridView é realmente muito útil e versátil. Tem inúmeras funcionalidades e diversos tipos de células (TextBox, ComboBox, Button, etc.) e permite ainda alojar outros tipos personalizados. A criação de tipos personalizados ou pré-definidos de células permite uma expansão a este controlo.

       

Um bom exemplo de criação de células personalizadas na DataGridView é a criação de uma sistema de classificação ou votação, onde normalmente se utiliza estrelas para identificar a preferência ou gosto (1 fraco, 5 excelente).

       

       

Para implementar este sistema é necessário adicionar algumas imagens aos Resources do nosso projecto – 12 para ser preciso). As seguintes imagens poderão ser alteradas, sendo apenas necessário manter o nome e o tamanho.

       


       

Depois, para criar uma coluna/células de estrelas que permitam a classificação de um determinado item é necessário criar uma classe que herde as classes DataGridViewImageColumn e DataGridViewImageCell. Esta classe deverá ter o seguinte código:

       


Imports System

Imports System.Collections.Generic

Imports System.ComponentModel

Imports System.Drawing

Imports System.Data

Imports System.Text

Imports System.Windows.Forms

       

' Definição do namespace

Namespace CustomDataGridViewColumn

       

    ' Cria um novo tipo de columa

    Public Class RatingColumn

        Inherits DataGridViewImageColumn

       

        ' Definições da coluna

        Public Sub New()

            Me.CellTemplate = New RatingCell()

            Me.DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter

            Me.ValueType = GetType(Integer)

        End Sub

       

    End Class

       

       

    ' Cria um novo tipo de célula

    Public Class RatingCell

        Inherits DataGridViewImageCell

       

        Public Sub New()

            Me.ValueType = GetType(Integer)

        End Sub

       

        ' Faz o overrides à função GetFormattedValue retornando a imagem

        Protected Overloads Overrides Function GetFormattedValue(ByVal value As Object, ByVal rowIndex As Integer, ByRef cellStyle As DataGridViewCellStyle, ByVal valueTypeConverter As TypeConverter, ByVal formattedValueTypeConverter As TypeConverter, ByVal context As DataGridViewDataErrorContexts) As Object

            Return starImages(CInt(value))

        End Function

       

       

        ' Define o valor por defeito

        Public Overloads Overrides ReadOnly Property DefaultNewRowValue() As Object

            Get

                Return 3

            End Get

        End Property

       

       

        ' Faz o overrides ao Paint da imagem

        Protected Overloads Overrides Sub Paint(ByVal graphics As Graphics, ByVal clipBounds As Rectangle, _

                ByVal cellBounds As Rectangle, ByVal rowIndex As Integer, ByVal elementState As DataGridViewElementStates, _

                ByVal value As Object, ByVal formattedValue As Object, ByVal errorText As String, _

                ByVal cellStyle As DataGridViewCellStyle, ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle, _

                ByVal paintParts As DataGridViewPaintParts)

       

            Dim cellImage As Image = DirectCast(formattedValue, Image)

       

            ' Verifica qual a estrela

            Dim point As Point = Me.DataGridView.PointToClient(Control.MousePosition)

            Dim starNumber As Integer = GetStarFromMouse(cellBounds, point)

       

            ' Caso o número seja válido

            If starNumber <> -1 Then

                cellImage = starHotImages(starNumber)

            End If

       

            ' Suspende o desenho da selecção

            MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, _

                 cellImage, errorText, cellStyle, advancedBorderStyle, _

                (paintParts And Not DataGridViewPaintParts.SelectionBackground))

       

        End Sub

       

       

        ' Actualiza o valor da célula quando o utilizador clica na estrela

        Protected Overloads Overrides Sub OnContentClick(ByVal e As DataGridViewCellEventArgs)

            MyBase.OnContentClick(e)

       

            Dim starNumber As Integer

            Dim x As Integer = Me.DataGridView.CurrentCellAddress.X

            Dim y As Integer = Me.DataGridView.CurrentCellAddress.Y

            Dim ret As Rectangle = Me.DataGridView.GetCellDisplayRectangle(x, y, False)

       

            ' Verifica qual o valor

            starNumber = GetStarFromMouse(ret, Me.DataGridView.PointToClient(Control.MousePosition))

       

            ' Caso o número seja válido

            If starNumber <> -1 Then

                Me.Value = starNumber

            End If

        End Sub

       

       

        ' Invalida as células quando o rato move ou sai

        Protected Overloads Overrides Sub OnMouseLeave(ByVal rowIndex As Integer)

            MyBase.OnMouseLeave(rowIndex)

            Me.DataGridView.InvalidateCell(Me)

        End Sub

       

        Protected Overloads Overrides Sub OnMouseMove(ByVal e As DataGridViewCellMouseEventArgs)

            MyBase.OnMouseMove(e)

            Me.DataGridView.InvalidateCell(Me)

        End Sub

       

       

        Shared starImages As Image()

        Shared starHotImages As Image()

       

        Const IMAGEWIDTH As Integer = 58

       

        ' Função que verifica qual a estrela onde está o rato

        Private Function GetStarFromMouse(ByVal cellBounds As Rectangle, ByVal mouseLocation As Point) As Integer

            If cellBounds.Contains(mouseLocation) Then

       

                Dim mouseXRelativeToCell As Integer = (mouseLocation.X - cellBounds.X)

                Dim imageXArea As Integer = (cellBounds.Width / 2) - (IMAGEWIDTH / 2)

       

                If ((mouseXRelativeToCell + 4) < imageXArea) OrElse (mouseXRelativeToCell >= (imageXArea + IMAGEWIDTH)) Then

                    Return -1

                Else

                    Dim value As Integer = CInt(Math.Round(((CSng((mouseXRelativeToCell - imageXArea + 5)) / CSng(IMAGEWIDTH)) * 5.0F), MidpointRounding.AwayFromZero))

                    If value > 5 OrElse value < 0 Then

                        System.Diagnostics.Debugger.Break()

                    End If

                    Return value

                End If

            Else

                Return -1

            End If

        End Function

       

        ' Carrega as imagens

        Shared Sub New()

       

            starImages = New Image(5) {}

            starHotImages = New Image(5) {}

       

            For i As Integer = 0 To 5

                starImages(i) = DirectCast(My.Resources.ResourceManager.GetObject("star" + i.ToString()), Image)

            Next

       

            For i As Integer = 0 To 5

                starHotImages(i) = DirectCast(My.Resources.ResourceManager.GetObject("starhot" + i.ToString()), Image)

            Next

        End Sub

       

    End Class

       

End Namespace

       

       

Finalmente a implementação!

       

O seguinte exemplo utiliza uma lista de musicas que estão numa base de dados. A base de dados está ligada à DataGridView e existe um campo que é a classificação da música. Ao ser carregada a lista ou alterada a classificação, será actualizado o respectivo campo na DataGridView e posterioremente na base de dados. Para ligar uma base de dados a uma DataGridView podem ver o seguinte exemplo: Utilizando o controlo DataGridView

       

No evento Form Load, além de definir a DataSource da DataGridView, é necessário adicionar a nova coluna e indicar quais as classificações actuais.   

     

    ' Definição da localização da coluna onde estão as

    ' classificações - Alterar de acordo com a coluna

    Private ratingBoundColumn As Byte = 2

    Private ratingColumn As Byte

       

       

    Private Sub frmRating_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

       

        Application.EnableVisualStyles()

       

        ' Suspende a actualização da DataGridView

        Me.DataGridView1.SuspendLayout()

       

       

        ' Definição de dataSource da datagridview

        ' ---------------------------------------------------------------------

        Me.DataGridView1.DataSource = ...

        ' ---------------------------------------------------------------------

       

        ' Adiciona a nova coluna à DataGridView

        Dim myRatingColumn As New CustomDataGridViewColumn.RatingColumn

        myRatingColumn.HeaderText = "Classificação"

        Me.DataGridView1.Columns.Insert(Me.DataGridView1.ColumnCount, myRatingColumn)

       

        ' Verifica qual o número da coluna

        ratingColumn = Me.DataGridView1.ColumnCount - 1

       

        ' Faz um ciclo em todas as linhas e define o nº de estrelas

        For Each row As DataGridViewRow In Me.DataGridView1.Rows

            If Not row.IsNewRow Then

                Dim rc As DataGridViewImageCell

                rc = (CType(Me.DataGridView1(ratingColumn, row.Index), DataGridViewImageCell))

                rc.Value = row.Cells(ratingBoundColumn).Value

            End If

        Next

       

        ' Esconde a coluna onde se encontra o valor

        Me.DataGridView1.Columns(ratingBoundColumn).Visible = False

       

        ' Actualiza a DataGridView

        Me.DataGridView1.ResumeLayout()

       

    End Sub

       

       

Depois, quando é alterada alguma classificação, utilizando o evento CellContentClick

       

       

    ' Sempre que é alterada a classificação escreve na coluna/célula respectiva

    Private Sub DataGridView1_CellContentClick(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellContentClick

       

        If e.ColumnIndex = ratingColumn And e.RowIndex <> -1 Then

       

            ' Verifica o valor nas coluna de classificação

            Dim rc As DataGridViewImageCell

            rc = (CType(Me.DataGridView1(ratingColumn, e.RowIndex), DataGridViewImageCell))

       

            ' Caso o valor seja diferente (seleccionado/existente)

            If rc.Value <> Me.DataGridView1(ratingBoundColumn, e.RowIndex).Value Then

                ' Escreve o novo valor

                Me.DataGridView1(ratingBoundColumn, e.RowIndex).Value = rc.Value

            End If

        End If

       

    End Sub

       


Exemplo do artigo: DOWNLOAD DO FICHEIRO

       

       

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