Afficher un texte ou des rectangles, ellipses, polygones, etc... inclinés en vb 2008 (2 méthodes possibles)

Soyez le premier à donner votre avis sur cette source.

Vue 6 838 fois - Téléchargée 510 fois

Description

Comment afficher un texte incliné (angle paramétrable) ou une ellipse inclinée ou même faire une animation en faisant tourner autour d'un point paramétrable.

2 méthodes sous vb 2008 express :

- avec e.Graphics.RotateTransform

- avec Drawing2D.Matrix et GraphicsPath

Source / Exemple :


Imports System.Math

Public Class Form1

#Region "variables globales :"
    Dim x, y As Double 'position de départ de la chaine et de l'ellipse (coin sup gauche)
    Dim angle As Double 'angle de rotation
    Dim pas As Double 'vitesse de l'animation
    Dim larg As Integer ' pour l'ellipse
    Dim haut As Integer 'pour l'ellipse
    Dim crayon As Pen = New Pen(Color.Blue, 3)
#End Region

    'Evenements :
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        ' initialisation des variables globales :
        x = 400.0F 'coin sup gauche X
        y = 250.0F 'coin sup gauche Y
        larg = 200 'largeur de l'ellipse
        haut = 80 'hauteur de l'ellipse
        angle = 0.0F 'angle de départ (animation)
        pas = 0.1F ' pas de l'angle (animation)
    End Sub
    Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        'dessin à faire à chaque rafraichissement de l'écran :
        Dim a, b As Integer 'centre de rotation utilisé pour les 2 méthodes

        a = x - 20 'centre de rotation (X)
        b = y 'centre de rotation (Y)
        DrawRotatedString(e, "Chaine à faire tourner", x, y, a, b, angle) 'afficher la chaine...

        a = x + larg / 2 'centre de l'ellipse (rotation X)
        b = y + haut / 2 'centre de l'ellipse (rotation Y)
        DrawRotatedEllipse(e, x, y, a, b, angle) '-angle -> ferait tourner l'ellipse en sens contraire...

    End Sub
    Private Sub CheckBoxAnim_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckBoxAnim.CheckedChanged

        If CheckBoxAnim.Checked Then Animation()

    End Sub 'bouton animation cliqué
    Private Sub ButtonVitesseMoins_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonVitesseMoins.Click
        pas /= 2
    End Sub 'bouton vitesse -
    Private Sub ButtonVitessePlus_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ButtonVitessePlus.Click
        pas *= 2
    End Sub 'bouton vitesse +

    'Fonctions :
    Private Sub DrawRotatedEllipse(ByVal e As PaintEventArgs, ByVal x1 As Single, ByVal y1 As Single, _
                                   ByVal a As Single, ByVal b As Single, ByVal ang As Single)
        ' position avant rotation : (x1,y1)
        ' centre voulu pour la rotation  : (a,b)
        ' position intermédiaire après rotation autour de (a,b) : (x2,y2)
        ' position à donner à l'instruction DrawEllipse : (posX,posY)  (déduit de (x2,y2) par rotation -ang)

        Dim x2, y2, posX, posY As Single
        Dim angrad As Single

        ' Set the SmoothingMode to high quality for best readability.
        e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality

        '+ centre de la rotation pour info :
        e.Graphics.DrawEllipse(Pens.Blue, a, b, 2, 2)

        'on transforme l'angle en radians :
        angrad = ang / 180 * PI
        'on calcule la position intermédiaire (rotation ang autour de (a,b) ) :
        x2 = a + (x1 - a) * Cos(angrad) - (y1 - b) * Sin(angrad)
        y2 = b + (x1 - a) * Sin(angrad) + (y1 - b) * Cos(angrad)
        'on calcule la position de départ nécessaire (rotation -ang autour de (0,0)) :
        posX = x2 * Cos(angrad) + y2 * Sin(angrad)
        posY = -x2 * Sin(angrad) + y2 * Cos(angrad)

        ' matrice de rotation appliquée avant le dessin :
        e.Graphics.RotateTransform(ang)
        ' dessiner l'ellipse (le système applique la matrice de rotation avant) :
        e.Graphics.DrawEllipse(crayon, posX, posY, larg, haut)

    End Sub 'méthode avec e.Graphics.RotateTransform

    Public Sub DrawRotatedString(ByVal e As PaintEventArgs, ByVal s As String, ByVal x1 As Single, ByVal y1 As Single, _
                                 ByVal a As Single, ByVal b As Single, ByVal ang As Single)
        ' position avant rotation : (x1,y1)
        ' centre voulu pour la rotation  : (a,b)

        Dim Origine As PointF = New PointF(x1, y1)
        Dim SF As StringFormat = New StringFormat(0)
        Dim Centre As PointF = New PointF(a, b)

        ' Create a GraphicsPath.
        Dim path As New System.Drawing.Drawing2D.GraphicsPath
        ' Declare a matrix that will be used to rotate the text.
        Dim Matrix As New System.Drawing.Drawing2D.Matrix

        ' Set the SmoothingMode to high quality for best readability.
        e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.HighQuality

        ' Add the string to the path; declare the font, font style, size :
        path.AddString(s, Me.Font.FontFamily, 1, 20, Origine, SF)
        ' Set the rotation angle and starting point for the text.
        Matrix.RotateAt(ang, Centre)
        'utiliser  Matrix.Translate() si on veut déplacer le dessin après rotation

        ' Transform the path with the matrix.
        path.Transform(Matrix)
        ' Fill in the path to draw the string :
        e.Graphics.FillPath(Brushes.Red, path) 'tracé lettres pleines
        'e.Graphics.DrawPath(Pens.Red, path) 'tracé contour des lettres seulement

        'path.Reset() 'vide le path si on veut tracer d'autres choses
        'rotateMatrix.Reset() ' et remet à zéro la matrice 

        '+ centre de la rotation pour info :
        e.Graphics.DrawEllipse(Pens.Red, a, b, 2, 2)

        ' Dispose of the path.
        path.Dispose()

    End Sub 'méthode avec Drawing2D.Matrix et GraphicsPath

    Private Sub Animation()
        'lance l'animation

        Do While CheckBoxAnim.Checked
            angle += pas 'variables globales
            If angle > 360 Then angle -= 360.0F
            Me.Refresh()
            System.Windows.Forms.Application.DoEvents()
        Loop

    End Sub

