User control pour un histogramme à barres verticales

Soyez le premier à donner votre avis sur cette source.

Snippet vu 6 050 fois - Téléchargée 19 fois

Contenu du snippet

A partir d'un User Control (U_C) on veut un Histogramme à Barres Verticales (version 4) en utilisant des Label et des PictureBox

Les props Read sont accessibles depuis la boite à outils du U_C dans l'Appli_Cliente (Echelle, Maxi...)
Les props Write ne sont accessible que depuis le code de l'Appli_Cliente (GO)
ci dessous les deux pages de code : l'Appli_Cliente puis le User_Control

Source / Exemple :


Public Class Form1
    ' ===== Application_Cliente utilisant un User Control = Histogramme à Barres Verticales (Version 4)  

    Private arrColor() As Color = {Color.Tomato, Color.DarkSeaGreen, Color.CornflowerBlue, _
                                   Color.Orchid, Color.OliveDrab, Color.SlateBlue, Color.Goldenrod, Color.Tan}
    Private table1902 As New DataTable, table1903 As New DataTable
    Private array1902() As Integer = {75, 300, 40, 250, 8, 165, 15}
    Private array1903() As Integer = {50, 280, 10, 350, 40, 75, 2}
    Private arrayNom() As String = {"Dijon", "Nantes", "Nice", "Paris", "Lyon", "Cherbourg", "Pau"}

    ' ===== Paramétrage du U_C et lancement du Traitement des Données :
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Charger_Table(table1902, array1902, arrayNom) ' on fait comme pour convertir un RecordSet en DataTable
        Charger_Table(table1903, array1903, arrayNom)
        With UC_Histo_1902
            ' ----- les props READ peuvent être valorisées dans la Boite de Props de cette Form :
            '   .HauteurGraphique = 400
            '   .MaxValue = 400
            '   .Echelle = 40                       ' Quand Echelle = 0 on n'affiche que la valeur MAXI
            '   .LargeurBarre = 40                  ' Facultatif = par défaut = 25
            '   .Titre_Graphique = "Conso Radis 1902"
            '   .Unite = "tonnes"   
            ' ----- les Props WRITE sont gérées par le U_C
            .Table_Serie = table1902
            .array_Couleurs = arrColor
            .Left = 20                           ' positon du U_C ici, dans l'Appli_Cliente
            ' ----- et on déclenche l'évenement Load PUBLIC de ce U_C (Go dans le U_C)
            .Go(sender, e)
        End With
        ' ----- ce qui donne pour faire court :
        With Uc_Histo_1903
            .Table_Serie = table1903
            .array_Couleurs = arrColor
            .Left = UC_Histo_1902.Width + 40
            .Go(sender, e)
        End With
    End Sub
    ' ===== Charger les tables (idem from RecordSet de BdD) :
    Private Function Charger_Table(ByVal _table As DataTable, ByVal _Val As Array, ByVal _Leg As Array) As Boolean
        Dim R As DataRow
        With _table
            .Columns.Add() : .Columns.Add()
            For i As Integer = 0 To 6 ' ici une limite arbitraire pour l'exemple
                R = .NewRow
                R(0) = _Leg(i) : R(1) = _Val(i)
                .Rows.Add(R) ' et on suppose pour l'exercice que les données sont cohérentes !
            Next
        End With
        Return _table.Rows.Count
    End Function
    ' ===== TCHCONST jan 2011 =====
