According to your post, I don’t know exactly what would you like to draw on your form of the project. Here I have an example that creates a PictureBox control on the form and uses the Paint event to draw it:
Private pictureBox1 AsNew PictureBox()
PrivateSub Form1_Load(ByVal sender AsObject, ByVal e As System.EventArgs) HandlesMyBase.Load
' Dock the PictureBox to the form and set its background to white.
pictureBox1.Dock = DockStyle.Fill
pictureBox1.BackColor = Color.White
' Connect the Paint event of the PictureBox to the event handler method.
I'm developing an application that draws a map using polygons (ESRI shape maps) like those you can see in google map (states, rivers, streets, etc), and the application has zoom, pan, etc. But some maps has thousand of polygons and drawing all of them every time the paint event fires even to redraw a small region is very slow. I don't know how to improve performance or what technic to use. Can you help me, or put me in the right way.
I think you really must look to override either the OnPaint method or attach a delegate to the Paint event. There are other ways, but you should only use them in exceptional cases; in short, if you can use OnPaint, do so.
Depending on the complexity of what you are attempting to paint, it may be that GDI+ is simply not suited to the task. It is slow, but there are a number of techniques that you can use to speed up rendering that may be worth exploring.
I am assuming that you are already aware that the PaintEventArgs.ClipRectangle property exposes the area that you need to paint, and that this may not necessarily be the entire form region.
There are a number of style bits that you can manipulate (if you inherit from a control type) that will help to speed up and improve the quality of your render and I would recommend you have a quick look at the SetStyle method. However, these improvements are likely to be minimal for a complex paint.
If your paint is static throughout the control lifetime, I would suggest you look to employ an offscreen paint that then gets bitblt'd to the screen on demand. This method means drawing to an in-memory bitmap outside the paint event .... within this method you can acquire the relevant resources (fonts,brushes,pens...), calculate any layout and paint to the image. In the OnPaint method, simply use the g.DrawImage method to pass in the prerendered image, and use the clip rectangle as both the source and destination paint areas (assuming your paint fills the entire client rectangle).
If you are using transformations to control rotation, zoom, scrolling etc, then you will need to remember to transform the cliprectangle to get the appropriate image co-ords to blt.
In short, keep the work within the Paint method to an absolute minimum.
eg.
With MyBase.ClientRectangle
mImage = New Drawing.Bitmap(.Width, .Height)
Using g As Drawing.Graphics = Drawing.Graphics.FromImage(b)
'' Paint your image here against the device context referenced by g
End Using
End With
If you think this recommendation is suitable and want to explore it some more, let me know what you need and I'll see if I can help further.
I'm using Paint event to draw but I'm drawing a shape map with a lot of polygons and when I move the form or any other thing that rises the paint event it's very slow to paint all the polygons again. Is there any way to resolve this For example in VB 6 there was the AutoRedraw property to avoid this problem.
I haven't played around with it yet, but the XNA Framework is perhaps something you could look at - it's a 3D game-creation tool but 3D games are basically "running around in a 3D map" so it may offer you an easy and far more powerful way to take your map tool into the third dimension (2D is of course also part of that). See the XNA forums in the index for more info: http://forums.microsoft.com/MSDN/default.aspx ForumGroupID=20&SiteID=1
But with me.createGraphics none of the drawing will persist. If you minimise the form, move the form off screen or if another window passes over the form then you lose the drawing you did - because the Paint event fires, and draws the form again. So use the paint event!
I'm developing an application that draws a map using polygons (ESRI shape maps) like those you can see in google map (states, rivers, streets, etc), and the application has zoom, pan, etc. But some maps has thousand of polygons and drawing all of them every time the paint event fires even to redraw a small region is very slow. I don't know how to improve performance or what technic to use. Can you help me, or put me in the right way.
Thanks.
Wow ... that sounds like a great project to be involved in.
Well ... GDI+ may simply not be the appropriate technology to use. If you are familiar with GDI, it may be worth going unmanaged as it is considerably quicker, or perhaps make the leap to WPF to benefit from accelerated graphics rendering (although that brings other issues with it).
If you must go the GDI+ route, off the top of my head, what follows is probably the route I would investigate first (noting that I do not have the full scope to consider).
I have kept the comments at an engineering level because you must be a competant programmer to be involved in such a project, but I would quickly branch off an mention that the PaintEventsArgs.ClipRectangle is the area than needs to be painted. It sounds like you might be unnecessarily painting everything each time OnPaint is called. if the ClipRectangle doesn't Intersect with the region of the polygon; the area you anticipate drawing, don't draw it. If you have hundreds of items to draw, it may be worth investing in storing the regions in an easily searchable structure and filtering out those you don't need with a simple algorithm, painting only those that remain.
Knowing I need to support panning, zooming etc, I know I need to employ transformations to my co-ordinates. Presumably zooming involves rendering maps at a greater granularity, therefore this suggests reloading another background map image each time I zoom/at certain stages within the zoom cycle. This means, each time I reach a granularity reload point, I need to recreate my in-memory images (ie, not too often).
I would then start to consider panning and the implications that has. As the form will only render part of my full graphic, it may be that I only need to cache that specific part of it. As panning is likely to occur post zooming, I would probably adopt a technique where I would split each part of the full image into smaller sections (ie smaller in-memory bitmaps, lazy rendered). As the user pans, I would render the new section and stitch it during the painting.
A simple method that transforms the PaintEventArgs.ClipRectangle to the in-memory location (considering zoom, pan, rotation etc) means I can work with a consistent co-ordinate system.
The physical paint method would simply need to tranform the cliprectangle, determine which bitmaps needed to be rendered, bitblt the relevant portions of these bitmaps and then paint any dynamic overlay on top (eg text). The polygons that outline boundaries etc could be painted when the bitmap is created as opposed to during the paint, assuming they scale as required during zooming (if not rebuild the bitmap each time you zoom).
You'll appreciate that your project is complex and that I cannot possibly give you a full design, but hopefully the above will get you started in the right direction.
Good luck ... sounds like a lot of fun.
Richard
Graphics in VB.NET- How do i draw to a form without using onpaint method?
Graphics in VB.NET- How do i draw to a form without using onpaint method?
grimdog
Hi all,
Thanks alot for your post, it is very helpful to me!
dvl_vn
andreas s
dvl_vn,
According to your post, I don’t know exactly what would you like to draw on your form of the project. Here I have an example that creates a PictureBox control on the form and uses the Paint event to draw it:
Private pictureBox1 As New PictureBox()
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Dock the PictureBox to the form and set its background to white.
pictureBox1.Dock = DockStyle.Fill
pictureBox1.BackColor = Color.White
' Connect the Paint event of the PictureBox to the event handler method.
AddHandler pictureBox1.Paint, AddressOf Me.pictureBox1_Paint
' Add the PictureBox control to the Form.
Me.Controls.Add(pictureBox1)
End Sub 'Form1_Load
Private Sub pictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs)
' Create a local version of the graphics object for the PictureBox.
Dim g As Graphics = e.Graphics
' Draw a string on the PictureBox.
g.DrawString("This is a diagonal line drawn on the control", _
New Font("Arial", 10), Brushes.Red, New PointF(30.0F, 30.0F))
' Draw a line in the PictureBox.
g.DrawLine(System.Drawing.Pens.Red, pictureBox1.Left, _
pictureBox1.Top, pictureBox1.Right, pictureBox1.Bottom)
End Sub 'pictureBox1_Paint
JLF
Hi Richard
I'm developing an application that draws a map using polygons (ESRI shape maps) like those you can see in google map (states, rivers, streets, etc), and the application has zoom, pan, etc. But some maps has thousand of polygons and drawing all of them every time the paint event fires even to redraw a small region is very slow. I don't know how to improve performance or what technic to use. Can you help me, or put me in the right way.
Thanks.
LPlate
Hi Ghaby,
I think you really must look to override either the OnPaint method or attach a delegate to the Paint event. There are other ways, but you should only use them in exceptional cases; in short, if you can use OnPaint, do so.
Depending on the complexity of what you are attempting to paint, it may be that GDI+ is simply not suited to the task. It is slow, but there are a number of techniques that you can use to speed up rendering that may be worth exploring.
I am assuming that you are already aware that the PaintEventArgs.ClipRectangle property exposes the area that you need to paint, and that this may not necessarily be the entire form region.
There are a number of style bits that you can manipulate (if you inherit from a control type) that will help to speed up and improve the quality of your render and I would recommend you have a quick look at the SetStyle method. However, these improvements are likely to be minimal for a complex paint.
If your paint is static throughout the control lifetime, I would suggest you look to employ an offscreen paint that then gets bitblt'd to the screen on demand. This method means drawing to an in-memory bitmap outside the paint event .... within this method you can acquire the relevant resources (fonts,brushes,pens...), calculate any layout and paint to the image. In the OnPaint method, simply use the g.DrawImage method to pass in the prerendered image, and use the clip rectangle as both the source and destination paint areas (assuming your paint fills the entire client rectangle).
If you are using transformations to control rotation, zoom, scrolling etc, then you will need to remember to transform the cliprectangle to get the appropriate image co-ords to blt.
In short, keep the work within the Paint method to an absolute minimum.
eg.
With MyBase.ClientRectanglemImage = New Drawing.Bitmap(.Width, .Height)
Using g As Drawing.Graphics = Drawing.Graphics.FromImage(b)
'' Paint your image here against the device context referenced by g
End Using
End With
If you think this recommendation is suitable and want to explore it some more, let me know what you need and I'll see if I can help further.
Richard
ZopoStyle
Do you mean the Paint event Why do you not want to use this event
Pro Australian
MeetJayBlack
I haven't played around with it yet, but the XNA Framework is perhaps something you could look at - it's a 3D game-creation tool but 3D games are basically "running around in a 3D map" so it may offer you an easy and far more powerful way to take your map tool into the third dimension (2D is of course also part of that). See the XNA forums in the index for more info:
http://forums.microsoft.com/MSDN/default.aspx ForumGroupID=20&SiteID=1
MartySeed
me.creategraphics.drawline(new pen(color.blue),0,0,1000,1000)
this draws a diagonal line across the form in one line of code
Bartosz
Hi Richards
Thanks a lot, i'll try to go in that way, i'll post what happens
kcdclan
If you minimise the form, move the form off screen or if another window passes over the form then you lose the drawing you did - because the Paint event fires, and draws the form again.
So use the paint event!
Dan-Teklynx
Wow ... that sounds like a great project to be involved in.
Well ... GDI+ may simply not be the appropriate technology to use. If you are familiar with GDI, it may be worth going unmanaged as it is considerably quicker, or perhaps make the leap to WPF to benefit from accelerated graphics rendering (although that brings other issues with it).
If you must go the GDI+ route, off the top of my head, what follows is probably the route I would investigate first (noting that I do not have the full scope to consider).
I have kept the comments at an engineering level because you must be a competant programmer to be involved in such a project, but I would quickly branch off an mention that the PaintEventsArgs.ClipRectangle is the area than needs to be painted. It sounds like you might be unnecessarily painting everything each time OnPaint is called. if the ClipRectangle doesn't Intersect with the region of the polygon; the area you anticipate drawing, don't draw it. If you have hundreds of items to draw, it may be worth investing in storing the regions in an easily searchable structure and filtering out those you don't need with a simple algorithm, painting only those that remain.
Knowing I need to support panning, zooming etc, I know I need to employ transformations to my co-ordinates. Presumably zooming involves rendering maps at a greater granularity, therefore this suggests reloading another background map image each time I zoom/at certain stages within the zoom cycle. This means, each time I reach a granularity reload point, I need to recreate my in-memory images (ie, not too often).
I would then start to consider panning and the implications that has. As the form will only render part of my full graphic, it may be that I only need to cache that specific part of it. As panning is likely to occur post zooming, I would probably adopt a technique where I would split each part of the full image into smaller sections (ie smaller in-memory bitmaps, lazy rendered). As the user pans, I would render the new section and stitch it during the painting.
A simple method that transforms the PaintEventArgs.ClipRectangle to the in-memory location (considering zoom, pan, rotation etc) means I can work with a consistent co-ordinate system.
The physical paint method would simply need to tranform the cliprectangle, determine which bitmaps needed to be rendered, bitblt the relevant portions of these bitmaps and then paint any dynamic overlay on top (eg text). The polygons that outline boundaries etc could be painted when the bitmap is created as opposed to during the paint, assuming they scale as required during zooming (if not rebuild the bitmap each time you zoom).
You'll appreciate that your project is complex and that I cannot possibly give you a full design, but hopefully the above will get you started in the right direction.
Good luck ... sounds like a lot of fun.
Richard