End Class

Codes Sources

A voir également

Ajouter un commentaire

Commentaires

cs_bigboss9
Messages postés
162
Date d'inscription
jeudi 22 janvier 2004
Statut
Membre
Dernière intervention
20 juillet 2013
-
C'est bien et ca fait plaisir. Par contre :

- N'utilise pas New Pen(Color.Blue, 3) dans une instruction car tu ne peux plus libérer ton objet ensuite. A chaque fois que ta form est redessinée, il en créee un nouveau ! 1ère fuite de mémoire.

- Idem pour New Rectangle(), New Point(), etc...
- Pour des raisons d'optimisation, déclare le plus tes variables en dehors des procédures. Sinon, chaque fois que ta form est redessinée, tu réutilise de la mémoire pour rien.
- Ne fais pas de procédures qui dessinent. Utilise plutot une fonction qui te retourne ton GraphicPath. Cela te permet de séparer les actions, mieux évaluer le code et faciliter sa mise à jour et son élimination des bugs.

Concernant laquelle de ces deux méthodes choisir, on dira que cela dépends de leur rapidité. Il faudrait mesurer. De plus, les calculs ne sont pas le fort du .Net. L'utilisation d'une DLL écrite en C++ serait fort appréciable pour avoir de meilleures performances.

Et dire que je suis tyranique ... %)
cs_bigboss9
Messages postés
162
Date d'inscription
jeudi 22 janvier 2004
Statut
Membre
Dernière intervention
20 juillet 2013
-
Pour info :

A partir du Framework 3.0 je crois, on peut utiliser :

Using TempBrush as New LoineaGradientBrush(Me.ClientRectangle, Color.Red,Color.Blue,Gradient.Vertical)

