Notifications
Clear all

[Closed] Mouse input window

 PEN

OK I have it working using On PicBox Paint, it paints directly into the backGroundImage property, I wonder if it is possible to paint into the image property and then just move it using the transform methods? At no point have I told it to paint into the backGroundImage so how can it be changed?

 PEN

Let me rephrase that, it isn’t painting into either the backGroundImage or image properties. Very interesting.

I’ve read about strange results before using the onpaint of a picturebox. image and background image are properties in the control, and the onpaint handler will overwrite these until the control is invalidated and redrawn. if you are then changing these properties you may lose anything you have done in the onpaint. a better explanation of this is here –
http://www.bobpowell.net/picturebox.htm

I took his advice and used the onpaint of a panel control on my joystick control. so the code in visual studio for the onpaint event is like this –

   Private Sub PanelBase_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PanelBase.Paint
 
 		e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias
 
 		If BackgroundStyle = BackgroundStyles.Grid Then
 			Dim Rect1 As System.Drawing.Drawing2D.GraphicsPath = New System.Drawing.Drawing2D.GraphicsPath(New System.Drawing.PointF() {New System.Drawing.PointF(108.5!, 0.000001057378!), New System.Drawing.PointF(117.0604!, -0.000006580535!), New System.Drawing.PointF(124.0!, 6.939575!), New System.Drawing.PointF(124.0!, 15.5!), New System.Drawing.PointF(124.0!, 15.5!), New System.Drawing.PointF(124.0!, 15.5!), New System.Drawing.PointF(124.0!, 15.5!), New System.Drawing.PointF(124.0!, 108.5!), New System.Drawing.PointF(124.0!, 117.0604!), New System.Drawing.PointF(117.0604!, 124.0!), New System.Drawing.PointF(108.5!, 124.0!), New System.Drawing.PointF(15.5!, 124.0!), New System.Drawing.PointF(6.939589!, 124.0!), New System.Drawing.PointF(0.0000005662081!, 117.0604!), New System.Drawing.PointF(0.0000003830284!, 108.5!), New System.Drawing.PointF(0.0000003830282!, 15.5!), New System.Drawing.PointF(-0.000001943159!, 6.939591!), New System.Drawing.PointF(6.939581!, 0.000002968986!), New System.Drawing.PointF(15.49999!, -0.0000002913209!)}, New Byte() {0, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 131})
 			Dim Rect1Brush As HatchBrush = New System.Drawing.Drawing2D.HatchBrush(System.Drawing.Drawing2D.HatchStyle.DottedGrid, Me.CrossHairColor, Me.BackStyleColor)
 			e.Graphics.FillPath(Rect1Brush, Rect1)
 			Rect1.Dispose()
 			Rect1Brush.Dispose()
 		ElseIf BackgroundStyle = BackgroundStyles.Flat Then
 			Dim Rect1 As System.Drawing.Drawing2D.GraphicsPath = New System.Drawing.Drawing2D.GraphicsPath(New System.Drawing.PointF() {New System.Drawing.PointF(108.5!, 0.000001057378!), New System.Drawing.PointF(117.0604!, -0.000006580535!), New System.Drawing.PointF(124.0!, 6.939575!), New System.Drawing.PointF(124.0!, 15.5!), New System.Drawing.PointF(124.0!, 15.5!), New System.Drawing.PointF(124.0!, 15.5!), New System.Drawing.PointF(124.0!, 15.5!), New System.Drawing.PointF(124.0!, 108.5!), New System.Drawing.PointF(124.0!, 117.0604!), New System.Drawing.PointF(117.0604!, 124.0!), New System.Drawing.PointF(108.5!, 124.0!), New System.Drawing.PointF(15.5!, 124.0!), New System.Drawing.PointF(6.939589!, 124.0!), New System.Drawing.PointF(0.0000005662081!, 117.0604!), New System.Drawing.PointF(0.0000003830284!, 108.5!), New System.Drawing.PointF(0.0000003830282!, 15.5!), New System.Drawing.PointF(-0.000001943159!, 6.939591!), New System.Drawing.PointF(6.939581!, 0.000002968986!), New System.Drawing.PointF(15.49999!, -0.0000002913209!)}, New Byte() {0, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 131})
 			Dim Rect1Brush As New SolidBrush(Me.BackStyleColor)
 			e.Graphics.FillPath(Rect1Brush, Rect1)
 			Rect1.Dispose()
 			Rect1Brush.Dispose()
 		ElseIf BackgroundStyle = BackgroundStyles.Check Then
 			Dim Rect1 As System.Drawing.Drawing2D.GraphicsPath = New System.Drawing.Drawing2D.GraphicsPath(New System.Drawing.PointF() {New System.Drawing.PointF(108.5!, 0.000001057378!), New System.Drawing.PointF(117.0604!, -0.000006580535!), New System.Drawing.PointF(124.0!, 6.939575!), New System.Drawing.PointF(124.0!, 15.5!), New System.Drawing.PointF(124.0!, 15.5!), New System.Drawing.PointF(124.0!, 15.5!), New System.Drawing.PointF(124.0!, 15.5!), New System.Drawing.PointF(124.0!, 108.5!), New System.Drawing.PointF(124.0!, 117.0604!), New System.Drawing.PointF(117.0604!, 124.0!), New System.Drawing.PointF(108.5!, 124.0!), New System.Drawing.PointF(15.5!, 124.0!), New System.Drawing.PointF(6.939589!, 124.0!), New System.Drawing.PointF(0.0000005662081!, 117.0604!), New System.Drawing.PointF(0.0000003830284!, 108.5!), New System.Drawing.PointF(0.0000003830282!, 15.5!), New System.Drawing.PointF(-0.000001943159!, 6.939591!), New System.Drawing.PointF(6.939581!, 0.000002968986!), New System.Drawing.PointF(15.49999!, -0.0000002913209!)}, New Byte() {0, 3, 3, 3, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 3, 1, 3, 3, 131})
 			Dim Rect1Brush As HatchBrush = New System.Drawing.Drawing2D.HatchBrush(System.Drawing.Drawing2D.HatchStyle.LargeCheckerBoard, Me.CrossHairColor, Me.BackStyleColor)
 			e.Graphics.FillPath(Rect1Brush, Rect1)
 			Rect1.Dispose()
 			Rect1Brush.Dispose()
 
 		End If
 		If CrossHairStyle <> CrossHairStyles.None Then
 			Dim pn As New Pen(Me.CrossHairColor, Me.CrossHairWidth)
 			pn.DashStyle = Me.CrossHairStyle
 			Dim pt1 As New Point(Me.MovableLabel.Location.X + 12, 0)
 			Dim pt2 As New Point(Me.MovableLabel.Location.X + 12, 126)
 			Dim pt3 As New Point(0, Me.MovableLabel.Location.Y + 12)
 			Dim pt4 As New Point(126, Me.MovableLabel.Location.Y + 12)
 			e.Graphics.DrawLine(pn, pt1, pt2)
 			e.Graphics.DrawLine(pn, pt3, pt4)
 			pn.Dispose()
 		End If
 
 		If DisplayText Then
 			Dim TextFont As System.Drawing.Font = New System.Drawing.Font("Verdana", 8, CType(0, System.Drawing.FontStyle), System.Drawing.GraphicsUnit.Point, 1)
 			Dim TextBrush As System.Drawing.SolidBrush = New System.Drawing.SolidBrush(Me.DisplayTextColor)
 			e.Graphics.DrawString(Me.Text, TextFont, TextBrush, 5, 5)
 			TextFont.Dispose()
 			TextBrush.Dispose()
 		End If
 
 		e.Graphics.Dispose()
 
 	End Sub

