dcsimg
Results 1 to 24 of 24

Thread: add rectangle to drawing

  1. #1

    Thread Starter
    Junior Member
    Join Date
    Oct 2016
    Posts
    22

    Post add rectangle to drawing

    hello,

    i am student automation and im searching for code to add a rectangle to a form via an button and drag the rectangle to somewhere and let it stay there, when i push the add button again an second rectangle appears and is able to move, i have searched the internet but has not found anything. i need this because i am writing palletising software for industrial robots.

    hopefully someone can help me. thankyou

  2. #2
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    32,389

    Re: add rectangle to drawing

    You might look into the Visual Basics Powerpacks, which might add additional functionality, but the way I'd do this is to have a List(of Drawing.Rectangle) at form scope. You could draw directly on the form by handling the Paint event, though you might also consider putting a panel or picturebox on the form and drawing in that. I'm not sure that there is much of an advantage to one or the other, except that the panel or picturebox could be a different color than the form and therefore make a visual "drawing area" within the form.

    Either way, in the Paint event, you'd draw all the rectangles in the list of rectangles using the Graphics object that is supplied in the e argument of the Paint event. So, you'd be using e.Graphics.DrawRectangle for an outline or FillRectangle for a filled rectangle. That would cover the drawing.

    To move the rectangles, you'd be handling the MouseDown event and checking whether the mouse location was inside one of the rectangles. If it was, then you'd note which one it was in, and the mouse location. Then, on the MouseUp event you'd figure the difference between the point where the mouse was pressed (the mouse location from MouseDown) and the current location (the mouse location from MouseUp). The difference in the X and Y between these two would give you the amount to move the rectangle, because you'd simply be moving the location of the rectangle by the same amount.
    My usual boring signature: Nothing

  3. #3
    Hyperactive Member
    Join Date
    Aug 2014
    Posts
    285

    Re: add rectangle to drawing

    Yes, I was about to say either you can draw them as graphics OR simply create a new shape control and move around, but then I checked visual studio and that control appears to have been removed (renamed?) since the days of vb6.

    Also, not sure what you mean by "able to move". By mouse? By keyboard? By a robot?

    Do some checkup on keydown/mouse events (whichever you prefer) and gdi+ drawing.
    Both of them are userfriendly and easy to learn functions.

  4. #4

    Thread Starter
    Junior Member
    Join Date
    Oct 2016
    Posts
    22

    Re: add rectangle to drawing

    yes be able to move by mouse i have written this code but it does not work at all

    Code:
      Private Sub Button_Add_Box_Click(sender As Object, e As EventArgs) Handles Button_Add_Box.Click
            ReDim array_addbox(+1)
            ReDim array_rectangle(+1)
            For i As Integer = array_addbox.Length() To array_addbox.Length()
                ReDim array_manually_ypos(array_addbox.Length() - 1)
                ReDim array_manually_xpos(array_addbox.Length() - 1)
                For j As Integer = array_manually_xpos.Length() - 1 To array_manually_xpos.Length()
                    array_manually_xpos(j) = 150
                    For k As Integer = array_manually_ypos.Length() - 1 To array_manually_ypos.Length()
                        array_manually_ypos(k) = 50
    
                    Next
                Next
            Next
    
            Refresh()
        End Sub
        Private Sub GraphicForm_manually_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
    
            If e.Button = MouseButtons.Left Then
                For j As Integer = array_manually_xpos.Length() - 1 To array_manually_xpos.Length()
                    array_manually_xpos(j) = e.X
                    For k As Integer = array_manually_ypos.Length() - 1 To array_manually_ypos.Length()
                        array_manually_ypos(k) = e.Y
    
                    Next
                Next
            End If
    
        End Sub
    
    
        Private Sub GraphicForm_manually_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
            'tekenen van de pallet met vorig geconverteerde waardes
            Dim Mypen As New Pen(Color.Blue, 2)
            e.Graphics.DrawRectangle(Mypen, 20, 20, lengthpalletvalue_s, widthpalletvalue_s)
            For i As Integer = array_manually_xpos.Length() - 1 To array_manually_xpos.Length()
                For j As Integer = array_manually_ypos.Length - 1 To array_manually_ypos.Length()
                    e.Graphics.DrawRectangle(Mypen2, array_manually_xpos(i - 1), array_manually_ypos(j), lengthboxvalue_s, widthboxvalue_s)
                Next
            Next
    
    
    
    
        End Sub

  5. #5
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    32,389

    Re: add rectangle to drawing

    First off, look into the List(of T). You shouldn't be doing all that Redim stuff. That tells me that you are using arrays that you are sizing dynamically. The List has an .Add method that does the same, but does it much more efficiently. In this case, you'd be using a List(of Drawing.Rectangle) as I mentioned earlier.

    The second thing you need to do is put a breakpoint on the first For loop and step through the code. Your loops are pretty badly messed up the way they are written. You are consistent with the mistake, so it's pretty fundamental. For example, you have this:
    Code:
    For i As Integer = array_manually_xpos.Length() - 1 To array_manually_xpos.Length()
    If the array has 5 elements in it, that would iterate through elements 5 and 6. Of course, there isn't an element 6, so it will crash on the second iteration. What you really wanted was:
    Code:
    For i As Integer = 0 To array_manually_xpos.Length()=1
    I would also say that using two arrays, one for x and one for y, is not a great way to go about it anyways. The List(of Rectangle) would allow you to build rectangles, without which you pretty much have no hope of dealing with mouse down efficiently. An alternative might be a List(of Point) such that the X and Y would stay together, at least, but you'd still have no hope of dealing with the mouse down effectively.
    My usual boring signature: Nothing

  6. #6
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,583

    Re: add rectangle to drawing

    I didn't really look at your code, but I thought it would be an easy enough task to quickly write an example before heading out the door that worked sort of along the lines of what you probably want to do.

    As, Shaggy Hiker mentioned, this uses List(Of T) to track the rectangle objects.
    It uses a small class to keep the information for the rectangle object together. I added things like a translucent fill color, and a border color, so that you can see overlapping rectangles.

    I use two lists to hold the references to the rectangle objects.
    One is used for drawing the objects, so the first drawn object is the "lowest" object, i.e. the bottom object.
    The second list is maintained in reverse order of the drawing list, so the first object is the "highest" object, i.e. the top object.

    The second list is used for "hit testing", so if rectangles overlap the highest rectangle that contains the point is the one selected.

    Hold the shift key down and click to create a rectangle.
    Drag on the rectangle with the left mouse button to move the rectangle.
    Drag on the rectangle with the right mouse button to change the size of the rectangle.

    p.p.s Just for kicks, added code to highlight the rectangle the mouse is over if not dragging.
    Code:
    Public Class Form1
      Private rand As New Random
    
      Private Class RectangleObject
        Public rect As Rectangle
        Public fillColor As Color
        Public OutLine As Color
        Public Sub draw(g As Graphics)
          Using br As New SolidBrush(Color.FromArgb(200, fillColor))
            Using pn As New Pen(OutLine, 3)
              g.FillRectangle(br, rect)
              g.DrawRectangle(pn, rect)
            End Using
          End Using
        End Sub
      End Class
    
      Private hitList As New List(Of RectangleObject)
      Private drawList As New List(Of RectangleObject)
      Private activeRect As RectangleObject
      Private overRect As RectangleObject
    
      Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        DoubleBuffered = True
        Text = "Hold Shift key, and drag mouse to create rectangles"
      End Sub
    
      Private Sub Form1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
        If My.Computer.Keyboard.ShiftKeyDown Then
          activeRect = New RectangleObject
          activeRect.fillColor = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255))
          activeRect.OutLine = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255))
          activeRect.rect = New Rectangle(e.Location, New Size(15, 15))
          drawList.Add(activeRect)
          hitList.Clear()
          hitList.AddRange(drawList.ToArray.Reverse) 'will reverse the order, so we can draw in Z-order (first in rectList is drawn last, so is on top)
          Invalidate()
        Else
          activeRect = FindRectangleAt(e.Location)
        End If
      End Sub
    
      Private Function FindRectangleAt(pnt As Point) As RectangleObject
        For Each r In hitList
          If r.rect.Contains(pnt) Then
            Return r
          End If
        Next
        Return Nothing
      End Function
    
      Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
        Static lpos As Point
        Static lrect As RectangleObject
    
        If activeRect IsNot Nothing Then
          With activeRect
            If e.Button = Windows.Forms.MouseButtons.Left Then
              .rect.Location += New Size(e.X - lpos.X, e.Y - lpos.Y)
            ElseIf e.Button = Windows.Forms.MouseButtons.Right Then
              .rect.Width += e.X - lpos.X
              .rect.Height += e.Y - lpos.Y
              If .rect.Width < 5 Then .rect.Width = 5 'don't allow to go too small
              If .rect.Height < 5 Then .rect.Height = 5
            End If
          End With
          Invalidate()
    
        Else  'Not dragging, highlight the rectangle the cursor is over
          overRect = FindRectangleAt(e.Location)
          If overRect IsNot lrect Then Invalidate()
          lrect = overRect
        End If
        lpos = e.Location
      End Sub
    
      Private Sub Form1_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
        activeRect = Nothing
      End Sub
    
      Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        For Each r As RectangleObject In drawList
          r.draw(e.Graphics)
        Next
    
        'Highlight the rectangle that the cursor is over (will pick if clicked)
        If overRect IsNot Nothing Then
          Using br As New SolidBrush(Color.FromArgb(128, Color.White))
            e.Graphics.FillRectangle(br, overRect.rect)
          End Using
        End If
      End Sub
    End Class
    p.s Here's another example of dragging rectangles around.
    In this case, the rectangles contain images of playing cards.
    Last edited by passel; Oct 31st, 2016 at 06:45 PM. Reason: make the fillcolor less translucent, changed class level Dims to Privates

  7. #7

    Thread Starter
    Junior Member
    Join Date
    Oct 2016
    Posts
    22

    Re: add rectangle to drawing

    thank you verry verry much for your help! this will help me way further that i was able to. now i will try to make the code working for my palletising program, again thank you

  8. #8

    Thread Starter
    Junior Member
    Join Date
    Oct 2016
    Posts
    22

    Re: add rectangle to drawing

    hello, i implemented the code of passel in my project but now i am searching how to delete the selected rectangle. another question is, are all the coordinates of the rectangles in the hitlist list?
    Code:
    Imports Microsoft.VisualBasic.PowerPacks
    Public Class GraphicForm_manually
        Dim lengthpalletvalue_s As Int64
        Dim widthpalletvalue_s As Int64
        Dim lengthboxvalue_s As Int64
        Dim widthboxvalue_s As Int64
        Private rand As New Random
        Dim rotate As Boolean
    
    
    
        Private Sub GraphicForm_manually_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    
    
    
    
    
            'converteren van double naar een 64 integer om te kunnen gebruiken voor Draw en voor het FormDesign
            lengthpalletvalue_s = Convert.ToInt64(Val(MainPalletizer.lengthpallet.Text))
            widthpalletvalue_s = Convert.ToInt64(Val(MainPalletizer.widthpallet.Text))
            lengthboxvalue_s = Convert.ToInt64(Val(MainPalletizer.lengthbox.Text))
            widthboxvalue_s = Convert.ToInt64(Val(MainPalletizer.widthbox.Text))
            Me.Size = New Size((widthpalletvalue_s + 200), (lengthpalletvalue_s + 60))
    
            Button_Add_Box.Location = New Point((widthpalletvalue_s + 40), 10)
            Button_Delete_Box.Location = New Point((widthpalletvalue_s + 40), 40)
            Button_Next_Layer.Location = New Point((widthpalletvalue_s + 40), 70)
            Button_Previous_Layer.Location = New Point((widthpalletvalue_s + 40), 100)
            Button_90_clockwise.Location = New Point((widthpalletvalue_s + 40), 130)
    
    
    
        End Sub
        Private Class RectangleObject
            Public rect As Rectangle
            Public fillColor As Color
            Public OutLine As Color
            Public Sub draw(g As Graphics)
                Using br As New SolidBrush(Color.FromArgb(200, fillColor))
                    Using pn As New Pen(OutLine, 3)
                        g.FillRectangle(br, rect)
                        g.DrawRectangle(pn, rect)
                    End Using
                End Using
            End Sub
        End Class
    
        Private hitList As New List(Of RectangleObject)
        Private drawList As New List(Of RectangleObject)
        Private activeRect As RectangleObject
        Private overRect As RectangleObject
    
        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            DoubleBuffered = True
            Text = "Click add box to start designing pallet"
        End Sub
    
        Private Sub Form1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
            If My.Computer.Keyboard.ShiftKeyDown Then
                activeRect = New RectangleObject
                activeRect.fillColor = Color.FromArgb(255,255,255)
                activeRect.OutLine = Color.FromArgb(255, 0, 0)
                activeRect.rect = New Rectangle(e.Location, New Size(lengthboxvalue_s, widthboxvalue_s))
                drawList.Add(activeRect)
                hitList.Clear()
                hitList.AddRange(drawList.ToArray.Reverse) 'will reverse the order, so we can draw in Z-order (first in rectList is drawn last, so is on top)
                Invalidate()
            Else
                activeRect = FindRectangleAt(e.Location)
            End If
    
        End Sub
    
        Private Function FindRectangleAt(pnt As Point) As RectangleObject
            For Each r In hitList
                If r.rect.Contains(pnt) Then
                    Return r
                End If
            Next
            Return Nothing
        End Function
    
        Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
            Static lpos As Point
            Static lrect As RectangleObject
    
            If activeRect IsNot Nothing Then
                With activeRect
                    If e.Button = MouseButtons.Left Then
                        .rect.Location += New Size(e.X - lpos.X, e.Y - lpos.Y)
                    ElseIf e.Button = MouseButtons.Right Then
                        .rect.Size = New Size(widthboxvalue_s, lengthboxvalue_s)
    
                    End If
    
                End With
                Invalidate()
    
            Else  'Not dragging, highlight the rectangle the cursor is over
                overRect = FindRectangleAt(e.Location)
                If overRect IsNot lrect Then Invalidate()
                lrect = overRect
            End If
            lpos = e.Location
        End Sub
    
        Private Sub Form1_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
            activeRect = Nothing
        End Sub
    
        Private Sub Form1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
            e.Graphics.DrawRectangle(Pens.Blue, 20, 20, lengthpalletvalue_s, widthpalletvalue_s)
            For Each r As RectangleObject In drawList
                r.draw(e.Graphics)
            Next
    
            'Highlight the rectangle that the cursor is over (will pick if clicked)
            If overRect IsNot Nothing Then
                Using br As New SolidBrush(Color.FromArgb(128, Color.White))
                    e.Graphics.FillRectangle(br, overRect.rect)
                End Using
            End If
        End Sub
    
        Private Sub Button_90_clockwise_Click(sender As Object, e As EventArgs)
            rotate = True
        End Sub
    End Class

  9. #9
    Super Moderator Shaggy Hiker's Avatar
    Join Date
    Aug 2002
    Location
    Idaho
    Posts
    32,389

    Re: add rectangle to drawing

    They are both in HitList AND in DrawList, since one is just the reverse of the other. So, to delete, you'd first find the right rectangle, then use the .Remove method of the List to remove the RectangleObject from both lists.

    How you'd find the right rectangle is a different matter, since you're already using MouseDown. You could use the right mouse button by changing that code a bit, or you could check for some other key.
    My usual boring signature: Nothing

  10. #10
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,583

    Re: add rectangle to drawing

    Been busy so not on the forum.
    As Shaggy says there are any number of ways from the GUI (i.e. the user input) to implement the deletion action, so how you decide to do it is up to you.

    As a quick test though, I just added a bit of code to the MouseUp event of the example code from post #6 to check to see if the control key is down when the MouseUp event occurs.
    If it is, it removes the rectangle from the two lists.

    You can hold the control key down and click on rectangles to delete them, or you could click and drag a rectangle out to make sure it is the one you want, and then hold down the control key as you release the mouse button to delete the rectangle.
    Code:
      Private Sub Form1_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
        If My.Computer.Keyboard.CtrlKeyDown Then
          If activeRect IsNot Nothing Then
            hitList.Remove(activeRect)
            drawList.Remove(activeRect)
          End If
        End If
    
        activeRect = Nothing
      End Sub
    p.s. Also, if you press the ctrl-key and then realize you don't want to delete the rectangle, you can just release the ctrl-key and (if you haven't released the mouse button yet), the rectangle won't be deleted, i.e. the ctrl-key isn't latched, it has to be down at the time the mouse button is released to cause the deletion.
    Last edited by passel; Nov 3rd, 2016 at 09:00 AM.

  11. #11
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,583

    Re: add rectangle to drawing

    Quote Originally Posted by baptistverm View Post
    ..., are all the coordinates of the rectangles in the hitlist list? ...
    To expand a bit on what Shaggy Hiker said, the lists are really a list of references to the instances of the RectangleObject classes.
    Technically, the RectangleObject instance itself exist somewhere in memory, and both lists have a reference that "points" to that instance. Either list can be use to access the object.

    Now, perhaps I didn't really need to create two lists. I was thinking at the time, that looping backward through the list to access the rectangles might be slower than having a copy of the list in the reverse order and just looping through it using For Each.
    But since the list should be using an array internally, that might not be the case.

    I haven't tested it, but I suppose I will in the near future.
    If looping through the list in reverse isn't much slower, I would change the hit search to loop through the draw list in reverse, and only use one list.

  12. #12

    Thread Starter
    Junior Member
    Join Date
    Oct 2016
    Posts
    22

    Re: add rectangle to drawing

    so now the adding and dragging rectangles works good but for my palletising option i need to add a button to go to an next layer, that means that there is again a blanc screen where i can add and move rectangles but is above the previous layer, i need to be able to also go back and see the previous designed layer, so how would i do that? also boxes on one layer may not overlap each other. i am struggeling to go to next layer, i am able to go to a next layer but not go back and see the previous designed layer.

  13. #13
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,583

    Re: add rectangle to drawing

    You just need another layer of hierarchy.
    In this case, I would make either an array of lists, if I new I wanted to have a set number of levels at the start of the program.
    If I wanted a more general flexible capability, then a List of Lists would be the way I would go.

    Once you have a list of lists, you can add whatever layer display filtering you want, by selectively drawing a list or not, i.e. you could only show a particular level, or several selected levels, or all the levels at the same time.
    You could make all shown levels dragable (move down the lists in zorder), or only the current selected layer.

    If you haven't done it already, I think I would make the change mentioned earlier to just have the one list, looping through it backwards for hit testing.
    Having two lists of lists should work fine, but seems a bit bulkier and probably generates a bit more garbage that has to be cleaned up, although the number of pallets is probably not that extensive to cause any noticeable effect.
    Last edited by passel; Nov 8th, 2016 at 07:48 AM.

  14. #14

    Thread Starter
    Junior Member
    Join Date
    Oct 2016
    Posts
    22

    Re: add rectangle to drawing

    hmmm i dont realy understand but i had created a new list that indecates how much boxes are on a layer and how much layers there are. with the number of boxes on a layer i would create an offset for the paint event to paint only the boxes on the next layer

    maybe i am searching it to far.?

    this is my code
    Code:
    Public Class GraphicForm_manually
        Dim lengthpalletvalue_s As Int64
        Dim widthpalletvalue_s As Int64
        Dim lengthboxvalue_s As Int64
        Dim widthboxvalue_s As Int64
        Dim heightboxvalue_s As Int64
        Private rand As New Random
        Dim rotate As Boolean
    
        Dim layernr As Integer
        Dim startheight As Integer
        Dim Graphics As Graphics
        Dim nextlayer As Boolean
        Dim max_aantaldozen_op_pallet As Integer
    
        'collisiondetect'
    
    
        Private Sub GraphicForm_manually_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            startheight = 0
    
    
    
    
            'converteren van double naar een 64 integer om te kunnen gebruiken voor Draw en voor het FormDesign
            max_aantaldozen_op_pallet = Convert.ToInt64(MainPalletizer.numberofboxesonpalletlayer)
            lengthpalletvalue_s = Convert.ToInt64(Val(MainPalletizer.lengthpallet.Text))
            widthpalletvalue_s = Convert.ToInt64(Val(MainPalletizer.widthpallet.Text))
            heightboxvalue_s = Convert.ToInt64(Val(MainPalletizer.heightbox.Text))
            lengthboxvalue_s = Convert.ToInt64(Val(MainPalletizer.lengthbox.Text))
            widthboxvalue_s = Convert.ToInt64(Val(MainPalletizer.widthbox.Text))
            Me.Size = New Size((widthpalletvalue_s + 200), (lengthpalletvalue_s + 60))
    
            'knoppen op de juiste positiers plaatsen
            Button_Next_Layer.Location = New Point((widthpalletvalue_s + 40), 70)
            Button_Previous_Layer.Location = New Point((widthpalletvalue_s + 40), 100)
    
    
    
    
        End Sub
        Private Class RectangleObject
            Public rect As Rectangle
            Public fillColor As Color
            Public OutLine As Color
            Public Sub draw(g As Graphics)
                Using br As New SolidBrush(Color.FromArgb(200, fillColor))
                    Using pn As New Pen(OutLine, 3)
                        g.FillRectangle(br, rect)
                        g.DrawRectangle(pn, rect)
                    End Using
                End Using
            End Sub
        End Class
    
        Private hitList As New List(Of RectangleObject)
        Private drawList As New List(Of RectangleObject)
        Private heightboxlist As New List(Of Integer)
        Private activeRect As RectangleObject
        Private overRect As RectangleObject
        Dim heightextra As Integer
        Dim Aantalgetekendedoze As Integer
        Dim aantalgetekendedoze_list As New List(Of Integer)
    
    
    
        Private Sub Form3_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            layernr = 0
            Aantalgetekendedoze = 0
            DoubleBuffered = True
            Text = "Press LeftShift and mouse to add boxes"
            '''' max_aantaldozen_op_pallet = MainPalletizer
        End Sub
    
        Private Sub Form3_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
    
            If My.Computer.Keyboard.ShiftKeyDown Then
                activeRect = New RectangleObject
                activeRect.fillColor = Color.FromArgb(255, 255, 255)
                activeRect.OutLine = Color.FromArgb(255, 0, 0)
                activeRect.rect = New Rectangle(e.Location, New Size(lengthboxvalue_s, widthboxvalue_s))
    
                heightboxlist.Add(startheight)
                Aantalgetekendedoze = Aantalgetekendedoze + 1
    
    
                drawList.Add(activeRect)
                hitList.Clear()
                hitList.AddRange(drawList.ToArray.Reverse) 'will reverse the order, so we can draw in Z-order (first in rectList is drawn last, so is on top)
                Invalidate()
            Else
                activeRect = FindRectangleAt(e.Location)
            End If
    
        End Sub
    
        Private Function FindRectangleAt(pnt As Point) As RectangleObject
            For Each r In hitList
                If r.rect.Contains(pnt) Then
                    Return r
                End If
            Next
            Return Nothing
        End Function
    
        Private Sub Form3_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
            Static lpos As Point
            Static lrect As RectangleObject
    
            If activeRect IsNot Nothing Then
                With activeRect
                    If e.Button = MouseButtons.Left Then
                        .rect.Location += New Size(e.X - lpos.X, e.Y - lpos.Y)
                    ElseIf e.Button = MouseButtons.Right Then
                        .rect.Size = New Size(widthboxvalue_s, lengthboxvalue_s)
    
                    End If
    
                End With
                Invalidate()
    
            Else  'Not dragging, highlight the rectangle the cursor is over
                overRect = FindRectangleAt(e.Location)
                If overRect IsNot lrect Then Invalidate()
                lrect = overRect
            End If
            lpos = e.Location
        End Sub
    
        Private Sub Form3_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseUp
            If My.Computer.Keyboard.CtrlKeyDown Then
                If activeRect IsNot Nothing Then
                    hitList.Remove(activeRect)
                    drawList.Remove(activeRect)
                    heightboxlist.Remove(heightextra)
                    Aantalgetekendedoze = Aantalgetekendedoze - 1
                End If
            End If
    
            activeRect = Nothing
        End Sub
    
        Private Sub Form3_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
            e.Graphics.DrawRectangle(Pens.Blue, 20, 20, lengthpalletvalue_s, widthpalletvalue_s)
    
            For Each r As RectangleObject In drawList
                r.draw(e.Graphics)
            Next
    
            'Highlight the rectangle that the cursor is over (will pick if clicked)
            If overRect IsNot Nothing Then
                Using br As New SolidBrush(Color.FromArgb(128, Color.White))
                    e.Graphics.FillRectangle(br, overRect.rect)
                End Using
            End If
            If nextlayer Then
    
                'e.Graphics.DrawRectangle(Pens.Red, 20, 20, lengthpalletvalue_s, widthpalletvalue_s)
                ' e.Graphics.FillRectangle(Brushes.Red, 20, 20, lengthpalletvalue_s, widthpalletvalue_s)
                Refresh()
                nextlayer = False
            End If
        End Sub
    
        Private Sub Button_Next_Layer_Click(sender As Object, e As EventArgs) Handles Button_Next_Layer.Click
            startheight = startheight + heightboxvalue_s
            nextlayer = True
            aantalgetekendedoze_list.Add(Aantalgetekendedoze)
            Aantalgetekendedoze = 0
            If layernr > MainPalletizer.numberofboxesheightround Then
                MessageBox.Show("max number of layers reached")
            Else
                layernr = layernr + 1
            End If
        End Sub
    End Class

  15. #15
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,583

    Re: add rectangle to drawing

    Sorry, I don't have time to look at your code right now.
    I did figure you might want an example of what I was talking about, so I was working on that while I ate breakfast before heading to work.
    I just modified the previous example I gave, using the List(Of List(Of RectangleObject)) object.
    I also changed the code to draw in a picturebox instead of on the form, so that the drawing area could easily be segregated from other areas that would hold other controls.

    (p.p.s I also removed the hit list, just traversing the drawlist in reverse when doing hit testing)

    I envisioned a panel along one side of the form which would house permanent controls at the top, and a scrollable area underneath which would hold dynamic controls added for each layer, to control layer specific things. Since time was short I didn't actually try to implement any dynamic adding of controls for each layer, or creating the scrollable area, although a panel was added as a place holder for that area.

    A small panel at the top of that left side control area does hold three controls, a button to add another layer, a numeric UpDown control to select a layer (the "active" layer), and a checkbox to allow switching between showing all the layers, or only the active layer.

    The numeric UpDown control is the only "dynamic" thing related to the layers.
    Its Minimum,Maximum properties are set to 0, and the 0 layer is created automatically when the program starts (0 is the active layer).
    When you click the button a new list (layer) is added to the list of lists (list of layers), and the maximum property is set to the last valid layer index (as well as the numericUpDown value).
    The numeric Updown is thus dynamically updated to allow only selecting valid layers from the List of layers.

    For minimal change, controls are only added to the active layer (pretty much a requirement anyway), but also you can only select, move and resize rectangles in the active area. I left the code in that highlights the rectangle the mouse is over on the active layer, so if you are showing all layers, only the ones in the active layer will highlight and be selectable, which means you can select a rectangle and move or resize it, even if it is completely obscured underneath higher level rectangles.

    I'll post the code, but since the example is more involved with the various panels and pictureboxes docked to the form, and controls located in a specific panel, I'll attach the project too. It is a VS2010 project, so should load fine in any VS after 2010, either with automatic conversion, or directly.
    Code:
    Public Class Form1
    
      Private rand As New Random
    
      Private Class RectangleObject
        Public rect As Rectangle
        Public fillColor As Color
        Public OutLine As Color
        Public Sub draw(g As Graphics)
          Using br As New SolidBrush(Color.FromArgb(240, fillColor))
            Using pn As New Pen(OutLine, 3)
              g.FillRectangle(br, rect)
              g.DrawRectangle(pn, rect)
            End Using
          End Using
        End Sub
      End Class
    
      Private drawList As New List(Of List(Of RectangleObject))
      Private activeRect As RectangleObject
      Private overRect As RectangleObject
      Private activeLayer As Integer
    
      Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        drawList.Add(New List(Of RectangleObject))   'add the first layer (layer 0) 
        Text = "Hold Shift key, and drag mouse to create rectangles"
      End Sub
    
      Private Sub picDrawArea_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles picDrawArea.MouseDown
        If My.Computer.Keyboard.ShiftKeyDown Then
          activeRect = New RectangleObject
          activeRect.fillColor = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255))
          activeRect.OutLine = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255))
          activeRect.rect = New Rectangle(e.Location, New Size(15, 15))
          drawList(activeLayer).Add(activeRect)
          picDrawArea.Invalidate()
        Else
          activeRect = FindRectangleAt(e.Location)
        End If
      End Sub
    
      Private Function FindRectangleAt(pnt As Point) As RectangleObject
        Dim L As List(Of RectangleObject) = drawList(activeLayer)
        For i As Integer = L.Count - 1 To 0 Step -1
          If L(i).rect.Contains(pnt) Then
            Return L(i)
          End If
        Next
        Return Nothing
      End Function
    
      Private Sub picDrawArea_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles picDrawArea.MouseMove
        Static lpos As Point
        Static lrect As RectangleObject
    
        If activeRect IsNot Nothing Then
          With activeRect
            If e.Button = Windows.Forms.MouseButtons.Left Then
              .rect.Location += New Size(e.X - lpos.X, e.Y - lpos.Y)
            ElseIf e.Button = Windows.Forms.MouseButtons.Right Then
              .rect.Width += e.X - lpos.X
              .rect.Height += e.Y - lpos.Y
              If .rect.Width < 5 Then .rect.Width = 5 'don't allow to go too small
              If .rect.Height < 5 Then .rect.Height = 5
            End If
          End With
          picDrawArea.Invalidate()
    
        Else  'Not dragging, highlight the rectangle the cursor is over
          overRect = FindRectangleAt(e.Location)
          If overRect IsNot lrect Then picDrawArea.Invalidate()
          lrect = overRect
        End If
        lpos = e.Location
      End Sub
    
      Private Sub picDrawArea_MouseUp(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles picDrawArea.MouseUp
        If My.Computer.Keyboard.CtrlKeyDown Then
          If activeRect IsNot Nothing Then
            drawList(activeLayer).Remove(activeRect)
          End If
        End If
        activeRect = Nothing
      End Sub
    
      Private Sub picDrawArea_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles picDrawArea.Paint
        If cbxDrawAllLayers.Checked Then
          For Each lList As List(Of RectangleObject) In drawList  'for each layer
            For Each r As RectangleObject In lList                '   for each rectangle in the layer
              r.draw(e.Graphics)
            Next
          Next
    
        Else  'just draw the rectangles in the selected layer
          For Each r As RectangleObject In drawList(activeLayer)
            r.draw(e.Graphics)
          Next
        End If
    
        'Highlight the rectangle in the active layer that the cursor is over (will pick if clicked)
        If overRect IsNot Nothing Then
          Using br As New SolidBrush(Color.FromArgb(128, Color.White))
            e.Graphics.FillRectangle(br, overRect.rect)
          End Using
        End If
      End Sub
    
      Private Sub btnAddLayer_Click(sender As System.Object, e As System.EventArgs) Handles btnAddLayer.Click
        drawList.Add(New List(Of RectangleObject))   'add another layer
        activeLayer = drawList.Count - 1
        nudLayer.Maximum = activeLayer
        nudLayer.Value = activeLayer
        picDrawArea.Invalidate()
      End Sub
    
      Private Sub nudLayer_ValueChanged(sender As System.Object, e As System.EventArgs) Handles nudLayer.ValueChanged
        activeLayer = CInt(nudLayer.Value)
        picDrawArea.Invalidate()
      End Sub
    
      Private Sub cbxDrawAllLayers_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles cbxDrawAllLayers.CheckedChanged
        picDrawArea.Invalidate()
      End Sub
    End Class
    p.s. Just a quick glance at your code, and I don't think I would be using Int64's for the values. Int32's should be sufficient (unless you're planing on having more than 2 billion rectangles).
    Int64s are probably a little slower than Int32s in calculations in some cases, besides taking twice the space.
    For purely calculation driven code, running on a 64-bit operating system, then a 64-bit executable is usually faster, but use of Int64 vs Int32 is not likely the reason.
    Also, with GDI+ graphics, I've found that a 32-bit executable actually draws a little faster on the machines I've tested.
    Attached Files Attached Files
    Last edited by passel; Nov 8th, 2016 at 10:03 AM.

  16. #16
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,583

    Re: add rectangle to drawing

    I did look through your code in post #14.
    Since you are using fixed size rectangles, I would probably just remove the right mouse button test rather than reset the rectangle to the size it already is in the mousemove event.

    I assume you didn't get too far along in your attempt at adding another layer because in the Paint Event you call Refresh(), which should cause another Paint Event which would call Refresh() which would cause another paint event, etc...
    I would think if you enabled the second layer it would have locked up in an endless loop in the Paint event and the application would have crashed from a stack overflow.

    I already mentioned I wouldn't use Int64's for anything. I think if you added "Option Strict On" to the first line of the file (you should turn it on in the project options so that it is always enabled), you would find that a lot of your assignments would have to be coerced to the correct type because of your use of Int64s.
    You should try to use the type that is expected for the properties and parameters of the classes you use to minimize the conversions between types necessary.

  17. #17

    Thread Starter
    Junior Member
    Join Date
    Oct 2016
    Posts
    22

    Re: add rectangle to drawing

    thank you for your help passel i changed the int64 to int32s. now i need that every rectangle has its own number shown on the rectangle itself, and the rectangles may not overlap each other, also need the rectangles coordinates be outputted to an datagridview. you helped me already alot!! thank you for that!!

  18. #18
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,583

    Re: add rectangle to drawing

    You should just add a member to the rectangleObject to hold the number. For an example I just added a string instead of a number, but basically the principle is the same.
    Then add code in the draw sub to draw that number/string how you want it presented.
    In my modification to the last example code I just print it 10,10 down and right of the upper left corner of the rectangle.

    I added the font to use as a shared member, so you only have one font for all the rectangles.
    You need to initialize that font before use, so I did that in the form load.

    Since the example allows you to resize the rectangles, I also set the clip region so the text won't draw outside the bounds of the rectangle. You wouldn't need the clip region since you have a fixed size rectangle.
    I changed the fillColor in the example so that it won't go near black (minimum rgb value would be 40,40,40) to make the black text standout better if a dark color happened to be chosen.

    This isn't all the code, just the Class and Subs that were modified.
    The code isn't complete in that the ID string set would contain the level and index of the rectangle at the time it was created.
    If you delete a rectangle the index changes, but this would not be reflected in the IDs already set, and if you add another rectangle to a list with deleted rectangles, then you will probably end up with rectangles with the same text. I assume your program would assign numbers based on some other standard, not the way this simple example does it.

    The modified example class and method code looks like this.
    Code:
      Private Class RectangleObject
        Public rect As Rectangle
        Public fillColor As Color
        Public OutLine As Color
        Public ID As String            'a string to be printed in the rectangle
        Public Shared idFont As Font   'the font to use for the print
    
        Public Sub draw(g As Graphics)
          Using br As New SolidBrush(Color.FromArgb(240, fillColor))
            Using pn As New Pen(OutLine, 3)
              g.FillRectangle(br, rect)
              g.DrawRectangle(pn, rect)
              g.SetClip(rect)
              g.DrawString(ID, idFont, Brushes.Black, rect.Location + New Size(10, 10))
              g.ResetClip()
            End Using
          End Using
        End Sub
      End Class
    
      Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        drawList.Add(New List(Of RectangleObject))   'add the first layer (layer 0) 
        Text = "Hold Shift key, and drag mouse to create rectangles"
        RectangleObject.idFont = New Font("Arial", 12)  'Init a font for the text written in the rectangle
      End Sub
    
     'added setting the ID string to a value that indicates the level and index of the rectangle
      Private Sub picDrawArea_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles picDrawArea.MouseDown
        If My.Computer.Keyboard.ShiftKeyDown Then
          activeRect = New RectangleObject
          activeRect.ID = String.Format("Rect: {0}:{1}", activeLayer, drawList(activeLayer).Count)
          activeRect.fillColor = Color.FromArgb(rand.Next(40, 255), rand.Next(40, 255), rand.Next(40, 255))
          activeRect.OutLine = Color.FromArgb(rand.Next(255), rand.Next(255), rand.Next(255))
          activeRect.rect = New Rectangle(e.Location, New Size(15, 15))
          drawList(activeLayer).Add(activeRect)
          picDrawArea.Invalidate()
        Else
          activeRect = FindRectangleAt(e.Location)
        End If
      End Sub

  19. #19

    Thread Starter
    Junior Member
    Join Date
    Oct 2016
    Posts
    22

    Re: add rectangle to drawing

    its works really nice but there is a small bug in it when you drawn 10 rectangles as example and then delete rectangle 4 and draw a new rectangle the new rectangle has also the number 10. how would that be solvable?

  20. #20
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,583

    Re: add rectangle to drawing

    Yes, I mentioned that would happen.
    The code isn't complete in that the ID string set would contain the level and index of the rectangle at the time it was created.
    If you delete a rectangle the index changes, but this would not be reflected in the IDs already set, and if you add another rectangle to a list with deleted rectangles, then you will probably end up with rectangles with the same text. I assume your program would assign numbers based on some other standard, not the way this simple example does it.
    The question is how should the boxes be numbered.
    I assumed you might have a textbox where the number had to be entered and then you would assign that number to the rectangle.

    If you don't have a scheme, then there are a number of ways to come up with a scheme that will avoid duplicates.
    For instance, keep a counter that just increments whenever you add a rectangle. If you delete a rectangle, then that number is gone and never to be seen again.

    Another scheme is to keep track of deleted rectangle numbers and when you add a rectangle, if there are any numbers available, reuse one of the deleted rectangle numbers, otherwise use a new number.

    You can have one number that increments and is assigned to a box regardless of what level it is on.
    You could have one number series for each level, similar to what is done now, but each level maintaining the rectangle numbers as described above.

    So, how do you want the number of pallets to work? What makes sense to the design of your program?
    Last edited by passel; Nov 16th, 2016 at 04:10 PM.

  21. #21

    Thread Starter
    Junior Member
    Join Date
    Oct 2016
    Posts
    22

    Re: add rectangle to drawing

    i was looking when you delete a box the numbers shifts. so if i have numbers for 0 to 10 and i delete the 4th the numbers will only go from 0 to 9 i hope you understand what i mean?
    also when i go to the next layer the number need to be still counting up so if you have 5 boxes on the first layer and you will add a box on the second layer the box number will be 6

    sorry for my bad english.

    thank you for your help!!

  22. #22
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    4,583

    Re: add rectangle to drawing

    Well, it seems a little awkward for the boxes to be renumbered when one is deleted, especially if you have an inventory system that is trying to track the boxes by their number, but if that is what you want the simplest thing to do is whenever one is deleted, just loop through them all and renumber them.
    Technically you would only have to renumber the ones after the one removed, but determining where to start and how to loop through the remaining using the lists as we have them is enough effort that doing the brute force loop through all and renumber is easier and probably fast enough for the limited number of pallets you're likely to have.

    Do you think you want to take a stab at updating the code yourself?
    Whenever you delete a box, after you delete it loop through the layers and list and renumber the boxes.
    You can look at the nested loop from the paint event as an example since it loops through all the rectangles to draw them.
    Code:
          For Each lList As List(Of RectangleObject) In drawList  'for each layer
            For Each r As RectangleObject In lList                '   for each rectangle in the layer
              r.draw(e.Graphics)  'instead of drawing, renumber the rectangle here.
            Next
          Next
    The fact is, if you want to renumber the boxes so that if you add a box to the lower layers all boxes above that layer also have to be renumbered, then you will really want to call the renumber routine whenever you delete a box or add a box.
    So, just put the renumber code in its own sub and call it from both places, or any other place you might need it in the future, i.e. if you move a box from one layer to another, then the sequence number of the boxes would change as well, with your scheme.

    p.s. Attached latest version of project including changes discussed since the last version attached.
    Attached Files Attached Files
    Last edited by passel; Mar 6th, 2018 at 04:58 AM.

  23. #23

    Thread Starter
    Junior Member
    Join Date
    Oct 2016
    Posts
    22

    Re: add rectangle to drawing

    hello, i'm back on it and i have another problem. i have a bunch of values stored in a datagrid and would like do make an adjustable drawing of it. the values in the datagrid ar the coordinates of the boxes and the number of the boxes that where placed on the pallet. when i click edit on the button above the datagrid an new form need to appear with the drawing on it. the drawing needs to be adjustable and when it is completed it can be saved back in the datagrid.

    here you can see the datagrid where the values are stored in. so when i press edit design manually i need to be able to get an drawing of the calculated coordinates and be able to adjust the drawing by clicking and dragging the boxes.
    Name:  datagrid.jpg
Views: 58
Size:  34.4 KB

    so i need something like this that can be edited from the datagrid.
    Name:  test.JPG
Views: 54
Size:  28.1 KB

    hopefully you guys understand me and are able to help me. sorry for the bad english.

  24. #24

    Thread Starter
    Junior Member
    Join Date
    Oct 2016
    Posts
    22

    Re: add rectangle to drawing

    i have tried to import the datagrid in to a list of an list to get the needed coordinates. but not all value's are in the list?
    next i need to make drawing of it that is adjustable by dragging the boxes.
    Code:
       Public Class EditDatagridManually
            Public Property boxnumber As Integer
            Public Property z_position As Integer
            Public Property x_position As Integer
            Public Property y_position As Integer
            Public Property rotation As Integer
    
        End Class
    
        Private Sub Edit_design_manually_Click(sender As Object, e As EventArgs) Handles Edit_design_manually.Click
            For l As Integer = 0 To DataGridView1.RowCount - 1
                Dim manuallyedit_vallues As New EditDatagridManually
                manuallyedit_vallues.boxnumber = DataGridView1.Rows(l).Cells(0).Value
                manuallyedit_vallues.x_position = DataGridView1.Rows(l).Cells(1).Value
                manuallyedit_vallues.y_position = DataGridView1.Rows(l).Cells(2).Value
                manuallyedit_vallues.z_position = DataGridView1.Rows(l).Cells(3).Value
                manuallyedit_vallues.rotation = DataGridView1.Rows(l).Cells(4).Value
    
                manuallyedit_value.Add(manuallyedit_vallues)
            Next
    Last edited by baptistverm; Mar 7th, 2017 at 02:39 PM.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Featured


Click Here to Expand Forum to Full Width