Click here to Skip to main content
15,887,267 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I am trying to write an app which will allow a user to create rectangles within a picturebox and be able to rearrange the size and position of the rectangles using the mouse. The code creates a rectangle which can be moved with the mouse, but I can't see how to create a second one that the app will be able to differentiate between. Also, when the second rectangle is created, I can't see what would be required to allow the code to move each of the rectangles separately. Whilst I want to add multiple rectangles eventually, I think if I can solve the problem with just two, I can move on from there. Any assistance would be appreciated.

What I have tried:

VB
Public Class Form1

    Private rect As Rectangle = New Rectangle(125, 125, 50, 50)
    Private isMouseDown As Boolean = False

    Public Sub New()
        InitializeComponent()
    End Sub

    Private Sub pictureBox1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles PictureBox1.Paint
        e.Graphics.FillRectangle(New SolidBrush(Color.RoyalBlue), rect)
    End Sub

    Private Sub pictureBox1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseDown
        isMouseDown = True
    End Sub

    Private Sub pictureBox1_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseMove
        If isMouseDown = True Then
            rect.Location = e.Location

            If rect.Right > PictureBox1.Width Then
                rect.X = PictureBox1.Width - rect.Width
            End If

            If rect.Top < 0 Then
                rect.Y = 0
            End If

            If rect.Left < 0 Then
                rect.X = 0
            End If

            If rect.Bottom > PictureBox1.Height Then
                rect.Y = PictureBox1.Height - rect.Height
            End If

            Refresh()
        End If
    End Sub

    Private Sub pictureBox1_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseUp
        isMouseDown = False
    End Sub

End Class
Posted
Updated 28-Aug-23 12:30pm
v2

Simple: don't use a single Rectangle.
Instead of this:
Private rect As Rectangle = New Rectangle(125, 125, 50, 50)
Create a collection of Rectangle objects:
Dim rectangles As List(Of Rectangle) = New List(Of Rectangle)()
Then when the user wants a new rectangle, create it and add it to the collection.
He can then select a rectangle to modify my clicking within your PictureBox and you can use Rectangle.Contains Method (System.Drawing) | Microsoft Learn[^] to see if the mouse is within a rectangle, and if so set that as the one he is changing.

It's really not as complicated as you might think - give it a try, and you'll see what I mean.
 
Share this answer
 
Comments
Member 15070471 25-Aug-23 20:05pm    
Thank you for your ideas, I fully understand the logic now and I have implemented the List which is working. I've also got the Rectangle.Contains method working, but now I've lost the persistent rectangle ability. It was quite a chnage from my original idea and not so simple for me, but I'm still working on it and I'll see how I go and revert. Thanks again.
OriginalGriff 26-Aug-23 0:46am    
You're welcome - but quite what you mean by "lost the persistent rectangle ability" I am not sure.
Were you drawing your rectangles on the Image behind the PictureBox? Because if you were that would make the rectangles really difficult to move later!
Instead, draw the rectangles from the List onto the PictureBox itself as part of it's Paint event. That way they are easy to move and visually persistent.
Member 15070471 26-Aug-23 20:19pm    
Hi, I posted an update on my code in the solution area below. I hope thats correct as I couldn't see how else to do it. Thanks
I really hate promoting my own work, but you might get some ideas from my article Create your Own Runtime Movable Windows Forms Controls[^].
 
Share this answer
 
Comments
Member 15070471 25-Aug-23 20:07pm    
Thank you for your suggestions and I'm sure they would be suitable, but they are a bit more advanced than I was looking for so I'll try the above method first and see if I come right. Thanks again.
Dave Kreskowiak 27-Aug-23 1:33am    
Well, you're going to find out the code you're writing is going to turn into "more advanced". You're putting a lot of code in the form that should be in its own control. This will save you from writing code specially to track every rectangle, doing hit tests on all of them to figure out which rectangle you're moving, managing z-order for them because rectangles can overlap and you probably don't want to move multiple rectangles at the same time, ...

