Regg Fulton Ответов: 1

Как освободить дескриптор для области GDI в массиве указателей?


В моем приложении Я рисую прямоугольники на picturebox в разных местах. Я могу перетаскивать их с помощью мыши и даже вращать колесиком мыши.

Сначала я использовал pictureboxes, но вращать их стало хлопотно, поэтому я создал свой собственный класс. Мой класс содержит точки рисования объекта, и в событии paint я создаю пути из этих точек и рисую их.

Чтобы получить событие мыши, я создал области в событии paint и сохранил их в массиве указателей, чтобы использовать
PtInRegion()
чтобы проверить, находится ли мышь над объектом.

Отлично все это работает. Объекты окрашиваются, перемещаются и вращаются. Мне нужно было только сделать математику для масштабирования всей партии, но потом я получил ошибку out of memmory.

Что я уже пробовал:

Используя Process Explorer я проследил проблему до этой строки:
ptrRegion(sx) = rgn.GetHrgn(g)
Здесь я храню дескриптор области в массиве указателей.
В Proccess Explorer Мой счетчик дескрипторов GDI взлетает до небес каждый раз, когда я перемещаю объекты.
Comenting The line out решает проблему дескриптора GDI, но тогда я больше не могу перетаскивать объекты.
Вот мое событие краски:
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


И на перемещения мыши:
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


Я попытался использовать region. translate вместо того, чтобы каждый раз создавать новый регион, но не смог этого понять. Может ли кто-нибудь сказать мне, как мне освободить ручки DGI? В моем коде в конце события paint я избавляюсь от всего, что использовал, но количество дескрипторов GDI все еще увеличивается, когда я перемещаю карту или другие объекты на ней.

Randor

Вам нужно вызвать Windows API DeleteObject (), чтобы удалить объект GDI. Я не такой VB.NET программист, поэтому я не знаю, встроено ли это в ваш фреймворк. Попробуйте вызвать его и посмотреть, что произойдет.

Regg Fulton

Спасибо. Никогда раньше не работал с вдовами Апис. Давай я погуглю и проверю. Область Мысли.Предполагается, что Dispose будет выполнять очистку.

1 Ответов

Рейтинг:
1

Regg Fulton

Не берите в голову. Я решил проблему. Решение оказалось до смешного простым. Я

ptrRegion(sx) = rgn.GetHrgn(g)
вместо этого сохраняйте регион и указатель на регион в качестве свойств в моем классе под названием BorderRegion и BorderRegionPtr. Затем замените это
Dim rgn As System.Drawing.Region
			rgn = New Region(mypath)
		  
			'If ptrRegion(sx) = 0 Then
			ptrRegion(sx) = rgn.GetHrgn(g)
с этим кодом
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)
используя регион и указатель региона, я теперь могу использовать регион.releaseHrgn, чтобы освободить ручку GDI.