'instructions
e.graphic.FillRectangle(Me.ClientRectangle, TempBrush

End Using

Au moment du End Using, il libère la ressource automatiquement.
Mais dans tous les cas et pour avoir testé, cela ne vaut pas la déclaration de tes variables en dehors des procédures/fonctions. En effet, le temps de libérer la mémoire, cela ralenti le processus de dessin.

A noter que cette méthode n'est valable que pour les objets disposants de l'interface IDisposable, c'est à dire comprenant la méthode Dispose().
Adn56
Messages postés
1220
Date d'inscription
jeudi 24 mai 2007
Statut
Membre
Dernière intervention
28 septembre 2013
1 -
comme le dit bigboss, y'a du flick ^^
essaye déja (gourmand mais bon) de placer ta form en doublebuffer=true,
cela évitera le clignotement de ta rotation ! dés plus désagréable à voir.
sinon bien vu les fonctions. Sauf pour animation() il doit y avoir mieux qu'un doevent non ?
bon j'suis pas pro, mais au pif...un timer ? un tread ?
@ suivre donc...et merci pour l'exemple.
kbalist
Messages postés
36
Date d'inscription
jeudi 28 janvier 2010
Statut
Membre
Dernière intervention
6 février 2011
-
merci de vos remarques qui me font progresser les gars...

pour BIGBOSS9 :
- j'ai rectifié le source pour tenir compte de ta remarque sur les fuites de mémoire avec des New dans les paramètres des fonctions. ça m'évoque 2 questions :

*comment vérifier qu'il n'y a pas de fuite de mémoire ? (le gestionnaire de programmes montre une mémoire très variable avec ou sans programme qui tourne)

*y a-t-il d'autres erreurs du même genre à ne pas faire ?

- j'ai plus de mal avec ta remarque :
"Pour des raisons d'optimisation, déclare le plus tes variables en dehors des procédures. Sinon, chaque fois que ta form est redessinée, tu réutilise de la mémoire pour rien."
faut-il comprendre que si j'utilise dans la routine DrawRotatedString un centre de rotation, il vaut mieux le déclarer et le définir dans la routine qui appelle DrawRotatedString (Form1_Paint dans mon exemple) et le passer en paramètre à DrawRotatedString , plutôt que de le définir dans DrawRotatedString elle-même ? ou le déclarer en global si c'est toujours le même ?

- pour résumer si j'ai bien compris : il vaudrait mieux déclarer le point-origine courant comme une variable globale avec

Dim Origine As PointF = New PointF(x1, y1)

et, après calculs, modifier Origine.x et Origine.y à chaque pas dans la routine Animation pour utiliser cette variable globale dans Form1_Paint ?

cela me gênait à priori car on m'a dit qu'il valait mieux utiliser des variables locales que globales.
de plus je voulais faire un exemple facile à réutiliser (copier-coller) par d'autres.

pour ADN56 : bonne remarque pour le double-buffer, j'oublie toujours !
c'est vrai que je ne pensais pas vraiment à l'aspect animation, j'ai fait celle-ci juste pour montrer comment utiliser les routines d'affichage du texte et de l'ellipse.

désolé si je suis trop long et si je pose trop de questions, mais je pense que cela peut permettre à d'autres autodidactes comme moi de faire des progrès sans perdre de temps à "réinventer la roue" ;-)

encore merci pour vos réponses et vos remarques constructives
Adn56
Messages postés
1220
Date d'inscription
jeudi 24 mai 2007
Statut
Membre
Dernière intervention
28 septembre 2013
1 -
Tes questions sont bonnes et tres justifiées !
J'ai essayé sur une source de base d'une horloge le changement conseillé par bigboss (car je pense comme toi au niveau des variables)
le résultat ?
ben mitigé, la source de base bouff 11Mo pour juste afficher une horloge analogique et augmente de 40Ko/sec.
Aprés avoir déclarer toutes mes variables dans le module de la form (comme le conseil bigboss) je ne bouff que 10MO et une augmentation que de 20Ko/sec !
donc à priori cela fontionne bien comme bigboss l'indique.
Seulement aprés 30minutes de marche de mes deux sources lancées simultannément, l'une atteind 15MO et continue d'augmenter et l'autre se stabilise à 13Mo !
Je vous laisse deviner celle qui se stabilise ^^
Celle qui utilise les variables dans les fonctions et qui les disposes à la fin. c'est pas trés clair pour moi.
Je ne suis pas assez 'pro' pour tout piger, mais si besoin je post les deux sources pour que vous puissiez y jeter un coup d'oeil. Je trouve tout de même assez lourd 14Mo de ressource, juste pour afficher une horloge ! non ?
++

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.