Putting the code into a control simplifies this greatly.
The issue you have is in pictureBox1_Paint, you are only rendering one rectangle, not each rectangle in the list.
You need to change this:
VB
Private Sub pictureBox1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) _
    Handles PictureBox1.Paint
    e.Graphics.FillRectangle(New SolidBrush(Color.Gray), rectangle)
End Sub

to:
VB
Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) _
    Handles PictureBox1.Paint
    For Each rect As Rectangle In rectangles
        e.Graphics.FillRectangle(New SolidBrush(Color.Gray), rect)
    Next
End Sub
 
Share this answer
 
Comments
Member 15070471 27-Aug-23 3:32am    
Thank you for this. It helped. Can you please explain how the Accept Solution works? I got a lot of help from OriginalGriff above and now from you. But the first post wasnt complete so I didnt wany to finalise it then. Whats the accepted procedure? You guys are so helpful I'd like to get it right.
Graeme_Grant 27-Aug-23 4:09am    
Glad that we could help. You can click on accept answer for more than one solution.
Thank you for for your interest in my project. I've got as far as I can with the code. I've implemented the list and can track whether the rectangle has been clicked or not, using Contains. I've included a message box and some labels to temporarily keep track of what's happening. A rectangle is created on the form loading but I rather want it created on a button. However, Button1 creates a second rectangle on top of the first and disappears when clicked and I can't see how to update the picturebox_paint with different values to create additional rectangles. So far, I can also move the single rectangle around the picturebox. Any further advice would be appreciated.


Public Class Form1

    Private rectangle As Rectangle = New Rectangle(70, 70, 100, 150)
    Dim rectangles As List(Of Rectangle) = New List(Of Rectangle)()
    Private isMouseDown As Boolean = False

    Public Sub New()
        InitializeComponent()
    End Sub

    Private Sub pictureBox1_Paint(ByVal sender As Object, ByVal e As PaintEventArgs) Handles PictureBox1.Paint
        e.Graphics.FillRectangle(New SolidBrush(Color.Gray), rectangle)
    End Sub

    Private Sub pictureBox1_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseDown
        isMouseDown = True
    End Sub

    Private Sub pictureBox1_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseMove

        If isMouseDown = True Then

            Label1.Text = e.Location.ToString
            If Contains(e.Location) = True Then
                Label2.Text = True.ToString
            Else
                Label2.Text = False.ToString
            End If

            rectangle.Location = e.Location

            If rectangle.Right > PictureBox1.Width Then
                rectangle.X = PictureBox1.Width - rectangle.Width
            End If

            If rectangle.Top < 0 Then
                rectangle.Y = 0
            End If

            If rectangle.Left < 0 Then
                rectangle.X = 0
            End If

            If rectangle.Bottom > PictureBox1.Height Then
                rectangle.Y = PictureBox1.Height - rectangle.Height
            End If

            Refresh()
        End If

    End Sub

    Private Sub pictureBox1_MouseUp(ByVal sender As Object, ByVal e As MouseEventArgs) Handles PictureBox1.MouseUp
        isMouseDown = False
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        PictureBox1.CreateGraphics.FillRectangle(New SolidBrush(Color.Brown), rectangle)

        rectangles.Add(rectangle)

        MsgBox(rectangles.Count.ToString)
        Dim sResult As String = ""
        For i = 0 To rectangles.Count - 1
            sResult = rectangles.Item(i).ToString
            MsgBox("Rectangle " & i.ToString & "  " & sResult)
        Next

    End Sub

    Public Overloads Function Contains(ByVal pt As System.Drawing.Point) As Boolean

        If rectangle.Contains(pt) Then
            Return True
        Else
            Return False
        End If
        Return False

    End Function

End Class
 
Share this answer
 
Comments
Graeme_Grant 26-Aug-23 20:39pm    
You should update your question by using the "Improve question" link as this is not a working solution.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900