Griser les onglets en vb.net

Description

On ne peut pas griser les onglets dans le framework .Net, alors voilà une classe qui permet de le faire.

Pour l'utiliser, au moment de la création de la fenêtre, créez un l'objet suivant :
TabControl1_Grisage = New GrisageOnglets(TabControl1)

Pour griser un onglet, utilisez l'objet créé :
TabControl1_Grisage.Griser(TabPage1)

Ensuite vous pouvez griser les onglets. Si vous voulez désactiver le grisage, vous pouvez alors effectuer :
TabControl1_Grisage.Dispose()
TabControl1_Grisage = Nothing

Source / Exemple :


Imports System.Runtime.InteropServices

Public Class GrisageOnglets
    Implements IDisposable

    Private Const Erreur_OngletActif As String = "L'onglet actif ne peut pas être grisé"
    Private Const Erreur_Personnalisé As String = "L'affichage des onglets est déjà personnalisé"

    Public TexteOngletNormal As Brush = SystemBrushes.ControlText
    Public TexteOngletSélectionné As Brush = SystemBrushes.ControlText
    Public TexteOngletGrisé As Brush = SystemBrushes.GrayText

    Dim oOnglets As TabControl
    Dim oOngletsGrisés As New List(Of TabPage)

    Private StringFormatSansBug As StringFormat = StringFormat.GenericTypographic

    Sub New(ByVal Onglets As TabControl)
        If Onglets.DrawMode = TabDrawMode.OwnerDrawFixed Then
            Throw New Exception(Erreur_Personnalisé)
        End If
        oOnglets = Onglets
        AddHandler Onglets.Selecting, AddressOf TabControl_Selecting
        AddHandler Onglets.DrawItem, AddressOf TabControl_DrawItem
        Onglets.DrawMode = TabDrawMode.OwnerDrawFixed
    End Sub

    Private Sub TabControl_Selecting(ByVal sender As System.Object, ByVal e As System.Windows.Forms.TabControlCancelEventArgs)
        If e.Action = TabControlAction.Selecting And oOngletsGrisés.Contains(e.TabPage) Then
            e.Cancel = True
        End If
    End Sub

    Private Sub TabControl_DrawItem(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DrawItemEventArgs)
        Dim Onglet As TabPage = oOnglets.TabPages(e.Index)
        Dim Texte As String = Onglet.Text
        Dim TailleTexte As SizeF = e.Graphics.MeasureString(Texte, e.Font, New PointF(e.Bounds.Left, e.Bounds.Top), StringFormatSansBug)
        Dim Icône As Image = oOnglets.ImageList.Images(Onglet.ImageKey)
        Dim LargeurImage As Integer
        If Icône Is Nothing Then LargeurImage = 0 Else LargeurImage = Icône.Width
        Dim Départ As PointF = New Point(e.Bounds.Left + LargeurImage + (e.Bounds.Width - LargeurImage - TailleTexte.Width) / 2, e.Bounds.Top + 3)
        Dim DépartImage As PointF = New Point(Départ.X - LargeurImage - 3, Départ.Y)
        If Icône IsNot Nothing Then
            If Icône.Height > TailleTexte.Height Then
                Départ.Y = Départ.Y + (Icône.Height - TailleTexte.Height) / 2
                DépartImage.Y = e.Bounds.Top + 2
            ElseIf Icône.Height < TailleTexte.Height Then
                DépartImage.Y = DépartImage.Y + (TailleTexte.Height - Icône.Height) / 2
            End If
        End If

        If e.State And DrawItemState.Selected = DrawItemState.Selected Then
            e.Graphics.DrawImage(Icône, DépartImage)
            e.Graphics.DrawString(Texte, e.Font, TexteOngletSélectionné, Départ, StringFormatSansBug)
            e.Graphics.DrawLine(SystemPens.Control, e.Bounds.Left, e.Bounds.Bottom - 2, e.Bounds.Right, e.Bounds.Bottom - 2)
        ElseIf oOngletsGrisés.Contains(Onglet) Then
            Dim ImageGrisée As Bitmap = GriserImage(Icône)
            e.Graphics.DrawImage(ImageGrisée, DépartImage)
            ImageGrisée.Dispose()
            e.Graphics.DrawString(Texte, e.Font, TexteOngletGrisé, Départ, StringFormatSansBug)
        Else
            e.Graphics.DrawImage(Icône, DépartImage)
            e.Graphics.DrawString(Texte, e.Font, TexteOngletNormal, Départ, StringFormatSansBug)
        End If

    End Sub

    Sub Griser(ByVal Page As TabPage)
        If Not oOngletsGrisés.Contains(Page) Then
            If Page Is oOnglets.SelectedTab Then
                Throw New Exception(Erreur_OngletActif)
            End If
            oOngletsGrisés.Add(Page)
            oOnglets.Invalidate()
        End If
    End Sub

    Sub Dégriser(ByVal Page As TabPage)
        If oOngletsGrisés.Contains(Page) Then
            oOngletsGrisés.Remove(Page)
            oOnglets.Invalidate()
        End If
    End Sub

    Sub Inverser(ByVal Page As TabPage)
        If oOngletsGrisés.Contains(Page) Then
            Dégriser(Page)
        Else
            Griser(Page)
        End If
    End Sub

    Property EstGrisé(ByVal Page As TabPage) As Boolean
        Get
            Return oOngletsGrisés.Contains(Page)
        End Get
        Set(ByVal value As Boolean)
            If value Then
                Griser(Page)
            Else
                Dégriser(Page)
            End If
        End Set
    End Property

    ''' <summary>
    ''' Grise une image avec transparence. Merci à tkfe.
    ''' </summary>
    Shared Function GriserImage(ByVal UneImage As Image) As Bitmap
        Dim bitmap As Bitmap = New Bitmap(UneImage)

        Dim width As Integer = bitmap.Width
        Dim height As Integer = bitmap.Height

        'Lockbits des images initial et résultat
        Dim bmpData As Imaging.BitmapData = bitmap.LockBits(New Rectangle(0, 0, width, height) _
        , System.Drawing.Imaging.ImageLockMode.ReadWrite, Imaging.PixelFormat.Format32bppArgb)

        'Copie des pixels dans un tableau contenant tous les composantes Bleu, vert, rouge, alpha
        Dim Pixel(width * height - 1) As Integer '4 octets = 4 composantes = 1 pixel
        Marshal.Copy(bmpData.Scan0, Pixel, 0, Pixel.Length)

        Dim loc, x, y, gray As Integer

        'tables de precalcul des multiplications pour le calcul de localisation des pixels
        'de l'ancienne image et de la nouvelle.
        Dim multi(height - 1) As Integer

        For y = 0 To height - 1
            multi(y) = width * y
        Next

        'tables de precalcul des multiplications pour le calcul du niveau de gris
        Dim tabBleu(255) As Integer
        Dim tabVert(255) As Integer
        Dim tabRouge(255) As Integer

        'Initialisation
        For y = 0 To 255
            tabBleu(y) = 76 * y
            tabVert(y) = 151 * y
            tabRouge(y) = 28 * y
        Next

        For y = 0 To height - 1

            For x = 0 To width - 1
                'calcul de la localisation du pixel
                loc = multi(y) + x
                'on calcule le niveau de gris sur 255
                'Formule ci-dessous en commentaires, à éviter car coûteuse
                'CByte(0.3 * oldPixel(loc) + 0.59 * oldPixel(loc + 1) + 0.11 * oldPixel(loc + 2))

                'on affecte le niveau de gris au pixel dans la nouvelle image
                gray = (tabBleu(Pixel(loc) And &HFF) + tabVert((Pixel(loc) And &HFF00) >> 8) + tabRouge((Pixel(loc) And &HFF0000) >> 16)) >> 8
                Pixel(loc) = gray + (gray << 8) + (gray << 16) + ((Pixel(loc) >> 1) And &H7F000000)
            Next

        Next

        'on recopie notre nouveau tableau dans la nouvelle image
        Marshal.Copy(Pixel, 0, bmpData.Scan0, Pixel.Length)
        bitmap.UnlockBits(bmpData)
        Return bitmap
    End Function

    Private disposedValue As Boolean = False        ' Pour détecter les appels redondants

    ' IDisposable
    Protected Overridable Sub Dispose(ByVal disposing As Boolean)
        If Not Me.disposedValue Then
            If disposing Then
                ' TODO : libérez des ressources managées en cas d'appel explicite
            End If

            ' TODO : libérez des ressources non managées partagées
            RemoveHandler oOnglets.Selecting, AddressOf TabControl_Selecting
            RemoveHandler oOnglets.DrawItem, AddressOf TabControl_DrawItem
            oOnglets.DrawMode = TabDrawMode.Normal
            oOnglets.Invalidate()
            oOnglets = Nothing
        End If
        Me.disposedValue = True
    End Sub

#Region " IDisposable Support "
    ' Ce code a été ajouté par Visual Basic pour permettre l'implémentation correcte du modèle pouvant être supprimé.
    Public Sub Dispose() Implements IDisposable.Dispose
        ' Ne modifiez pas ce code. Ajoutez du code de nettoyage dans Dispose(ByVal disposing As Boolean) ci-dessus.
        Dispose(True)
        GC.SuppressFinalize(Me)
    End Sub
#End Region

End Class

Conclusion :


Le résultat est satisfaisant. Cela dit, lorsque l'on met les onglets en mode dessin personnalisé, le rendu se fait à la mode Windows 95.

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.