IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VB.NET Discussion :

Dessiner rectangles et pouvoir les déplacer


Sujet :

VB.NET

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    44
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 44
    Points : 26
    Points
    26
    Par défaut Dessiner rectangles et pouvoir les déplacer
    Bonjour,

    Je souhaiterai réaliser une petite appli pour le boulot où des utilisateurs créeraient des rectangles de couleurs et ensuite les rangeraient dans un certain ordre de couleur.

    Bref...,

    La partie création de rectangles, les couleurs pas de problème avec System.Drawing sur un picturebox.

    Par contre, une fois que j'ai mes rectangles, je ne vois pas par quelle technique les déplacer.

    1 - Par du cliquer-glisser-déposer en gérant les coordonnées (anciennes et nouvelles pour du "Annuler") sous forme de tableau où chaque nouveau rectangle possèderai ses anciennes coordonnées et ses nouvelles, ses dimensions, sa couleur. Programmation qui me semble sera très lourde.

    2 - Programmation orientée objet où chaque rectangle une fois dessiné créera une instance d'objet "Rectangle"

    Quelle est la meilleure des solutions? Y en a-t'il une autre?

    Si c'est la 2. Pourriez-vous me mettre sur la voie car je ne vois pas comment démarrer. Je connais un peu la POO mais ne la maitrise pas à fond.

    Je précise car je ne pense pas avoir été assez clair, je n'ai pas encore de code à montrer car il s'agit encore d'un projet. Mais comme je ne vois pas comment aboutir, je n'ai pas encore commencé car je réfléchi encore sur la solution.

    Merci pour votre aide.

  2. #2
    Membre averti Avatar de Saintelaitlait
    Homme Profil pro
    Responsable ServiceDesk
    Inscrit en
    Août 2011
    Messages
    179
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Canada

    Informations professionnelles :
    Activité : Responsable ServiceDesk
    Secteur : Service public

    Informations forums :
    Inscription : Août 2011
    Messages : 179
    Points : 355
    Points
    355
    Par défaut
    Bonjour, j'ai quelques petits indices pour toi, essaie de mettre cela en application. Tu aura besoin d'un timer pour mettre tout ca en place.

    tu travaillera avec un objet de tupe graphics
    dans ton Load tu fera :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
      Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Timer1.Enabled = True
            Timer1.Start()
            g = Me.CreateGraphics
    End Sub

    Tu devra avoir une classe rectangle qui ressemblera, grossièrement, à ceci.

    Liste des attributs
    -X (integer)
    -Y (integer)
    -height (integer)
    -width (integer)
    -Level (integer)
    -recColor (color)

    Tous ces attribut seront affectés lors de la création. Tu les utilisera lors du drawing.

    *Création des rectangles*
    tu stock tes rectangle dans un arraylist. Lors de la création, tu vérifie dans ton arraylist si le rectangle que tu essaie de crée sera par dessus. Tu vérifie donc si la position X,Y du rectangle que tu veux créer est comprise dans la superficie d'un des rectangle déjà créé. Si tu compte 3 rectangle qui sont en dessous, l'attribut level du rectangle que tu est en train créer sera donc 4. Pour l'instant, ton objet rectangle est créé, mais non affiché.

    *Gestion du déplacement*
    Lors du clique dans ton formulaire, récupère la localisation du click, ainsi que la couleur. Utilise la fonction getPixel sur ton bitmap dans lequel tu dessine pour récupérer la couleur sous la souris. Avec la localisation et la couleur, tu vérifie, dans ton array de rectangle, celui dont l'attribut recColor est égale a ce que retourne getPixel, et que la position de ta souris est dans sa superficie. Tu vérifie finalement son level pour prendre le plus ''haut'' si on veut.

    Donc si tu a 3 rectangle rouge qui se croise, et que tu clique a l'endoit où les 3 sont un par dessus l'autre, c'est celui avec le level le plus élevé qui sera ''sélectionner''. Tu appellera ensuite une méthode ( de ta classe rectangle) qui modifie ton point x et y en lui passant la position de ta souris.

    *Affichage*
    Donc, lorsque ta fonction qui dessine s'éxécutera, elle devra dessiner des rectangles, en fonction de ceux dans ton tableau d'objet rectangle, avec leur position (x,y) leur 'height' leur 'width' et leur 'recColor'.

    Tu devra premièrement vider ton graphics. Je met du blanc comme couleur de fond

    Deuxièment tu dessinera chaque rectangle dans ton arraylist de rectangle, l'utilisation du for each facilite grandement l'accès au attributs.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
      For Each Rectangle As Rectangle In rectArray
                    g.FillRectangle(New SolidBrush(recColor), Rectangle.X, Rectangle.Y, Rectangle.Width, Rectangle.Height)
    Next

    Donc si tu as bien compris, ton graphics sera vider et redessiner dans chaque tick de ton timer(35 milliseconde par tick c'est suffisant, ton affichage sera rafraîchie 28 fois par seconde!)

    C'est simple et compliqué en même temps

    Résumé.

    A chaque tick tu fait
    gestion des rectangle( création, déplacement)
    dessin des rectangle dans ton graphics

    Si tu n'a jamais utilisés les timers pour gérer les dessins, tu va probablement trouver ca très difficile à comprendre. Si tel est le cas, j'essaierai de t'expliquer ca plus en détails. Tu verra, une fois que tu aura saisi tu pourra faire plein de petits jeux genre tower defense, casse-tête et compagnie avec vb.net

    Bonne chance

  3. #3
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    44
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 44
    Points : 26
    Points
    26
    Par défaut
    Wouhaou

    Salut Saintelaitlait.

    Merci pour cette aide très fournie.

    Oui, j'ai compris.

    J'ai déjà utilisé le timer dans une appli de compte à rebours.
    Je n'aurai jamais pensé à l'utiliser pour rafraichir l'écran. Cela ne va-t'il pas utiliser trop de ressource?

    Je vois que le tableau pour les paramètres des rectangles est incontournable.

  4. #4
    Membre averti Avatar de Saintelaitlait
    Homme Profil pro
    Responsable ServiceDesk
    Inscrit en
    Août 2011
    Messages
    179
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Canada

    Informations professionnelles :
    Activité : Responsable ServiceDesk
    Secteur : Service public

    Informations forums :
    Inscription : Août 2011
    Messages : 179
    Points : 355
    Points
    355
    Par défaut
    Le tableau ne contient pas vraiment les paramètres des rectangles. Considère le plus comme une étagère dans laquelle tu range tes rectangles. Tu va chercher celui que tu veux, et tu vérifie sa largeur, hauteur etc..On l'utilise donc pour stocker tes objets de type rectangle!

    L'utilsation du timer n'est pas vraiment gourmande. Ajuste le pour qu'il tick entre 35 et 50 milisecondes. C'est suffisant car si mes souvenirs sont bon ton cerveau ne voit plus le rafraîchissement à partir de 24 image seconde, ca devient donc un vidéo! Juste comme ca, la télé est environ à 24 fps dépendamment des endroits.

    -> une seconde = 1000 miliseconde. Donc 1000/24 image seconde = 41.6 miliseconde. Donc pour avoir un fps semblable à la télévision tu devra ajuster ton timer a 40 ou 45 miliseconde. Perso je travail avec le timer à 35 miliseconde, mais sache que 40 ou 45 ca sera suffisant pour avoir une bonne fluidité.

    Donc en gros, plus tu fait ticker ton timer souvent, plus ton fps sera élevé

    J'ai fait un towerDefense il y a environ 1 an, et l'application commencait à avoir des ralentissement quand j'avais environ 30-40 magiciens, avec une cinquantaine d'ennemis, et environ 4-5 projectiles ou Laser par magicien.

    Donc dis toi que lorsque tu vérifie si chaque projectile de chaque magicien est en collision avec un des ennemies, c'est beaucoup plus de tour de boucle qu'avec tes rectangles! Donc selon moi ca va très bien rouler!

    Hésite pas à demander si tu a de la difficulté à comprendre le principe de gestion de ton image avec le timer, j'expliquerai cette partie plus en profondeur

    Et n'oublie pas, tu gère les rectangles, tu les dessines dans ton graphic qui s'affichera par lui même.(le type graphics s'affiche automatiquement)

    Si tu préfère gérer toi même le moment ou ton image sera affiché, tu devra travailler avec des bitmap et un container. Tu travaillera sur un bitmap en mémoire pendant qu'un autre est affiché. Comme le fait la bibliothèque graphique SDL( c,c++,python,java, etc..)


    Bonne chance!

  5. #5
    Rédacteur
    Avatar de SaumonAgile
    Homme Profil pro
    Team leader
    Inscrit en
    Avril 2007
    Messages
    4 028
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Team leader
    Secteur : Conseil

    Informations forums :
    Inscription : Avril 2007
    Messages : 4 028
    Points : 6 334
    Points
    6 334
    Par défaut
    Pourquoi ne pas utiliser des panels directement ? Voire même le composant Rectangle disponible dans le VisualBasic PowerPack ?
    Tu n'aurais plus qu'à gérer le MouseDown, MouseUp et le MouseMove pour détecter/gérer les mouvements.

  6. #6
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 177
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 177
    Points : 25 125
    Points
    25 125
    Par défaut
    il n'y a pas besoin de timer ... ca va faire bosser le pc pour rien
    parce que redessiner quelques chose 28 fois par seconde si l'utilisateur n'a rien fait ca ne sert pas à grand chose ...

    et en effet avec des panels (ou control même) ca fait juste quelques lignes de codes avec un peu de chance

  7. #7
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 442
    Points
    4 442
    Par défaut dessiner avec un controle shape rectangle
    bonjour jlm57
    Comme l'as dit pol63 .C'est encore plus simple si tu dessine avec un shape qui est un custom shape controle auquel tu donneras l'allure voulue avec la classe GraphicsPath de GDI+.
    Quant à la gestion de la liste des rectangles la collection Control.Controls s'en charge.
    Control etant soit un PictureBox(on ne pas helas scroller) soit de preference un Panel car il dispose du scrolling .

    Bref voici un customShape control qui dessine au choix un control de forme Rectangulaire,Ellipse ou Triangle (ou toute forme qui te plaira,y compris une image clippe....).
    Cliquable ,draggable , movable et resizable.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
     
    'NB: Les props BackColor, ForeColor, Location, ou
    'Size, sont construites ad-hoc dans le controle de base CustomShape.
    'ASTUCE:pour eviter de recreer brushes et pens chaque fois qu'une shape est dessinee, on peut creer brush
    '& pen une seule fois et les memoriser comme variables membres. 
    'Mais alors=>il faut 
    'soit : s'assurer chaque fois que Brush et Pen n'ont pas ete change  
    'avant de commencer à dessiner 
    'soit: implementer les evenements ForeColorChanged & BackColorChanged events.
    '
    '
    'Ajouter dans le Designer 
    '01 ContextMenuStrip nomme "mnuShape" 
    'et sa collection de 4 sous-menu:
    '-mnuFillColorChange
    '-mnuRemoveShape
    '-mnuBringToFront
    '-mnuBringToFront
    Imports System.Drawing.Drawing2D
    Public Class CustomShape
        Inherits System.Windows.Forms.Control
        'Met en surbrillance selection
        Private selectionForeColor As Color = Color.Yellow
        'BackStore du ForeColor pour retablir apres deselection
        Private oldForeColor As Color
     
        ' Shape courant.
        Private shape As ShapeType = ShapeType.Rectangle
        Private path As GraphicsPath
        ' le type de shapes supporte par ce controle.
        Public Enum ShapeType
            Rectangle
            Ellipse
            Triangle
        End Enum
     
        Public Sub New()
            ' Cet appel est requis par le Concepteur Windows Form.
            InitializeComponent()
            ' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
            'Affecte le ContextMenuStrip au controle
            Me.ContextMenuStrip = Me.mnuShape
            oldForeColor = Me.ForeColor
        End Sub
     
        Public Property Type() As ShapeType
            Get
                Return shape
            End Get
            Set(ByVal value As ShapeType)
                shape = value
                RefreshPath()
                Me.Invalidate()
            End Set
        End Property
        ' Cree le GraphicsPath correspondant pour shape, 
        ' et l'affecte à la prop Region du controle .
        ' Rappel: le Region d'un controle est sa zone interactive
        Private Sub RefreshPath()
            If path IsNot Nothing Then path.Dispose()
            path = New GraphicsPath()
            Select Case shape
                Case ShapeType.Rectangle
                    path.AddRectangle(Me.ClientRectangle)
                Case ShapeType.Ellipse
                    path.AddEllipse(Me.ClientRectangle)
                Case ShapeType.Triangle
                    Dim pt1 As Point = New Point(Me.Width / 2, 0)
                    Dim pt2 As Point = New Point(0, Me.Height)
                    Dim pt3 As Point = New Point(Me.Width, Me.Height)
                    path.AddPolygon(New Point() {pt1, pt2, pt3})
            End Select
            Me.Region = New Region(path)
        End Sub
        ' Redefinition  OnPaint
        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            MyBase.OnPaint(e)
            If path IsNot Nothing Then
                Dim shapeBrush As New SolidBrush(Me.BackColor)
                Dim shapePen As New Pen(Me.ForeColor, 5)
                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
                e.Graphics.FillPath(shapeBrush, path)
                e.Graphics.DrawPath(shapePen, path)
                shapePen.Dispose()
                shapeBrush.Dispose()
            End If
        End Sub
        ' Redefinition  OnResize
        Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
            MyBase.OnResize(e)
            RefreshPath()
            Me.Invalidate()
        End Sub
     
        'Enfin le  ConTextMenuStrip "mnuShape" propose 4 options. 
        '1ere , sur click autorise l'user à changer couleur 
        'de remplissage avec boite color dialog.
        'Le code retrouve le control shape actif avec la prop 
        'SourceControl du ContextMenuStrip
        Private Sub mnuColorChange_Click(ByVal sender As Object, ByVal e As EventArgs) Handles mnuFillColorChange.Click
            Dim colorDlg As New ColorDialog
            If colorDlg.ShowDialog() = DialogResult.OK Then
                Me.mnuShape.SourceControl.BackColor = colorDlg.Color
            End If
        End Sub
        '2eme  option autorise l'user à supprimer le shape courant selectionne.
        Private Sub mnuRemoveShape_Click(ByVal sender As Object, ByVal e As EventArgs) Handles mnuRemoveShape.Click
            Dim ctrl As Control
            ctrl = Me
            ctrl.Parent.Controls.Remove(Me)
        End Sub
        '2eme  option et 4eme option pour Z-Order.
        Private Sub mnuBringToFront_Click(ByVal sender As Object, ByVal e As EventArgs) Handles mnuBringToFront.Click
            Me.BringToFront()
        End Sub
        Private Sub mnuSendToBack_Click(ByVal sender As Object, ByVal e As EventArgs) Handles mnuSendToBack.Click
            Me.SendToBack()
        End Sub
        '- Click : selection du control position.
        '- Right-Click : affiche context menu, qui prevoit les option 
        ' -Delete Objet 
        ' -Change FillColor
        ' -BringToFront
        ' -SendToBack
        '- Click Coin Bas-Droit :redimensionnenement
     
        ' Garder une trace quand Dragging ou Redimensionnement sont actives.
        Private isDragging As Boolean = False
        Private isResizing As Boolean = False
        ' Memorise position ou l'user a clicke sur le controle.
        Private clickOffsetX, clickOffsetY As Integer
        Private Sub ctrl_MouseDown(ByVal sender As Object, _
        ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
            ' Retrouve une reference du shape actif.
            Dim currentCtrl As Control
            currentCtrl = CType(sender, Control)
            If e.Button = MouseButtons.Right Then
                ' Affiche context menu.
                mnuShape.Show(currentCtrl, New Point(e.X, e.Y))
     
            ElseIf e.Button = MouseButtons.Left Then
                '  Redimensionnement
                clickOffsetX = e.X
                clickOffsetY = e.Y
                If currentCtrl.Cursor = Cursors.SizeNWSE Or _
                currentCtrl.Cursor = Cursors.SizeNS Or _
                currentCtrl.Cursor = Cursors.SizeWE Then
                    ' pointeur souris est sur l'un des cotes 
                    ' aussi le redimensionnement est approprie.
                    isResizing = True
                Else
                    ' Sinon  Mode Dragging est approprie.
                    isDragging = True
                End If
            End If
        End Sub
     
        'MouseMove change position ou taille suivant mode "drag" ou "resize"
        'MouseMove change aussi le curseur (feedback user) à un "icon resize" 
        'pour alerter l'user quand pointeur souris est aligne sur l'un des cotes .
        Private Sub ctrl_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Me.MouseMove
            ' Retrouve une reference du shape Actif.
            Dim currentCtrl As Control
            currentCtrl = CType(sender, Control)
            If isDragging Then
                ' deplace controle shape.
                currentCtrl.Left = e.X + currentCtrl.Left - clickOffsetX
                currentCtrl.Top = e.Y + currentCtrl.Top - clickOffsetY
                currentCtrl.ForeColor = Me.selectionForeColor
            ElseIf isResizing Then
                ' Redimensionne control shape , suivant "resize mode".
                currentCtrl.ForeColor = Me.selectionForeColor
                If currentCtrl.Cursor = Cursors.SizeNWSE Then
                    currentCtrl.Width = e.X
                    currentCtrl.Height = e.Y
                ElseIf currentCtrl.Cursor = Cursors.SizeNS Then
                    currentCtrl.Height = e.Y
                ElseIf currentCtrl.Cursor = Cursors.SizeWE Then
                    currentCtrl.Width = e.X
                End If
            Else
                ' Change cursor si pointeur souris est sur  le cote droit et bas
                ' du controle shape.
                If (e.X + 5) > currentCtrl.Width And _
                (e.Y + 5) > currentCtrl.Height Then
                    currentCtrl.Cursor = Cursors.SizeNWSE
                ElseIf (e.X + 5) > currentCtrl.Width Then
                    currentCtrl.Cursor = Cursors.SizeWE
                ElseIf (e.Y + 5) > currentCtrl.Height Then
                    currentCtrl.Cursor = Cursors.SizeNS
                Else
                    ' ce curseur souris est le 4eme type de curseur pour le pointeur souris
                    ' utilise souvent pour deplacer les objets.
                    currentCtrl.Cursor = Cursors.SizeAll
                End If
            End If
        End Sub
        'MouseUp termine dragging et redimensionnement.
        Private Sub ctrl_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Me.MouseUp
            Me.ForeColor = Me.oldForeColor
            isDragging = False
            isResizing = False
        End Sub
     
     
    End Class
    et voici le form qui l'utilise situe dans le meme projet:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
     
    'Ajouter :
    '-un Control Panel scrollable 
    '-un ContextMenuStrip nomme "ctxMenuStripShapes" avec
    'sa collection de 3 sous-menus 
    '-ctxMnuAddRectangle
    '-ctxMnuAddEllipse
    '-ctxAddTriangle
    'NB:cet exemple un contexte menu propre au controle CustomShape et
    'un autre context menu propre au Form(qui aurait pus etre un menu)
    Public Class Form1
        Private shp As CustomShape
        Public Sub New()
     
            ' Cet appel est requis par le Concepteur Windows Form.
            InitializeComponent()
     
            ' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
            'Affecte le ContextMenuStrip au Form
            Me.ContextMenuStrip = Me.ctxMenuStripShapes
            Me.Panel1.Dock = DockStyle.Fill
            Me.Panel1.BackColor = Color.WhiteSmoke
            'Active le srolling
            Me.Panel1.AutoScroll = True
        End Sub
     
     
        Private Sub AddRectangle_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ctxMnuAddRectangle.Click
            shp = New CustomShape
            shp.Type = CustomShape.ShapeType.Rectangle
            shp.Width = 100
            shp.Height = 100
            shp.ForeColor = Color.Black
            'ajoute à liste Panel1
            Me.Panel1.Controls.Add(shp)
     
        End Sub
     
        Private Sub AddEllipse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ctxMnuAddEllipse.Click
            shp = New CustomShape
            shp.Type = CustomShape.ShapeType.Ellipse
            shp.Width = 100
            shp.Height = 60
            shp.ForeColor = Color.Black
            'ajoute à liste Panel1
            Me.Panel1.Controls.Add(shp)
     
        End Sub
     
        Private Sub addTriangle_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ctxMnuAddTriangle.Click
            shp = New CustomShape
            shp.Type = CustomShape.ShapeType.Triangle
            shp.Width = 100
            shp.Height = 100
            shp.ForeColor = Color.Black
            'ajoute à liste Panel1
            Me.Panel1.Controls.Add(shp)
     
        End Sub
    End Class
    Ceci aurait pu etre realise par "peinture des figures" avec une classe figure qui doit encapsuler :
    *proprietes : largeur,hauteur,forecolor,backolor,....une classe GrapicsPath PathGDI
    *methodes : PaintFigure(graphicsControlSite as graphics),InvalidateFigure(ControlSite as Control) plus la panoplie de methodes : MoveFigure(toX as Integer,toY as Integer),
    ResizFigure(width as Integer,height as Integer),HitTestFigure(pt as Point)
    Le principe est le meme mais l'utilisation du controle economise tout ce code de peinture.
    Sans compter que le controle peut etre teste sur le designer ce qui n'est le cas par la methode de "peinture des figures"(ou methode 2)...........

    Pour la sauvegarde de tes figures sur un fichier image :
    -rajoute une variable bmp as bitmap dans le form.
    -utilise Panel1.DrawToBitmap(bmp, Panel1.ClientRectangle)
    -bmp.Save(filename As string)bon code.................

    bon code....................

  8. #8
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    44
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 44
    Points : 26
    Points
    26
    Par défaut
    Salut à tous

    Merci pour toute cette aide.

    Je devrais pouvoir m'en sortir.

    Encore une question:
    Comment créer un effet de magnétisme lorsque 2 rectangles se rapprocheront, pour se coller parfaitement ajustés.

  9. #9
    Expert confirmé
    Inscrit en
    Avril 2008
    Messages
    2 564
    Détails du profil
    Informations personnelles :
    Âge : 64

    Informations forums :
    Inscription : Avril 2008
    Messages : 2 564
    Points : 4 442
    Points
    4 442
    Par défaut
    bonjour jlm57
    Pour obtenir le magnetisme ou "snapping" il faut une grille sur le control panel .

    Pour ce faire voici en plus du control CustomShape le code d'un control panel personnalise CustomPanelGrid avec une grille .

    De plus il faut modifier legerement le control CustomShape pour le faire "snapper" sur le CustomPanelGrid.

    Enfin un ContextMenu est rajoute sur le form pour activer ou desactiver la visibilite de la grille
    code du control CustomShape revu:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
     
    'Ajouter dans le Designer 
    '01 ContextMenuStrip nomme "mnuShape" 
    'et sa collection de 4 sous-menu:
    '-mnuFillColorChange
    '-mnuRemoveShape
    '-mnuBringToFront
    '-mnuBringToFront
    '***************************
    'Rajouter au controle customShape : 
    '-la procedure SnapToGrid
    '-et un appel à cette proc dans MouseMove
    Imports System.Drawing.Drawing2D
    Public Class CustomShape
        Inherits System.Windows.Forms.Control
        'Met en surbrillance selection
        Private selectionForeColor As Color = Color.Yellow
        'BackStore du ForeColor pour retablir apres deselection
        Private oldForeColor As Color
     
        ' Shape courant.
        Private shape As ShapeType = ShapeType.Rectangle
        Private path As GraphicsPath
        ' le type de shapes supporte par ce controle.
        Public Enum ShapeType
            Rectangle
            Ellipse
            Triangle
        End Enum
     
        Public Sub New()
            ' Cet appel est requis par le Concepteur Windows Form.
            InitializeComponent()
            ' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
            'Affecte le ContextMenuStrip au controle
            Me.ContextMenuStrip = Me.mnuShape
            oldForeColor = Me.ForeColor
        End Sub
     
        Public Property Type() As ShapeType
            Get
                Return shape
            End Get
            Set(ByVal value As ShapeType)
                shape = value
                RefreshPath()
                Me.Invalidate()
            End Set
        End Property
     
     
        ' Cree le GraphicsPath correspondant pour shape, 
        ' et l'affecte à la prop Region du controle .
        ' Rappel: le Region d'un controle est sa zone interactive
        Private Sub RefreshPath()
            If path IsNot Nothing Then path.Dispose()
            path = New GraphicsPath()
            Select Case shape
                Case ShapeType.Rectangle
                    path.AddRectangle(Me.ClientRectangle)
                Case ShapeType.Ellipse
                    path.AddEllipse(Me.ClientRectangle)
                Case ShapeType.Triangle
                    Dim pt1 As Point = New Point(Me.Width / 2, 0)
                    Dim pt2 As Point = New Point(0, Me.Height)
                    Dim pt3 As Point = New Point(Me.Width, Me.Height)
                    path.AddPolygon(New Point() {pt1, pt2, pt3})
            End Select
            Me.Region = New Region(path)
        End Sub
        ' Redefinition  OnPaint
        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            MyBase.OnPaint(e)
            If path IsNot Nothing Then
                Dim shapeBrush As New SolidBrush(Me.BackColor)
                Dim shapePen As New Pen(Me.ForeColor, 5)
                e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
                e.Graphics.FillPath(shapeBrush, path)
                e.Graphics.DrawPath(shapePen, path)
                shapePen.Dispose()
                shapeBrush.Dispose()
            End If
     
     
        End Sub
        ' Redefinition  OnResize
        Protected Overrides Sub OnResize(ByVal e As System.EventArgs)
            MyBase.OnResize(e)
            RefreshPath()
            Me.Invalidate()
        End Sub
     
        'Enfin le  ConTextMenuStrip "mnuShape" propose 4 options. 
        '1ere , sur click autorise l'user à changer couleur 
        'de remplissage avec boite color dialog.
        'Le code retrouve le control shape actif avec la prop 
        'SourceControl du ContextMenuStrip
        Private Sub mnuColorChange_Click(ByVal sender As Object, ByVal e As EventArgs) Handles mnuFillColorChange.Click
            Dim colorDlg As New ColorDialog
            If colorDlg.ShowDialog() = DialogResult.OK Then
                Me.mnuShape.SourceControl.BackColor = colorDlg.Color
            End If
        End Sub
        '2eme  option autorise l'user à supprimer le shape courant selectionne.
        Private Sub mnuRemoveShape_Click(ByVal sender As Object, ByVal e As EventArgs) Handles mnuRemoveShape.Click
            Dim ctrl As Control
            ctrl = Me
            ctrl.Parent.Controls.Remove(Me)
        End Sub
        '2eme  option et 4eme option pour Z-Order.
        Private Sub mnuBringToFront_Click(ByVal sender As Object, ByVal e As EventArgs) Handles mnuBringToFront.Click
            Me.BringToFront()
        End Sub
        Private Sub mnuSendToBack_Click(ByVal sender As Object, ByVal e As EventArgs) Handles mnuSendToBack.Click
            Me.SendToBack()
        End Sub
        '- Click : selection du control position.
        '- Right-Click : affiche context menu, qui prevoit les option 
        ' -Delete Objet 
        ' -Change FillColor
        ' -BringToFront
        ' -SendToBack
        '- Click Coin Bas-Droit :redimensionnenement
     
        ' Garder une trace quand Dragging ou Redimensionnement sont actives.
        Private isDragging As Boolean = False
        Private isResizing As Boolean = False
        ' Memorise position ou l'user a clicke sur le controle.
        Private clickOffsetX, clickOffsetY As Integer
        Private Sub ctrl_MouseDown(ByVal sender As Object, _
        ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
            ' Retrouve une reference du shape actif.
            Dim currentCtrl As Control
            currentCtrl = CType(sender, Control)
            If e.Button = MouseButtons.Right Then
                ' Affiche context menu.
                mnuShape.Show(currentCtrl, New Point(e.X, e.Y))
     
            ElseIf e.Button = MouseButtons.Left Then
                '  Redimensionnement
                clickOffsetX = e.X
                clickOffsetY = e.Y
                If currentCtrl.Cursor = Cursors.SizeNWSE Or _
                currentCtrl.Cursor = Cursors.SizeNS Or _
                currentCtrl.Cursor = Cursors.SizeWE Then
                    ' pointeur souris est sur l'un des cotes 
                    ' aussi le redimensionnement est approprie.
                    isResizing = True
                Else
                    ' Sinon  Mode Dragging est approprie.
                    isDragging = True
                End If
            End If
        End Sub
     
        'MouseMove change position ou taille suivant mode "drag" ou "resize"
        'MouseMove change aussi le curseur (feedback user) à un "icon resize" 
        'pour alerter l'user quand pointeur souris est aligne sur l'un des cotes .
        Private Sub ctrl_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Me.MouseMove
            ' Retrouve une reference du shape Actif.
            Dim currentCtrl As Control
            currentCtrl = CType(sender, Control)
            If isDragging Then
                ' deplace controle shape.
                currentCtrl.Left = e.X + currentCtrl.Left - clickOffsetX
                currentCtrl.Top = e.Y + currentCtrl.Top - clickOffsetY
                currentCtrl.ForeColor = Me.selectionForeColor
                'RAJOUT CETTE LIGNE 
                Call SnapToGrid(currentCtrl)
            ElseIf isResizing Then
                ' Redimensionne control shape , suivant "resize mode".
                currentCtrl.ForeColor = Me.selectionForeColor
                If currentCtrl.Cursor = Cursors.SizeNWSE Then
                    currentCtrl.Width = e.X
                    currentCtrl.Height = e.Y
                ElseIf currentCtrl.Cursor = Cursors.SizeNS Then
                    currentCtrl.Height = e.Y
                ElseIf currentCtrl.Cursor = Cursors.SizeWE Then
                    currentCtrl.Width = e.X
                End If
            Else
                ' Change cursor si pointeur souris est sur  le cote droit et bas
                ' du controle shape.
                If (e.X + 5) > currentCtrl.Width And _
                (e.Y + 5) > currentCtrl.Height Then
                    currentCtrl.Cursor = Cursors.SizeNWSE
                ElseIf (e.X + 5) > currentCtrl.Width Then
                    currentCtrl.Cursor = Cursors.SizeWE
                ElseIf (e.Y + 5) > currentCtrl.Height Then
                    currentCtrl.Cursor = Cursors.SizeNS
                Else
                    ' ce curseur souris est le 4eme type de curseur pour le pointeur souris
                    ' utilise souvent pour deplacer les objets.
                    currentCtrl.Cursor = Cursors.SizeAll
                End If
            End If
        End Sub
        'MouseUp termine dragging et redimensionnement.
        Private Sub ctrl_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs) Handles Me.MouseUp
            Me.ForeColor = Me.oldForeColor
            isDragging = False
            isResizing = False
        End Sub
        'RAJOUT CETTE PROCEDURE QUI POSITION LE CONTROLE
        'CUSTOMSHAPE SUR LA GRILLE
        Public Sub SnapToGrid(ByVal ctrl As Control)
     
            'This blue bit of code will do that
            Dim parentCtrl As CustomPanelGrid = CType(ctrl.Parent, CustomPanelGrid)
            If parentCtrl IsNot Nothing Then
                Dim sizeGrid As Size = parentCtrl.GridSpacing
                Dim x1, y1 As Double
                x1 = ctrl.Location.X
                y1 = ctrl.Location.Y
     
                x1 = Math.Round(x1 / sizeGrid.Width) * sizeGrid.Width
                y1 = Math.Round(y1 / sizeGrid.Width) * sizeGrid.Width
                ctrl.Location = New Point(CInt(x1), CInt(y1))
            End If
        End Sub
    End Class
    code du control CustomPanelGrid personnalise avec une grille 10x10(à personnaliser):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
     
    'Control CustomPanelGrid  herite de Panel
    'Ajouter dans le Designer 
    '01 ContextMenuStrip nomme "ctxMnuGrid" 
    'et un 01 sous-menu:
    '-mnuShowGrid
    Public Class CustomPanelGrid
        Inherits Panel
        'backstore  liste des points de la grille 
        Private gridPoints() As Point
        Private m_showGrid As Boolean
        Private m_gridSpacing As Size
        Public Sub New()
     
            ' Cet appel est requis par le Concepteur Windows Form.
            InitializeComponent()
     
            ' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
            '
            'Active le mode DoubleFuffer et UserPaint
            'pour eviter le fickering 
            '
            Me.SetStyle(ControlStyles.DoubleBuffer, True)
            Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
            Me.SetStyle(ControlStyles.ResizeRedraw, True)
            Me.SetStyle(ControlStyles.UserPaint, True)
            Me.SetStyle(ControlStyles.SupportsTransparentBackColor, True)
            'initialise l'espacement grille
            m_gridSpacing = New Size(10, 10)
        End Sub
        Public Property GridSpacing() As Size
            Get
                Return m_gridSpacing
            End Get
            Set(ByVal value As Size)
                m_gridSpacing = value
                Me.Invalidate()
            End Set
        End Property
        Public Property ShowGrid() As Boolean
            Get
                Return m_showGrid
            End Get
            Set(ByVal value As Boolean)
                m_showGrid = value
                Me.Invalidate()
            End Set
        End Property
        Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
            MyBase.OnPaint(e)
     
            'Ajoutez ici votre code de dessin personnalisé
            'Rajout d'une grille pour le snapping
            If ShowGrid Then
                'Dim m_gridSpacing As New Size(10, 10)
                Dim myPen As New Pen(Color.LightGray, 1)
     
                For x As Integer = 0 To Me.Width Step m_gridSpacing.Width
                    e.Graphics.DrawLine(myPen, x, 0, x, Me.Height)
                Next
                For y As Integer = 0 To Me.Height Step m_gridSpacing.Height
                    e.Graphics.DrawLine(myPen, 0, y, Me.Width, y)
                Next
     
                Dim myList As New List(Of Point)
                For x As Integer = 0 To Me.Height Step m_gridSpacing.Height
                    For y As Integer = 0 To Me.Height Step m_gridSpacing.Height
                        myList.Add(New Point(x, y))
                    Next
                Next
     
                'Put the list of gridPoints in the array called "gridPoints".>>
                gridPoints = myList.ToArray
            End If
        End Sub
     
     
    End Class
    code du winform de test revu:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
     
    'Ajouter :
    '-un Control CustomPanelGrid scrollable 
    '-un ContextMenuStrip nomme "ctxMenuStripShapes" avec
    'sa collection de 3 sous-menus 
    '-ctxMnuAddRectangle
    '-ctxMnuAddEllipse
    '-ctxMnuAddTriangle
    'Rajouter un sous-menu aux precedent pour gerer la grille:
    '-ctxMnuShowGrid
    'NB:cet exemple comporte un contexte menu propre au controle CustomShape et
    'un autre context menu propre au Form(qui aurait pus etre un menu)
    Public Class frmTestCustomShape
     
        Private shp As CustomShape
        Public Sub New()
     
            ' Cet appel est requis par le Concepteur Windows Form.
            InitializeComponent()
     
            ' Ajoutez une initialisation quelconque après l'appel InitializeComponent().
            'Affecte le ContextMenuStrip au Form
            Me.ContextMenuStrip = Me.ctxMenuStripShapes
            Me.CustomPanelGrid1.Dock = DockStyle.Fill
            Me.CustomPanelGrid1.BackColor = Color.WhiteSmoke
            'Active le srolling
            Me.CustomPanelGrid1.AutoScroll = True
            'Desactive la grille par defaut
            Me.CustomPanelGrid1.ShowGrid = False
        End Sub
     
     
        Private Sub AddRectangle_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CtxMnuAddRectangle.Click
            shp = New CustomShape
            shp.Type = CustomShape.ShapeType.Rectangle
            shp.Width = 100
            shp.Height = 100
            shp.ForeColor = Color.Black
            'ajoute à liste CustomPanelGrid1
            Me.CustomPanelGrid1.Controls.Add(shp)
     
        End Sub
     
        Private Sub AddEllipse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CtxMnuAddEllipse.Click
            shp = New CustomShape
            shp.Type = CustomShape.ShapeType.Ellipse
            shp.Width = 100
            shp.Height = 60
            shp.ForeColor = Color.Black
            'ajoute à liste CustomPanelGrid1
            Me.CustomPanelGrid1.Controls.Add(shp)
     
        End Sub
     
        Private Sub addTriangle_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ctxMnuAddTriangle.Click
            shp = New CustomShape
            shp.Type = CustomShape.ShapeType.Triangle
            shp.Width = 100
            shp.Height = 100
            shp.ForeColor = Color.Black
            'ajoute à liste CustomPanelGrid1
            Me.CustomPanelGrid1.Controls.Add(shp)
     
        End Sub
     
     
        Private Sub ctxMnuShowGrid_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ctxMnuShowGrid.Click
            Me.CustomPanelGrid1.ShowGrid = Not Me.CustomPanelGrid1.ShowGrid
            Me.ctxMnuShowGrid.Checked = Not Me.ctxMnuShowGrid.Checked
        End Sub
     
     
    End Class
    A l'utilisation pour aligner un control le deplacer .........
    bon code................

  10. #10
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Avril 2008
    Messages
    44
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2008
    Messages : 44
    Points : 26
    Points
    26
    Par défaut
    Merci à tous pour votre aide.

    Je devrai pouvoir m'en sortir avec toutes ces idées.

    Merci encore.

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Février 2010
    Messages
    291
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : France

    Informations forums :
    Inscription : Février 2010
    Messages : 291
    Points : 390
    Points
    390
    Par défaut
    Bonjour,

    La méthode la plus simple pour déplacer un rectangle est d'utiliser les RasterOP qui ne sont malheureusement pas fournies avec GDI+.
    Pour ce faire il suffit d'utiliser l'API :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Private Declare Function SetROP2 Lib "gdi32" (ByVal hdc As IntPtr, ByVal nDrawMode As Intptr) As Intptr
    Ce pour dessiner en mode XOR

    Je dessine mon rectangle
    Je stocke ses coordonnées

    Mouse_move: je passe en mode XOR je dessine au anciennes coordonnées (cela efface le recatangle)
    Le passe en mode normal:
    Je dessine aux nouvelles coordonnées

    Etc ...

Discussions similaires

  1. dessiner une ligne et la déplacer
    Par salihovic dans le forum Windows Forms
    Réponses: 6
    Dernier message: 14/03/2008, 10h58
  2. Dessiner rectangle de selection inversé.
    Par quentinthib dans le forum OpenGL
    Réponses: 2
    Dernier message: 27/08/2007, 00h44
  3. C# dessiner Rectangle (drawRectangle)
    Par jeromeke22 dans le forum Windows Forms
    Réponses: 4
    Dernier message: 09/05/2007, 19h42
  4. Réponses: 2
    Dernier message: 21/02/2007, 12h54
  5. [VB.NET] [newbie] Charger plusieurs .X et les déplacer
    Par tamagotchi dans le forum DirectX
    Réponses: 12
    Dernier message: 12/04/2006, 11h45

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo