prodonjs

This is a strange one for me. What I have is a List(Of Rectangle) that are each 200 by 200. I want to be able to go through the list iteratively, change each ones location to being 10 pixels to the right and 10 pixels down and then shrink their size by 20 on each dimension.

Initially, I planned on something like this:

Private SubprepareMenuSquares(ByRef squares As List(Of Rectangle))

For Each thing As Rectangle In squares

thing.X += 10

thing.Y += 10

thing.Width -= 20

thing.Height -= 20

Next

End Sub

I assumed I would be passing the List by reference and then would have access directly to the Rectangle objects themselves and could do an inplace modifcation, no problem. Well that didn't work and I thought well maybe it was because the For Each statement was creating a temporary variable to hold each Rectangle distinct from the actual Rectangle. So I tried using the same structure in a For loop and saying squares(i).X etc..., but I ran into the "Expression cannot be the target of an assignment error" and after looking that up, I tried changing it so I was making a brand New Rectangle object, and then was copying back to the squares(i) position and I still couldn't get the changes to reflect in the main part of my program.

In fact, I can make the changes and see them within the scope of the For loop, but outside of the loop the changes are already gone. What am I missing Is it the case that even though I am passing the List by reference, I am not able to gain direct access to each member of the list directly That seems very odd to me. Perhaps I will try not using a list and just a standard array, but I would really like to keep this the way it is because the List(Of Rectangle) gets returned from another class and I would rather not go into redesigning that file too. Please let me know what I can do.



Re: Visual Basic Language Trying to Do an inplace Update of Rectangle Objects stored in generic List

PEng1

I believe this does something like what you are trying to do:

Public Class Form1

Dim Rectangles As New List(Of Rectangle)

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Rectangles.Add(New Rectangle(10, 15, 20, 20))

Rectangles.Add(New Rectangle(20, 25, 20, 20))

End Sub

Private Sub btnChangeSquares_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnChangeSquares.Click

PrepareMenuSquares()

DrawSquares()

End Sub

Private Sub PrepareMenuSquares()

Dim Squares As New List(Of Rectangle)

Do While Rectangles.Count <> 0

Squares.Add(Rectangles(Rectangles.Count - 1))

Rectangles.RemoveAt(Rectangles.Count - 1)

Loop

For Each Square As Rectangle In Squares

Square.Offset(10, 10)

Square.Inflate(-2, -2)

Rectangles.Add(Square)

Next

End Sub

Private Sub DrawSquares()

Dim myPen As New System.Drawing.Pen(System.Drawing.Color.Black)

Dim formGraphics As System.Drawing.Graphics

formGraphics = Me.CreateGraphics()

formGraphics.DrawRectangle(myPen, Rectangles(0))

formGraphics.DrawRectangle(myPen, Rectangles(1))

myPen.Dispose()

formGraphics.Dispose()

End Sub

Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint

DrawSquares()

End Sub

End Class

You need to have Rectangles set equal to the list return from the other class, This was just the first way I came up with and I am sure there is an easier way to do it that will make me feel really stupid, but I can't find it any where.  Hope this helps a little anyway.  I was really interested to know what was happening and I got the same results that you did.  It really is confusing why you can't just reference the rectangle objects in the list and change their properties.  I also found that if you set another list object (say squares) equal to rectangles and then remove the items from the rectangles list you also remove them from the squares list, I also found similar behavior when you use a collection instead of list and that has really got me stumped.

 






Re: Visual Basic Language Trying to Do an inplace Update of Rectangle Objects stored in generic List

Dave299

The reason you can't modify the rectangle objects is because they are not objects, they are structures.

This seems to work ok:

Private Sub prepareMenuSquares(ByRef squares As List(Of Rectangle))
Dim R As Rectangle
For count As Integer = 0 To squares.Count - 1
R = squares(count)
R.Inflate(-10, -10)
squares(count) = R
Next
End Sub





Re: Visual Basic Language Trying to Do an inplace Update of Rectangle Objects stored in generic List

PEng1

I said some one would make me feel stupid and I was right, good work, I still don't understand why you cant just modify the Rect structure, It just dosen't make any since, why would they allow you to set the properties if you cant really modify them




Re: Visual Basic Language Trying to Do an inplace Update of Rectangle Objects stored in generic List

Dave299

A rectangle is not an object, it is a structure of integer types.

If you were using reference types you could change the properties, but with value types the For Each loop works rather differently.

If you had say an array of buttons, then something like

For each B as Button in ButtonArray
B.BackColor = Color.Red
Next

