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: 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!

4 comentários:

Vítor disse...

Boas..
Obrigado por este excelente exemplo..
Programo em VB.NET e tenho acompanhado com interesse este blog.

Que valor guarda na BD para a coluna das imagens?

Anónimo disse...

hola, muy interesante el articulo sabes si podrias poner la demo para descargarla?? te lo agradeceria mucho.. eske intente hacerlo pero me encontre con algunitos errores, tal vez me ekivoke o faltan algunas cosas, spero puedas subirla como descargar.. te lo agradeceria.. :D
gracias de antemano..

Leonardo.
si puedes envialo ami E-mai:
aprendiz_002@hotmail.com

Anónimo disse...

Hola amigo, muchas gracias por subirlo,pero he intentado descargarlo, pero no se puede descargar por mas que intento :(

http://vbtuga.vndv.com/DataGridViewRateStar.zip
se cancela la pagina... :(
spero se pueda areglar, gracias nuevamente

Atte:
Leonardo

aprendiz_002@hotmail.com

Morpheus disse...

Tá muito fixe!.
Obrigado pelo exemplo JPaulino.
Até+

Mensagens Recentes



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