End Class
----------  Le User Control ----------
Public Class uc_Histo_V3

    ' ===== CDC : User_Control qui construit un Histogramme à Barres Verticales 
    '             en utilisant seulement des Label et des PictureBox - TCHCONST jan 2011 -  

    ' ===== Variables et Propriétés  
    Private graphHauteur, Maxi, Echelle As Integer
    Private barreLargeur As Integer = 25
    Private interval As Integer = 0
    Private Units As String = "unités"
    Private Titre As String = "HistoGramme" ' ou Message d'Erreur
    Private Serie As DataTable
    Private arrColors As Array
    Private Erreur As Boolean = False
    Public Property Titre_Graphique() As String
        Get
            Return Titre
        End Get
        Set(ByVal value As String)
            Titre = value
        End Set
    End Property
    Public Property Unite() As String
        Get
            Return Units
        End Get
        Set(ByVal value As String)
            Units = value
        End Set
    End Property
    Public Property Max_Value() As Integer
        Get
            Return Maxi
        End Get
        Set(ByVal value As Integer)
            Maxi = value
        End Set
    End Property
    Public Property Echelle_Valeurs() As Integer
        Get
            Return Echelle
        End Get
        Set(ByVal value As Integer)
            Echelle = value
        End Set
    End Property
    Public Property Hauteur_Graphique() As Integer
        Get
            Return graphHauteur
        End Get
        Set(ByVal value As Integer)
            graphHauteur = value
        End Set
    End Property
    Public Property Largeur_Barre() As Integer
        Get
            Return barreLargeur
        End Get
        Set(ByVal value As Integer)
            barreLargeur = value
        End Set
    End Property
    Public Property Interval_Barre() As Integer
        Get
            Return interval
        End Get
        Set(ByVal value As Integer)
            interval = value
        End Set
    End Property
    Public WriteOnly Property Table_Serie() As DataTable
        Set(ByVal value As DataTable)
            Serie = value
        End Set
    End Property
    Public WriteOnly Property array_Couleurs() As Array
        Set(ByVal value As Array)   ' c'est dans l'Appli_Cliente que l'on s'assure de la cohérence Série > Couleurs 
            arrColors = value
        End Set
    End Property

    ' ===== Création des controles constitutifs et Traitement des données (ici l'evt Load est PUBLIC) 

    Public Sub Go(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Serie Is Nothing Then Exit Sub
        Dim nbBarres, i As Integer
        ' vérifier les paramètres (gestion erreur LIGHT) :
        If graphHauteur < 100 Then Erreur = True : Titre = "Hauteur Histo incohérente"
        nbBarres = Serie.Rows.Count
        If nbBarres = 0 Then Erreur = True : Titre = "Série incohérente"
        If Maxi = 0 Then Erreur = True : Titre = "Max incohérent"
        If Maxi < Echelle Then Erreur = True : Titre = "Echelle incohérente"
        ' NB : nous avons 1 controle dans le [Design] L_Titre(Label) pour le titre ou la gestion d'Erreur
        Dim L As Label                  ' label pour toutes les valeurs
        Dim P As PictureBox             ' niveaux, barres, graph, nuancier    

        If Not Erreur Then

            Dim barreColor, fontColor, graphColor As Color
            Dim fontTexte As New Font("Verdana", 10)
            Dim fontVal As New Font("Verdana", 8, FontStyle.Bold)
            Dim maVal As Integer
            Dim monTxt As String

            ' ----- 1) Formatage Général 
            Dim lblHauteur, ctlTop, ctlHauteur, cptLeft, cptBas As Integer
            Dim nbEchelons, interEchelon, Marge, margeGauche, graphLargeur, margeDroite As Integer
            graphLargeur = (nbBarres * barreLargeur) + ((nbBarres - 1) * interval)
            L_Titre.Text = Maxi                     ' valeur témoin pour la largeur de la Marge Gauche 
            L_Titre.Font = fontVal
            L_Titre.FlatStyle = 3 : L_Titre.AutoSize = True
            margeGauche = L_Titre.Width
            lblHauteur = L_Titre.Height             ' hauteur témoin d'une étiquette
            Marge = Math.Round(lblHauteur / 2)      ' les marges autour des divers controles

            ' ----- 2) Afficher l'Echelle ou la Valeur Maxi ?
            If Echelle > 0 And Maxi > 0 Then
                nbEchelons = Math.Round(Maxi / Echelle)
                interEchelon = Math.Round(graphHauteur / Maxi * Echelle)
                For i = 0 To nbEchelons
                    ' ----- 2.1) Valeur dans la marge gauche 
                    monTxt = (Echelle * i).ToString
                    ctlTop = graphHauteur - (interEchelon * i)
                    L = New Label With {.Top = ctlTop, .Left = 0, .Width = margeGauche, _
                                        .Text = monTxt, .Font = fontVal, .TextAlign = 4}
                    ' ----- 2.2) Barre de niveau dans le cadre du graphique  
                    P = New PictureBox With {.Top = ctlTop + Marge, .Left = margeGauche, _
                                             .Width = graphLargeur, .Height = 1, .BackColor = Color.Wheat}
                    Controls.Add(L) : Controls.Add(P)
                Next
            Else
                ' ----- 2.bis) Maxi seulement 
                L = New Label With {.Top = 0, .Left = 0, .ForeColor = Color.Black, .Text = Maxi, _
                                    .Width = margeGauche, .Font = fontVal, .TextAlign = 4, .FlatStyle = 3}
                Controls.Add(L)
            End If

            ' ----- 3) Barres de la Série et Valeurs 
            If Not arrColors Is Nothing Then
                If arrColors.Length > nbBarres Then
                    graphColor = arrColors(nbBarres) ' la couleur du fond du graphique demandée 
                Else
                    graphColor = Color.White : barreColor = Color.LightGray ' ou par défaut 
                End If
            Else ' toutes les couleurs par défaut 
                barreColor = Color.LightGray : fontColor = Color.Black : graphColor = Color.Tan
            End If
            cptLeft = margeGauche
            With Serie
                For i = 0 To nbBarres - 1
                    monTxt = .Rows(i).Item(0) : maVal = .Rows(i).Item(1)
                    ' ----- 3.1) Barre
                    ctlHauteur = Math.Round(graphHauteur / Maxi * .Rows(i).Item(1))
                    ctlTop = Marge + graphHauteur - ctlHauteur
                    If ctlHauteur > graphHauteur Then                    ' le max est incohérent, erreur déjà levée !
                        ctlTop = Marge
                        ctlHauteur = graphHauteur
                        If Not Erreur Then Titre = String.Format("Maxi={0} < {1}={2}", Max_Value, monTxt, maVal)
                        Erreur = True
                    End If
                    If Not arrColors Is Nothing Then barreColor = arrColors(i)
                    P = New PictureBox With {.Left = cptLeft, .Top = ctlTop, .Width = barreLargeur, _
                                             .Height = ctlHauteur, .BackColor = barreColor, .Cursor = Cursors.Hand}
                    ' ----- 3.2) Valeur sous le Top de la barre, ou au dessus si la barre < hauteur de police 
                    If ctlHauteur < fontVal.GetHeight Then
                        ctlTop -= fontVal.GetHeight
                        barreColor = graphColor : fontColor = Color.Black
                    Else
                        fontColor = Color.White
                    End If
                    L = New Label With {.Left = cptLeft, .Top = ctlTop, .Width = barreLargeur, .BackColor = barreColor, _
                                        .ForeColor = fontColor, .Text = maVal, .TextAlign = 2, .FlatStyle = 3, _
                                        .Font = fontVal, .Height = fontVal.GetHeight, .Cursor = Cursors.Hand}
                    Controls.Add(P) : Controls.Add(L)
                    ' ----- 3.3) Bulles et premier-plan 
                    P.BringToFront() : L.BringToFront()
                    monTxt = String.Format(" {0} {1} {2} ", monTxt, maVal, Units)
                    ttip.SetToolTip(P, monTxt) : ttip.SetToolTip(L, monTxt)
                    cptLeft += barreLargeur + interval
                Next

                ' ----- 4) Titre du Graphique ou Erreur
                With L_Titre
                    .Font = fontTexte
                    If Erreur Then
                        .Text = "erreur: " & Titre
                    Else
                        .Text = String.Format("{0} ({1})", Titre, Units)
                    End If
                    .Left = margeGauche : .Top = graphHauteur + lblHauteur
                    .TextAlign = 16 : .FlatStyle = 3 : .AutoSize = True
                End With

                ' ----- 5) Légende en bas à droite 
                cptLeft += Marge - interval
                cptBas = Marge + graphHauteur
                For i = nbBarres - 1 To 0 Step -1           ' en partant de la base du graphique 
                    If arrColors Is Nothing Then
                        barreColor = Color.LightGray        ' couleur de la barre par défaut 
                    Else
                        barreColor = arrColors(i)
                    End If
                    ' ----- 5.1) Nuancier = Carrés de 12x12  
                    P = New PictureBox With {.Top = cptBas - 12, .Left = cptLeft, .Width = 12, .Height = 12, _
                                             .BackColor = barreColor, .Cursor = Cursors.Hand}
                    ' ----- 5.2) Etiquette
                    monTxt = String.Format(" {0} ", .Rows(i).Item(0))
                    L = New Label With {.Top = cptBas - lblHauteur, .Left = cptLeft + 10, .Text = monTxt, _
                                        .Cursor = Cursors.Hand, .TextAlign = 256, .FlatStyle = 3, .AutoSize = True}
                    Controls.Add(P) : Controls.Add(L)
                    ' ----- 5.3) Bulle et marge Droite 
                    monTxt = String.Format(" {0} {1} {2} ", .Rows(i).Item(0), .Rows(i).Item(1), Units)
                    ttip.SetToolTip(P, monTxt) : ttip.SetToolTip(L, monTxt)
                    If L.Width > margeDroite Then margeDroite = L.Width
                    cptBas -= (lblHauteur + 2)
                Next
                margeDroite += 12 + (Marge * 3)
            End With

            ' ----- 6) Cadre de fond du graphique 
            P = New PictureBox With {.Top = Marge, .Left = margeGauche, .Width = graphLargeur, _
                                    .Height = graphHauteur, .BackColor = graphColor}
            Controls.Add(P) : P.SendToBack()

            ' ----- 7) Dimensions finales du U_C 
            Width = cptLeft + margeDroite
            Height = graphHauteur + (lblHauteur * 2.5)

        Else

            ' ----- 8) Erreurs !!! 
            With L_Titre
                .Text = "erreur: " & Titre
                .Left = 0 : .Width = 300
            End With
            Width = 300
        End If
    End Sub
    ' ===== TCHCONST jan 2011 =====
End Class

Conclusion :


Dans ce U_C aucun contrôle ne déclenche un quelconque événement.
Pour gérer les contrôles constitutifs et les données, on déclenche depuis l'Appli_Cliente l'événement Load du U_C qui est Public.

A voir également

Ajouter un commentaire

Commentaires

Messages postés
1172
Date d'inscription
jeudi 24 mai 2007
Statut
Membre
Dernière intervention
28 septembre 2013
1
Code à méditer avec un peu de temps ^^ Sinon pour info y'a Zedgraph qui fait tout ça et qui est trés bien documenté et aussi (voir plus) joli que MsChart :) Maintenant tes 4 sources sont interressantes et mériteraient de faire parti d'un tuto global plutot que de codes dispatchés sur le site, c'est mon avis. Bon boulot cependant merci pour ta participation. ADN
Messages postés
10
Date d'inscription
lundi 15 septembre 2008
Statut
Membre
Dernière intervention
11 octobre 2011

oups ! tapé un zéro de trop; 300 fois plus petit...
Messages postés
10
Date d'inscription
lundi 15 septembre 2008
Statut
Membre
Dernière intervention
11 octobre 2011

Merci pour les critiques constructives, vous allez penser que je chipote, le principe indiqué et suivi est justement de ne pas utiliser le MS_Chart de base (le OWC11.dll) qui est très moche et pas si simple à mettre en œuvre à la volée (pas de doc et pas de traduction en French, mais bien pour la finance). Ce User_Control est juste 3000 fois plus petit. Le Go déclenche le Load du User_Control qui a vraiment besoin d'un Sender et d'un "e". Merci pour vos notations. TCH.
Messages postés
6063
Date d'inscription
dimanche 13 avril 2003
Statut
Modérateur
Dernière intervention
15 juillet 2011
25
Le code n'est pas tres clair.
Utilises un design pattern builder et/ou decorateur pour faire ce genre de travail.
Tu devrait avoir n methodes de 2 à 10 lignes normalement.

Ensuite pourquoi reinventé la roue, il y a microsoft chart library
http://msdn.microsoft.com/en-us/magazine/dd569763.aspx

Qui est plus optimisé et complet:-)


Le .Go(sender, e) ne sert a rien sender et e ne sont pas utilisé?
Evites les notations : ca complexifie le code.
Messages postés
162
Date d'inscription
jeudi 22 janvier 2004
Statut
Membre
Dernière intervention
20 juillet 2013

La POO existe pour divier par 4 ou 5 le nombre de lignes de ton code. Si c'est pour faire ca, autant le dessiner dans une picturebox, c'est kif kif niveau qualité.

D'autant plus que si tu veux faire du procédural, il existe d'autres méthodes pour rendre le code plus lisible et plus rapide.

Toi tu le comprends parce que ce code est dans ta tête. Celui qui passe derrière toi n'a pas à chercher 3 heures ce que fait tel ou tel variable (nommage des variables exotique par exemple)

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.