please go easy all you code gurus, im a novice vb programmer!

 PEN

I don’t know a thing about VB, what is it you are doing here, making your own dotNet control? If so I can’t do that in Max script and I don’t know VB, C# or anything else I can use.

I have it working really well right now except the onPaint is getting spammed. Not sure how to stop this. Any test I add in there kills it completely.

 PEN

Also I’m not sure how I should be using dispose(), anything I try throws errors. What shoudl I be disposing? and when?

1 Reply
(@lonerobot)
Joined: 11 months ago

Posts: 0

you use dispose() to clear any GDI+ resources from memory – if the paint event fires repeatedly and you havent released them, you could tie up memory. so as i understand it, you release any brushes/shapes you use in the paint event after you have finished with them, as well as the GDI+ graphics object. you can get the idea from the code i posted.

a paint handler has the event handler argument –

System.Windows.Forms.PaintEventArgs

that passes the graphics object in it so in theory you should be able to access it by calling

e.Graphics.Dispose()

the dotnetobject event handlers in max should allow you to access these.

ah sorry paul, i got you. I assumed that as your previous incarnation was max8 this was a dotnet version in visual studio. It could be that the refresh/invalidate of the control is being triggered somewhere else (perhaps in the command panel, or dotnetcontrol object or something, your guess as good as mine) so is clearing whatever you do. I am indeed building a custom dotnet control. i decided that having the class control everything would make an implementation easier, although i realize its an extra dll. My attempts at this solely in max would have been impossible doing it your way, I found i was fumbling around too much and using vs as a testing environment worked better. I hope to release a bunch of controls really soon.