would work because for each element the variable B references the object you want to change.

However for a value type if you try something similar

For each I as integer in IntegerArray
I += 20
Next

will indeed change the value of I but it won't change anything in the array because I is not referencing the element of the array, it as a different variable which has been set equal to the element.





Re: Visual Basic Language Trying to Do an inplace Update of Rectangle Objects stored in generic List

prodonjs

Ok this is extremely weird. I am at a total loss for what could be going on now because actually, I tried a simple solution that the one you suggested Dave and I assumed it wasn't working before looking more deeply into it. Now get a load of this here because this is boggling my mind.

'Call the method to reduce the size of each square (to not overwrite the numbers)

For Each t As Rectangle In menuSquares

Console.WriteLine("Before prepareMenuSquares2" & t.Size.ToString & "," & t.Location.ToString)

Next

prepareMenuSquares2(menuSquares)

For Each t As Rectangle In menuSquares

Console.WriteLine(vbTab & "After prepareMenuSquares2 " & t.Size.ToString & "," & t.Location.ToString)

Next

'Create two Meal objects (base class) taking the first two squares from the List

Console.WriteLine("menuSquare(0) = " & menuSquares(0).Size.ToString & "," & menuSquares(0).Location.ToString)

cokeMeal = New Meal(menuSquares(0), 10, Brushes.Chocolate)

orangeMeal = New Meal(menuSquares(1), 10, Brushes.OrangeRed)

When I run this, this is the output I get from the console:

Before prepareMenuSquares2{Width=200, Height=200},{X=20,Y=25}

Before prepareMenuSquares2{Width=200, Height=200},{X=260,Y=25}

Before prepareMenuSquares2{Width=200, Height=200},{X=500,Y=25}

Before prepareMenuSquares2{Width=200, Height=200},{X=740,Y=25}

Before prepareMenuSquares2{Width=200, Height=200},{X=20,Y=250}

Before prepareMenuSquares2{Width=200, Height=200},{X=260,Y=250}

Before prepareMenuSquares2{Width=200, Height=200},{X=500,Y=250}

Before prepareMenuSquares2{Width=200, Height=200},{X=740,Y=250}

After prepareMenuSquares2 {Width=180, Height=180},{X=40,Y=45}

After prepareMenuSquares2 {Width=180, Height=180},{X=280,Y=45}

After prepareMenuSquares2 {Width=180, Height=180},{X=520,Y=45}

After prepareMenuSquares2 {Width=180, Height=180},{X=760,Y=45}

After prepareMenuSquares2 {Width=180, Height=180},{X=40,Y=270}

After prepareMenuSquares2 {Width=180, Height=180},{X=280,Y=270}

After prepareMenuSquares2 {Width=180, Height=180},{X=520,Y=270}

After prepareMenuSquares2 {Width=180, Height=180},{X=760,Y=270}

menuSquare(0) = {Width=180, Height=180},{X=40,Y=45}

However they are still not drawing correctly only the screen. I added code into the actual Draw methods of the Meal objects and these are the sizes I get out.

m_mySquare = {Width=180, Height=180}{X=40,Y=45}

m_mySquare = {Width=180, Height=180}{X=280,Y=45}

And m_mySquare is the Rectangle object that used for each Meal object. So somehow, even though the sizes are correct I'm still drawing at 200x200. Its as if somehow, I changed all these sizes but the original Rectangle object that was 200 x 200 never changed and it is the one getting drawn to. What could be the issue here





Re: Visual Basic Language Trying to Do an inplace Update of Rectangle Objects stored in generic List

Dave299

No obvious problem in the code you have posted. Could you post the code you are using to draw the rectangles.



Re: Visual Basic Language Trying to Do an inplace Update of Rectangle Objects stored in generic List

prodonjs

Well, I realized that things were actually going correctly all along. What I couldn't realize was that yes the Rectangles were correctly changing sizes and location. However, I wasn't just changing the local copy I had in my Form class, I was also changing those squares that were in the Background class that I had instantiated.

I don't know how that was happening because the List(Of Rectangle) in my Background class was a Read-Only property, but I think since I wasn't creating a new List(Of Rectangle) in my Form class (I was just setting a variable = to the Property of the Background class), that I had actually created an alias for it. So I was doing exactly what I wanted to do, an in-place update of sizes except I was working with a scope that I didn't actually intend to work with. Oh well, it was a great exercise in the issues with data encapsulation and management.

And here I thought this project for my VB class was going to be a boring cakewalk since I hate using drawing stuff. Thanks for all your help everyone.