Click here to Skip to main content
15,879,613 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
In my app I paint rectangles on a picturebox in diferent locations. I can drag them around with the mouse and even rotate them with the mouse wheel.

At first I used pictureboxes, but rotating them became a hassle, so I created my own class instead. My class holds the drawing point points of the object and in the paint event I create paths from these points and paint them.

To get mouse event I created regions in the paint event and stored them in a pointer array so I can use
PtInRegion()
to check if a mouse is over an object.

Great it all works. Object are painted, moved and rotated. I only needed to do the math for scaling the whole lot but then i got an out of memmory error.

What I have tried:

Using Process Explorer I traced the problem to this line:
ptrRegion(sx) = rgn.GetHrgn(g)
This is where I store a handle to the region in a pointer array.
In Proccess Explorer my GDI handle count skyrockets every time I move the objects.
Comenting the line out solves the GDI Handle problem but then I cannot drag the objects anymore.
Here is my paint event:
Try
	Dim g As Graphics = e.Graphics
   
	For Each Drop As MyPictureBox In DropList
		With Drop
			Dim sx As Integer
			sx = .ArrayIndex   'array index of drop 

			Dim mypath, fillPath As New System.Drawing.Drawing2D.GraphicsPath
			Dim curvepoints As Point() = {.BorderPoint1, .BorderPoint2, .BorderPoint3, .BorderPoint4}
			Dim fillPoint As Point() = {.FillPoint1, .FillPoint2, .FillPoint3, .FillPoint4}
			Dim rPoint = .DrawCentre

			mypath.AddPolygon(curvepoints)
			fillPath.AddPolygon(fillPoint)

			Dim mymatrix As New System.Drawing.Drawing2D.Matrix
			mymatrix.RotateAt(.ShelfRotation, rPoint)
			mypath.Transform(mymatrix)
			fillPath.Transform(mymatrix)

			Dim rgn As System.Drawing.Region
			rgn = New Region(mypath)
		  
			'If ptrRegion(sx) = 0 Then
			ptrRegion(sx) = rgn.GetHrgn(g) 'if I comment this line out promblem disappears but I cannot move the objects anymore.
			'End If
			
			g.FillPath(.BorderSolidBrush, mypath)
			g.FillPath(.FillSolidBrush, fillPath)

			rgn.Dispose()
			mypath.Dispose()
			fillPath.Dispose()
			mymatrix.Dispose()
		End With
	Next
   
Catch ex As Exception
	MsgBox("Error:" & ex.ToString)
End Try


And on mouse move:
Private Sub picFloor_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles picFloor.MouseMove
	lblCoordinates.Text = "Mouse is at X: " & e.X & " Y: " & e.Y

	Dim id As Integer
	id = 9999 'mouse pointing at background
	For Each Drop As MyPictureBox In DropList
		Dim x As Integer
		x = Drop.ArrayIndex
		If (PtInRegion(ptrRegion(x), e.X, e.Y)) Then
			id = x 'mouse is pointing to an object
			picFloor.ContextMenuStrip = rightClickMenu
			Exit For
		End If
	Next
	mouseOverID = id
	lblmouseid.Text = mouseOverID

	If drag = True Then
		picFloor.ContextMenuStrip = Nothing
		'Scroll the map on mouse right button
		If e.Button = Windows.Forms.MouseButtons.Right Then
			Dim DeltaX As Integer = (startPos.X - e.X)
			Dim DeltaY As Integer = (startPos.Y - e.Y)
			'Set the new autoscroll position.
			DropPannel.AutoScrollPosition = New Drawing.Point((DeltaX - DropPannel.AutoScrollPosition.X), (DeltaY - DropPannel.AutoScrollPosition.Y))
			panelScrollPoss = New Drawing.Point((DeltaX - DropPannel.AutoScrollPosition.X), (DeltaY - DropPannel.AutoScrollPosition.Y))
		End If

		'Drag the shelf on left button
		If (dragID <> 9999) Then
			If e.Button = Windows.Forms.MouseButtons.Left Then
				Dim Drop As MyPictureBox = DropList.Find(Function(c) c.ArrayIndex = dragID)
				If Drop.PositionLocked = False Then
					Dim diference = New Point(e.X - startPos.X, e.Y - startPos.Y) 'distance that the mouse moved.					
					Drop.DrawCentre = New Point(startPos.X + diference.X - mouseOfset.X, startPos.Y + diference.Y - mouseOfset.Y)
					Drop.SetCentrePoint()
					Me.Refresh()
				End If
			End If
		End If
	Else
		picFloor.Focus()
		DropPannel.AutoScrollPosition = panelScrollPoss 'Return scrollbars to its last position
	End If
End Sub


I tried to use region.translate instead of creating a new region every time, but couldn't figure it out. Can anyone please tell me how do I release the DGI handles? In my code at the end of the paint event, I dispose of everything I used but the GDI handle count still maxes when I move the map or othe objects on it.
Posted
Updated 3-Jun-17 10:26am
v2
Comments
[no name] 31-May-17 10:19am    
You need to call the Windows API DeleteObject() to delete the GDI object. I am not a VB.NET programmer so I don't know if you have this built into your framework. Try to pInvoke it and see what happens.
Regg Fulton 1-Jun-17 14:39pm    
Thanks. Never worked with widows APIs before. Let me Google it and check. Thought Region.Dispose is supposed to do the cleanup.

1 solution

Never mind. I solved the problem. The solution was ridiculously easy. I did away with
ptrRegion(sx) = rgn.GetHrgn(g)
instead keepig the region and a pointer to the region as properties in my class called BorderRegion and BorderRegionPtr. Then replace this
Dim rgn As System.Drawing.Region
			rgn = New Region(mypath)
		  
			'If ptrRegion(sx) = 0 Then
			ptrRegion(sx) = rgn.GetHrgn(g)
with this code
Dim rgn As System.Drawing.Region
                       rgn = New Region(mypath)

                       If (Drop.BorderRegionPtr = 0) Then
                           'Region not created yet.
                       Else
                           Drop.BorderRegion.ReleaseHrgn(Drop.BorderRegionPtr)
                       End If


                       Drop.BorderRegion = rgn
                       Drop.BorderRegionPtr = rgn.GetHrgn(g)
using the region and the region pointer I can now use Region.releaseHrgn to release the GDI handle.
 
Share this answer
 

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