Sorry i cant help more but maybe you could try using the panel control paint to do your GDI+ drawing and calling the controlname.invalidate() function (which triggers a redraw of the control) on the mouse move event.

 PEN

I have something with pictureBox again. I was unnessesarily loading the backGroundImage in the paint handler and that was forcing it to spam. Doesn’t look like I’m getting any major memory leaks any more and it draws really nice. Still not sure where to dispose()

 PEN

OK after all that I have this, still have a leak if you can find it. I’m loading two images one that is 81×81 and the target that is 20×20.

try(destroyDialog testR)catch()
rollout testR "Test"
(
	local col=dotNetClass "system.drawing.color"
	local bgm=dotNetObject "system.drawing.bitMap" ((getDir #UI)+"\\\Icons\penProductions\\joyStick80Sq.bmp")
	local targetBm=dotNetObject "system.drawing.bitMap" ((getDir #UI)+"\\\Icons\penProductions\	arget.bmp")
	local targRad=targetBm.width/2
	local rec=dotNetObject "System.Drawing.Rectangle" 10 10 20 20
	
	dotNetControl picBox "system.windows.forms.pictureBox" width:81 height:81
	
	fn drawTarget control paintArg bg target=
	(
		if rec.x<-targRad then rec.x= -targRad
		if rec.x>bg.width-targRad then rec.x=bg.width-targRad
		if rec.y<-targRad then rec.y=-targRad
		if rec.y>bg.height-targRad then rec.y=bg.height-targRad
		
		graphics=paintArg.graphics
		paintArg.dispose()
		Graphics.DrawImage target rec
	)
	
	on picBox mouseMove arg do
	(
		if arg.button==arg.button.left then
		(
			rec.x=arg.x-targRad
			rec.y=arg.y-targRad
			picBox.Invalidate()
		)
	)
	on picBox mouseUp arg do
	(
	)
	
	on picBox paint senderArg paintArg do
	(
		drawTarget senderArg paintArg bgm targetBm
	)
	
	on testR open do
	(
		targetBm.makeTransparent()
		picBox.backGroundImage=copy bgm
		rec.x=bgm.width/2-targRad
		rec.y=bgm.height/2-targRad

	)
	on testR close do
	(
		bgm.dispose()
		targetBm.dispose()
	)
)
createDialog testR
clearListener()

hi paul,

i usually dispose at the end of my drawing function – but the way you have done it doesnt look like it should have any memory problems. The only thing i have done differently in VS is dispose the graphics surface, not the painteventargs. However, this is still a legitimate call and since the painteventarg contains reference to the grpahics surface i dont know. I get the same exception as you if i call graphics.dispose() so im not sure if it is actually disposing correctly anyway.

Can you describe more about when you see a leak, is it when you move the control handle around?

ive just tested drawing directly onto the picturebox surface with GDI+. I am thinking that with your graphics you are using you could recreate this easilly with system.brushes without having to load the bitmaps. just another option! i have left the parentheses off the dispose call – with them it gives an exception, but without i dont think it’s doing anything. i will look into this when i can.

rollout dnpb "" width:140 height:140
   (	
   	dotnetcontrol pb "System.Windows.Forms.Picturebox" pos:[5,5] width:130 height:130
   	
   	on pb paint e do
   	(	
   	g = e.graphics
   	GDIsmoothing = dotnetclass "System.Drawing.Drawing2D.SmoothingMode"
   	g.SmoothingMode = GDIsmoothing.AntiAlias			
   	g.FillRectangle abrush 3 3 124 124
   	g.FillEllipse anotherbrush 50 50 30 30  
    -- this line is problematic!!	  
      -- g.dispose
   	)
   	
   	on dnpb open do
   	(
   	acolor = dotnetclass "system.drawing.color"
   	abrush = dotnetobject "System.Drawing.SolidBrush" acolor.yellow	
   	anotherbrush = dotnetobject "System.Drawing.SolidBrush" acolor.Fuchsia
   	)	
   	
   	on dnpb close do 
   	(
   -- as are these !!
     --  abrush.dispose
     --  anotherbrush.dispose
   	)
   	
   )
   createdialog dnpb

okay my second take on this GDI+ only method. There is something not right with using the picturebox as a drawing surface. Because if i substitute a panel for the picturebox, the dispose function calls without an exception. What i am seeing that is unwanted is a flicker when moved quickly. I have also set up a test painting onto a label control. this throws an exception if i try to dispose of the graphics in the paint handler. If i remove it, it functions normally without flicker.

I do not know if doing this creates a memory problem. if i perform the same dispose function in a label’s paint handler in Visual studio, I also get the same exception, so this must be a behaviour of the label control.

In VB i would solve flicker by setting the control double buffered property to true. This usually solves any redraw flicker. However i cant seem to set this in an MXS form and it appears that some controls like panel, even though they should inherit this class will still not allow you to set doublebuffered to true.

rollout dnpb "GDI+ paint" width:280 height:140
  (	
 	local acolor = dotnetclass "system.drawing.color"
 	 local abrush = dotnetobject "System.Drawing.SolidBrush" acolor.yellow	
 	 local anotherbrush = dotnetobject "System.Drawing.SolidBrush" acolor.Fuchsia
 	local pos1x = 65
 	local pos1y = 65	 
 	local pos2x = 65
 	local pos2y = 65	 
 	 dotnetcontrol pb "System.Windows.Forms.label" pos:[5,5] width:130 height:130 
 	dotnetcontrol pb1 "System.Windows.Forms.panel" pos:[145,5] width:130 height:130 
 	 
 	 on pb paint e do
 	 (	
 	g = e.graphics	
 	GDIsmoothing = dotnetclass "System.Drawing.Drawing2D.SmoothingMode"
 	 g.SmoothingMode = GDIsmoothing.highspeed		
 	 g.FillRectangle abrush 3 3 124 124
 	 g.FillEllipse anotherbrush (pos1x-15) (pos1y-15) 30 30		
 	)
 	
 	on pb1 paint e do
 	 (	
 	g = e.graphics	
 	GDIsmoothing = dotnetclass "System.Drawing.Drawing2D.SmoothingMode"
 	 g.SmoothingMode = GDIsmoothing.highspeed		
 	 g.FillRectangle abrush 3 3 124 124
 	 g.FillEllipse anotherbrush (pos2x-15) (pos2y-15) 30 30		
 	 g.dispose()
 	)
 	
 	on pb mouseMove sender arg do
 	(			
 		if arg.button==arg.button.left then
 		(			
 			pos1x = arg.x
 			pos1y = arg.y
 			pb.invalidate()
 		)
 	)
 	
 	on pb1 mouseMove sender arg do
 	(
 			
 		if arg.button==arg.button.left then
 		(			
 			pos2x = arg.x
 			pos2y = arg.y
 			pb1.invalidate()
 		)
 	)
 --	  
 	 on dnpb close do 
 	 (
 	 abrush.dispose()
 	 anotherbrush.dispose()
 	 )
 	 
  )
  createdialog dnpb

again, the more i experiment in max makes me think that for me, building a custom user control in VS is the best way to go…

1 Reply
 PEN
(@pen)
Joined: 11 months ago

Posts: 0

Interesting that the forms.panel is showing the same problem that the imgTag is in Max. I have a much brighter out look on doing it with pictureBox at this point. Although I don’t have all the controls working agian I’m nto seeing any of the issues I was using setPixel. I thank you for pointing me down this path. I’m not getting flicker at all and the amount of code that I need to manage this has gone way down. I will report back with speed once I get it all working and see what kind of redraw that I’m getting compared to before and if it is in an acceptable range.

Page 7 / 10