I have a question on object disposing. On a form I have several controls that represent document pages. Each of these page has a Bitmap and a Graphics object associated. When scrolling the document, pages are continuosly disposed of and recreated on the fly. This is done dozen times for second. If I declare the Bitmap and Graphics objects as Private within the control, do I have to dispose manually them when the control (ie the document page) is disposed? Or they are automatically disposed of ? And what about they are declared Public. Does anything change? Further, if I dispose the bitmap and the graphics based on that bitmap, is the disposing order important (I noticed sometimes I get exceptions due to events still firing, like mouse move when disposing) -P
In article <1161860892.108149.138300@k70g2000cwa.googlegroups.com>, pamelafluente@libero.it says... [quoted text, click to view] > > I have a question on object disposing. > > On a form I have several controls that represent > document pages. > > Each of these page has a Bitmap and a Graphics object associated. > When scrolling the document, pages are continuosly disposed of > and recreated on the fly. This is done dozen times for second. > > If I declare the Bitmap and Graphics objects as Private within the > control, > do I have to dispose manually them when the control (ie the document > page) > is disposed? Or they are automatically disposed of ? > > And what about they are declared Public. Does anything change? > > Further, if I dispose the bitmap and the graphics based on that > bitmap, is the > disposing order important (I noticed sometimes I get exceptions due to > events still firing, > like mouse move when disposing)
Any time you create an object that implements IDisposable, you should Dispose of it when you're done. If you didn't create it (i.e. a Graphics object is handed to you during a Paint event), then don't worry about Disposing it. You don't *have* to Dispose of anything yourself, but things work much smoother if you do. -- Patrick Steele
Disposing of and re-creating a bitmap while scrolling doesn't sound like a good idea. Those are the sorts of things you want hanging around. NEVER declare a field public! Its OOP not POO.... Don't keep Graphics object hanging about. Use 'em, dispose of 'em. If an object implements IDisposable, dispose of it if you created it, leave it for the caller to dispose of if it was passed to you. -- Bob Powell [MVP] Visual C#, System.Drawing Ramuseco Limited .NET consulting http://www.ramuseco.com Find great Windows Forms articles in Windows Forms Tips and Tricks http://www.bobpowell.net/tipstricks.htm Answer those GDI+ questions with the GDI+ FAQ http://www.bobpowell.net/faqmain.htm All new articles provide code in C# and VB.NET. Subscribe to the RSS feeds provided and never miss a new article. [quoted text, click to view] "pamela fluente" <pamelafluente@libero.it> wrote in message news:1161860892.108149.138300@k70g2000cwa.googlegroups.com... > > I have a question on object disposing. > > On a form I have several controls that represent > document pages. > > Each of these page has a Bitmap and a Graphics object associated. > When scrolling the document, pages are continuosly disposed of > and recreated on the fly. This is done dozen times for second. > > If I declare the Bitmap and Graphics objects as Private within the > control, > do I have to dispose manually them when the control (ie the document > page) > is disposed? Or they are automatically disposed of ? > > And what about they are declared Public. Does anything change? > > Further, if I dispose the bitmap and the graphics based on that > bitmap, is the > disposing order important (I noticed sometimes I get exceptions due to > events still firing, > like mouse move when disposing) > > -P >
Bob Powell [MVP] ha scritto: [quoted text, click to view] > Disposing of and re-creating a bitmap while scrolling doesn't sound like a > good idea. Those are the sorts of things you want hanging around.
Thanks Patrick, Thanks Bob :) The problem is the document can have hundred pages. I am currently drawing only the pages which are visible to the user (they can be one or dozens, depending on the zoom). So far I could not see another solutions. Keeping in memory all the pages bitmap would probably be impossible. If you have a better strategy for doing this, please advise. [quoted text, click to view] > > NEVER declare a field public! Its OOP not POO....
right :) [quoted text, click to view] > > Don't keep Graphics object hanging about. Use 'em, dispose of 'em. > > If an object implements IDisposable, dispose of it if you created it, leave > it for the caller to dispose of if it was passed to you.
I guess there is no harm always disposing them. I was just wondering if the graphics objects, associated with picture boxes on then controls, get also disposed, when the control do... -P [quoted text, click to view] > > > > -- > Bob Powell [MVP] > Visual C#, System.Drawing > > Ramuseco Limited .NET consulting > http://www.ramuseco.com > > Find great Windows Forms articles in Windows Forms Tips and Tricks > http://www.bobpowell.net/tipstricks.htm > > Answer those GDI+ questions with the GDI+ FAQ > http://www.bobpowell.net/faqmain.htm > > All new articles provide code in C# and VB.NET. > Subscribe to the RSS feeds provided and never miss a new article. > > > > "pamela fluente" <pamelafluente@libero.it> wrote in message > news:1161860892.108149.138300@k70g2000cwa.googlegroups.com... > > > > I have a question on object disposing. > > > > On a form I have several controls that represent > > document pages. > > > > Each of these page has a Bitmap and a Graphics object associated. > > When scrolling the document, pages are continuosly disposed of > > and recreated on the fly. This is done dozen times for second. > > > > If I declare the Bitmap and Graphics objects as Private within the > > control, > > do I have to dispose manually them when the control (ie the document > > page) > > is disposed? Or they are automatically disposed of ? > > > > And what about they are declared Public. Does anything change? > > > > Further, if I dispose the bitmap and the graphics based on that > > bitmap, is the > > disposing order important (I noticed sometimes I get exceptions due to > > events still firing, > > like mouse move when disposing) > > > > -P > >
Thanks Joergen for all the brilliant ideas provided. I will be working on them ! :) Only one question. You mentioned the double buffering. I am working with VS2005. I do not seem to see a difference when I use it. Is it possible that it applied only to version 1.1. of the framework ? Or perhaps it's because I am actually kind of doing it myself, painting on an "invisible" bitmap and loading it as a picture box image only after finished ? I noticed a significant improvement by avoiding any refresh and simply refreshing the pointer of the image, as this does not seem to cause any refresh of possible objects layed out on the picture boxes (my pages). -P Joergen Bech ha scritto: [quoted text, click to view] > >The problem is the document can have hundred pages. I am currently > >drawing only the pages which are visible to the user (they can be one > >or dozens, depending on the zoom). > > > >So far I could not see another solutions. Keeping in memory all the > >pages bitmap would probably be impossible. > > Question is: Does it take significantly longer to render the pages > compared to saving/loading them from disk? In that case you might > consider caching the page "bitmaps" on disk. Only render pages when > new pages come into view. Read cached pages from disk when "old" > ones come (back) into view. Clear the cache if the zoom level is > changed. > > But I wonder if you cannot just keep most of the pages in view anyway? > > If the zoom level is high (like 100% or more), you can only see part > of a > single page. A single page should be easy to render in realtime, > requiring no caching at all. If the zoom level is low (such as 10%), > there is room for dozens of pages on the screen and though these > might take a bit longer to finish rendering, the resulting bitmaps are > so small that the price of caching them in memory would be very low. > > My recommendation therefore would be to cache the most recent > <nn> number of pages visited in memory (put them in a queue) which > will fit in a buffer of roughly the size of 2-3 *screens* As new pages > are visited, the oldest ones in the queue are removed. So the number > of pages available in the queue would constantly depend on the > current zoom level. If the zoom level is changed, clear the queue > and start over. > > As for performance: I have written a print layout system which uses > something like a hierarchical element layout system where each element > adjusts to its parent depending on a set of rules. Features row- and > column spanning, etc. Even with several hundred page elements, > calculating the layout and rendering those elements (even with inter- > polation enabled) takes little more than 50 ms full screen, double- > buffered. I don't think there should be any problems using the scheme > I propose, but then again, I do not know what you are rendering or > how well optimized your rendering funtions are. > > Note: I presume that you are rendering your pages to scale rather > than storing the bitmaps at full size and rescaling them when > displaying them on the screen :) > > >> If an object implements IDisposable, dispose of it if you created it, leave > >> it for the caller to dispose of if it was passed to you. > > > > I guess there is no harm always disposing them. I was just wondering > >if the graphics objects, associated with picture boxes on then > >controls, get also disposed, when the control do... > > Yes, as long as you do not keep any other references to the images > (I presume we are talking about images and not the Graphics object > handed to you in the paint events) around, the garbage collector will > eventually reclaim the space. If you are just using plain old > picturebox controls, just remove the picturebox from your controls > collection and let the framework do the rest. > > I, for one, would not constantly add/remove pictureboxes from a > controls collection (if that is what you are talking about), but just > render (using double-buffering) all the pages on a custom user > control. > > /Joergen Bech
[quoted text, click to view] >The problem is the document can have hundred pages. I am currently >drawing only the pages which are visible to the user (they can be one >or dozens, depending on the zoom). > >So far I could not see another solutions. Keeping in memory all the >pages bitmap would probably be impossible.
Question is: Does it take significantly longer to render the pages compared to saving/loading them from disk? In that case you might consider caching the page "bitmaps" on disk. Only render pages when new pages come into view. Read cached pages from disk when "old" ones come (back) into view. Clear the cache if the zoom level is changed. But I wonder if you cannot just keep most of the pages in view anyway? If the zoom level is high (like 100% or more), you can only see part of a single page. A single page should be easy to render in realtime, requiring no caching at all. If the zoom level is low (such as 10%), there is room for dozens of pages on the screen and though these might take a bit longer to finish rendering, the resulting bitmaps are so small that the price of caching them in memory would be very low. My recommendation therefore would be to cache the most recent <nn> number of pages visited in memory (put them in a queue) which will fit in a buffer of roughly the size of 2-3 *screens* As new pages are visited, the oldest ones in the queue are removed. So the number of pages available in the queue would constantly depend on the current zoom level. If the zoom level is changed, clear the queue and start over. As for performance: I have written a print layout system which uses something like a hierarchical element layout system where each element adjusts to its parent depending on a set of rules. Features row- and column spanning, etc. Even with several hundred page elements, calculating the layout and rendering those elements (even with inter- polation enabled) takes little more than 50 ms full screen, double- buffered. I don't think there should be any problems using the scheme I propose, but then again, I do not know what you are rendering or how well optimized your rendering funtions are. Note: I presume that you are rendering your pages to scale rather than storing the bitmaps at full size and rescaling them when displaying them on the screen :) [quoted text, click to view] >> If an object implements IDisposable, dispose of it if you created it, leave >> it for the caller to dispose of if it was passed to you. > > I guess there is no harm always disposing them. I was just wondering >if the graphics objects, associated with picture boxes on then >controls, get also disposed, when the control do...
Yes, as long as you do not keep any other references to the images (I presume we are talking about images and not the Graphics object handed to you in the paint events) around, the garbage collector will eventually reclaim the space. If you are just using plain old picturebox controls, just remove the picturebox from your controls collection and let the framework do the rest. I, for one, would not constantly add/remove pictureboxes from a controls collection (if that is what you are talking about), but just render (using double-buffering) all the pages on a custom user control. /Joergen Bech
There is nothing .Net-ish about double buffering. It is just a technique. When I do all my drawing in a usercontrol myself, I add this to the user control code: ---snip--- Public Sub New() ' This call is required by the Windows Form Designer. InitializeComponent() ' Add any initialization after the InitializeComponent() call. SetStyle(ControlStyles.AllPaintingInWmPaint, True) SetStyle(ControlStyles.UserPaint, True) SetStyle(ControlStyles.ResizeRedraw, True) SetStyle(ControlStyles.OptimizedDoubleBuffer, True) End Sub ---snip--- But instead of using this method, it is perfectly acceptable to create a bitmap in memory the size of the client rectangle of the user control (remember to destroy and recreate it if the size of the client rectangle changes), paint everything on that buffer image, then blast the whole thing to the screen using DrawImageUnscaled. Remember to override the OnPaintBackground (comment out the MyBase call) so the system does not paint anything on the background since you are overwriting the whole thing yourself anyway. If rendering "dynamic" elements on an image background, you might consider using triple-buffering, i.e. one buffer with the image, another for the scratch buffer where you combine the image and dynamic elements, and finally the last "buffer" which is the destination. Remember: Only destroy and recreate buffers if their sizes actually change. To elaborate on the simple, system double buffer example I mentioned at the top, I have written this quick test you can try out. Just start a new VB.NET 2005 project and replace the Form1 code with this: ---snip--- Option Explicit On Option Strict On Imports System Public Class Form1 Const USEDOUBLEBUFFERING As Boolean = True Public Sub New() ' This call is required by the Windows Form Designer. InitializeComponent() ' Add any initialization after the InitializeComponent() call. SetStyle(ControlStyles.ResizeRedraw, True) If USEDOUBLEBUFFERING Then SetStyle(ControlStyles.AllPaintingInWmPaint, True) SetStyle(ControlStyles.UserPaint, True) SetStyle(ControlStyles.OptimizedDoubleBuffer, True) End If End Sub Private Sub Form1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint Dim fnt As New Font("Arial", 200, FontStyle.Regular) Dim sf As SizeF = e.Graphics.MeasureString("Test", fnt, -1, System.Drawing.StringFormat.GenericDefault) Dim loc As PointF = New PointF((Me.ClientRectangle.Width - sf.Width) / 2, _ (Me.ClientRectangle.Height - sf.Height) / 2) e.Graphics.DrawString("Test", fnt, Brushes.Blue, loc) End Sub End Class ---snip--- Start the program. Try resizing the form. When USEDOUBLEBUFFERING = True, there should be no flickering. When False, there is plenty of flickering as the form is being cleared and repainted on-screen. Note that although double buffering avoids *flickering*, you will still notice some *tearing*. Flickering happens because areas are cleared, then repainted in the visible space. Tearing happens because the update is not in sync with the monitor, i.e. part of the image is updated during one refresh and the rest of it during the next. For most standard applications (not games), tearing is acceptable, but flickering should be avoided. In my opinion, a flickering view is a sign of incompetence and makes me question the quality of the rest of program whenever I see it. I made a few video games many years ago and yes, the first one did suffer from flickering (which was not unusual at that time), but after that I made every effort to avoid it. Something I have carried with me to application UI programming. To avoid tearing in Windows apps today, the only way I know of is to go with DirectX and take over the whole desktop, but that is hardly relevant for anything but games (or Windows Vista with Aero enabled). /Joergen Bech On 27 Oct 2006 14:45:08 -0700, "pamela fluente" [quoted text, click to view] <pamelafluente@libero.it> wrote: >Thanks Joergen for all the brilliant ideas provided. > >I will be working on them ! :) > > >Only one question. You mentioned the double buffering. I am working >with VS2005. I do not seem to see a difference when I use it. Is it >possible that it applied only to version 1.1. of the framework ? Or >perhaps it's because I am actually kind of doing it myself, painting on >an "invisible" bitmap and loading it as a picture box image only after >finished ? >I noticed a significant improvement by avoiding any refresh and simply >refreshing the pointer of the image, as this does not seem to cause any >refresh of possible objects layed out on the picture boxes (my pages). > >-P > >Joergen Bech ha scritto: > >> >The problem is the document can have hundred pages. I am currently >> >drawing only the pages which are visible to the user (they can be one >> >or dozens, depending on the zoom). >> > >> >So far I could not see another solutions. Keeping in memory all the >> >pages bitmap would probably be impossible. >> >> Question is: Does it take significantly longer to render the pages >> compared to saving/loading them from disk? In that case you might >> consider caching the page "bitmaps" on disk. Only render pages when >> new pages come into view. Read cached pages from disk when "old" >> ones come (back) into view. Clear the cache if the zoom level is >> changed. >> >> But I wonder if you cannot just keep most of the pages in view anyway? >> >> If the zoom level is high (like 100% or more), you can only see part >> of a >> single page. A single page should be easy to render in realtime, >> requiring no caching at all. If the zoom level is low (such as 10%), >> there is room for dozens of pages on the screen and though these >> might take a bit longer to finish rendering, the resulting bitmaps are >> so small that the price of caching them in memory would be very low. >> >> My recommendation therefore would be to cache the most recent >> <nn> number of pages visited in memory (put them in a queue) which >> will fit in a buffer of roughly the size of 2-3 *screens* As new pages >> are visited, the oldest ones in the queue are removed. So the number >> of pages available in the queue would constantly depend on the >> current zoom level. If the zoom level is changed, clear the queue >> and start over. >> >> As for performance: I have written a print layout system which uses >> something like a hierarchical element layout system where each element >> adjusts to its parent depending on a set of rules. Features row- and >> column spanning, etc. Even with several hundred page elements,
Joergen Bech ha scritto: [quoted text, click to view] > There is nothing .Net-ish about double buffering. It is just > a technique. .... > SetStyle(ControlStyles.AllPaintingInWmPaint, True) > SetStyle(ControlStyles.UserPaint, True) > SetStyle(ControlStyles.ResizeRedraw, True) > SetStyle(ControlStyles.OptimizedDoubleBuffer, True) >
Thanks Joergen, very helpful. Thanks for the beautiful example. Now I see what you meant. Probably the fact that I never saw that flickering is due to the fact that I am not working with the Paint event. I am definining pages as controls containing a docked picture box and within each page I define a graphics derived from the picture box image. These pages are rendered as "controls" of a scrollable panel (representing the document). Following the suggestions just provided I have just added some dispose command on the "page" (even though it is probably unnecessary (?)) Private Graphics As Graphics Private Bitmap As Bitmap .... Private Sub PageSurface_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed ' here I dispose : Me.Graphics, Me.Bitmap End Sub My document layout is "bidimensional" (I have pages in a grid, like a crosstab of pages) and on the pages there are several object (like very large tables or images: a table can span even 10 pages or more bottom and 100 pages right) that are split on the pages. Every object is recomputed and split in portions on each page and only the pages that are currently visible to the user are drawn (or rebuilt if size changed) each time. In my strategy I do not need to DrawImageUnscaled: I simply refresh the pointer to the image and this causes the newly painted page to appear smootly... Do you think I should make changes to this strategy? I really did NOT "know" how to do it, but this one is the result of many attempts I made to find the "smoothest" result ... I may be missing something important though. [quoted text, click to view] > ---snip--- > > But instead of using this method, it is perfectly acceptable to > create a bitmap in memory the size of the client rectangle of > the user control (remember to destroy and recreate it if the > size of the client rectangle changes), paint everything on > that buffer image, then blast the whole thing to the screen > using DrawImageUnscaled. Remember to override the > OnPaintBackground (comment out the MyBase call) so the > system does not paint anything on the background since > you are overwriting the whole thing yourself anyway. > > If rendering "dynamic" elements on an image background, > you might consider using triple-buffering, i.e. one buffer with > the image, another for the scratch buffer where you combine > the image and dynamic elements, and finally the last "buffer" > which is the destination. Remember: Only destroy and recreate > buffers if their sizes actually change.
In the previous post you mentioned an application of yours where you solve a similar problem. If it is possible and there is some kind of downloadable version or demo, I would like to take a look at the degree of smoothness you have achieved to have an idea of what we are talking about and the kind of result I should aim to. Thanks a lot, -P [quoted text, click to view] > > >> > >> /Joergen Bech
[quoted text, click to view] > > ---snip---
Thanks a lot Joergen, this is very helpful. It's really kind of you to provide such quality help. Actually based on your suggestion of using the drawimage function for the pages, I am actually thinking to modify my current strategy. I am thinking to replace the controls (which usually are relatively "heavy", with directly drawn images). Actualy the images I already have, because they are just the bitmap I currently load as image in the picture boxes. The only complication is that would change the coordinates of the mouse events (I have a lot of mouse processing, dragging and so on, on the pages). But I expect the effort could be worth. Drawing directly the pages on a bitmap which represent the vievable portion of the document should be much quicker than addin the page controls. Another complication I can foresee is with scrolling. Imagine I have a 100 pages vertically and some othe 10 horizontally. If I place the pages as picture boxes in a scrollable panel it's easy to scroll and to dispose them when go out of scope. I am not sure I will be able to handle this on a bitmap (representing the document). Hmmm, In this case the bitmap would remain "still" and what change is just the portion of document which is projected on to it... -P
Joergen Bech ha scritto: .... [quoted text, click to view] > > e.Graphics.DrawImageUnscaled(buffer, e.ClipRectangle) > > gBuffer.Dispose() > > Debug.WriteLine("Count: " & count.ToString) > > End Sub > > Protected Overrides Sub OnPaintBackground(ByVal e As > System.Windows.Forms.PaintEventArgs) > 'Do nothing here. Do not call the base event handler. > End Sub > > End Class
Thanks Joergen. Very very helpful. I am going to rewrite completely my editor based on you enlighting suggestions :) -P [quoted text, click to view] > ---snip---
On Sat, 28 Oct 2006 09:24:00 +0200, Joergen Bech [quoted text, click to view] >If rendering "dynamic" elements on an image background, >you might consider using triple-buffering, i.e. one buffer with >the image, another for the scratch buffer where you combine >the image and dynamic elements, and finally the last "buffer" >which is the destination. Remember: Only destroy and recreate >buffers if their sizes actually change.
I think I have my terms mixed up a bit. Check http://en.wikipedia.org/wiki/Triple_buffering for a better definition. Let's just call it "off-screen compositing using as many buffers as necessary". [quoted text, click to view] >For most standard applications (not games), tearing is acceptable, >but flickering should be avoided. In my opinion, a flickering view >is a sign of incompetence and makes me question the quality of the >rest of program whenever I see it. I made a few video games many >years ago and yes, the first one did suffer from flickering (which was >not unusual at that time), but after that I made every effort to avoid >it. Something I have carried with me to application UI programming.
Let me put that in more diplomatic terms before I start coming across like something I'm not: Flickering detracts from my/the overall user experience. I do not like it myself, hence I strive to eliminate it from my own programs/controls. /Joergen Bech
[quoted text, click to view] > In my strategy I do not need to DrawImageUnscaled: I simply refresh >the pointer to > the image and this causes the newly painted page to appear smootly... > Do you think I should make changes to this strategy? I really did NOT >"know" how to do it, > but this one is the result of many attempts I made to find the >"smoothest" result ... > I may be missing something important though.
There is no right or wrong way to do things. "My" way requires more work, but offers more control. "Your" way might be quicker to implement. If it looks right and feels right, it is right. [quoted text, click to view] > In the previous post you mentioned an application of yours where you > solve a similar problem. If it is possible and there is some kind of >downloadable > version or demo, I would like to take a look at the degree of >smoothness you have > achieved to have an idea of what we are talking about and the kind of >result I should aim to.
Sorry. Would love to release my little print layout/preview/pdf export framework, but it is a small part of a commercial product for a niche market (one of those: if you are not in the market, you'll never hear about it). It is not mine to give away, even though it is just a generic component. Just fire up Microsoft Word, fill a page with text and various graphical elements, put it in landscape mode, do a print preview wit view set to Whole Page, then resize the preview window. Pretty fast update. Again: If it looks ok, you are done. I can, however, offer two more tips: 1. Use Process Explorer from SysInternals to check if the memory or (gdi) handle count fluctuates wildly when you constantly resize your preview window. 2. Use the MemoryWatch class I wrote for my own use (see below) to check how much memory your buffers are eating up. You can check MemoryTotal either after each refresh or in a timer event (write the value to debug or the caption of your form). I don't think you should be concerned with buffers taking up 20-30MB, but if the value sometimes shoots over 100MB or more, you probably need to rethink your strategy, as PCs equipped with lesser amounts of RAM might not provide the same experience once they hit the ceiling. /Joergen Bech ---snip--- Option Explicit On Option Strict On Imports System.Diagnostics Public Class MemoryWatch Private _Total As Long 'Total memory used at last call to Start or CheckPoint Private _Start As Long 'Memory used at the time of the last call to Start Private _Previous As Long 'Previous _Total - _Start value Public Sub New() Start() End Sub Public Sub Start(Optional ByVal forceFullCollection As Boolean = True) Me._Total = System.GC.GetTotalMemory(forceFullCollection) Me._Start = Me._Total Me._Previous = Me._Total End Sub Public Sub CheckPoint(Optional ByVal forceFullCollection As Boolean = True) Me._Previous = MemoryUsed(False) Me._Total = System.GC.GetTotalMemory(forceFullCollection) End Sub Public ReadOnly Property MemoryUsed(Optional ByVal SetCheckPoint As Boolean = False) As Long 'Returns the amount of extra memory used relative to _Start at the last call to Start or CheckPoint Get If SetCheckPoint Then CheckPoint() End If Return Me._Total - Me._Start End Get End Property Public ReadOnly Property MemoryTotal(Optional ByVal SetCheckPoint As Boolean = False) As Long 'Returns the total amount of memory used at the time Start or CheckPoint was called Get If SetCheckPoint Then CheckPoint() End If Return Me._Total End Get End Property Public ReadOnly Property MemoryDelta(Optional ByVal SetCheckPoint As Boolean = False) As Long 'Returns the difference in memory used between last call to CheckPoint and the previous call 'to Start or CheckPoint. Get If SetCheckPoint Then CheckPoint() End If Return MemoryUsed(False) - Me._Previous End Get End Property End Class ---snip---
[quoted text, click to view] >Another complication I can foresee is with scrolling. Imagine I have a >100 pages vertically and some othe 10 horizontally. If I place the >pages as picture boxes in a scrollable panel it's easy to scroll and to >dispose them when go out of scope. I am not sure I will be able to >handle this on a bitmap (representing the document). Hmmm, In this case >the bitmap would remain "still" and what change is just the portion of >document which is projected on to it...
Just add a horizontal and vertical scrollbar to the usercontrol. Recalculate their positions, sizes, max values, and visibility every time the control is resized. Use current values as offsets when processing subsequent mouse events. When calculating whether or not to show either vertical or horizontal scrollbar, remember that the appearance of one limits the space available on the other axis, which suddenly might require that the other is shown as well :) .... An easier solution might be to set the size of your user control to encompass the pages you need, place that single user control on a scrollable panel, thereby getting the scrollbars for free. Only paint on the part of the user control which is visible. In this case you should do any buffering yourself. Do NOT use SetStyle(...) to let the system handle the buffering, as it will create a buffer the size of the control. Try out the code below. Start a new VB.NET project, add a new UserControl named "HugeControl" with the code shown below. Set Form1.AutoScroll = True. Add an instance of HugeControl to Form1 and set its size to 30.000 x 30.000. Yes, a 30.000 x 30.000 pixel control with double-buffered rendering without taking up more memory for the buffer than the size of the screen (make sure you read the comments). /Joergen Bech ---snip--- Option Explicit On Option Strict On Public Class HugeControl Private buffer As Bitmap Public Sub New() ' This call is required by the Windows Form Designer. InitializeComponent() ' ' Add any initialization after the InitializeComponent() call. 'NO! Do NOT use the system's double buffering. A buffer matching the ' full size of the control would be created, even if we are only ' going to show a small portion of it. ' If you enable this code, memory will disappear and the app might ' even crash. ' SetStyle(ControlStyles.AllPaintingInWmPaint, True) ' SetStyle(ControlStyles.OptimizedDoubleBuffer, True) ' SetStyle(ControlStyles.ResizeRedraw, True) ' SetStyle(ControlStyles.UserPaint, True) 'We are being lazy here by just once and for all creating a buffer 'the size of the primary screen. In the case that the primary screen 'is smaller than a secondary screen and we are displaying the application 'on the secondary screen, this is a really, really bad idea. buffer = New Bitmap(Screen.PrimaryScreen.Bounds.Width, _ Screen.PrimaryScreen.Bounds.Height, _ System.Drawing.Imaging.PixelFormat.Format32bppPArgb) End Sub Private Sub HugeControl_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint Dim count As Integer = 0 Dim offsetX As Integer = -e.ClipRectangle.X Dim offsetY As Integer = -e.ClipRectangle.Y Dim gBuffer As Graphics = Graphics.FromImage(buffer) gBuffer.FillRectangle(New SolidBrush(Me.BackColor), New Rectangle(0, 0, e.ClipRectangle.Width, e.ClipRectangle.Height)) For x As Integer = 0 To Me.ClientRectangle.Width Step 64 Dim x255 As Integer = CType((x / Me.ClientRectangle.Width) * 255, Integer) For y As Integer = 0 To Me.ClientRectangle.Height Step 64 Dim y255 As Integer = CType((y / Me.ClientRectangle.Height) * 255, Integer) Dim clr As Color = Color.FromArgb(x255, x255, y255) Dim destrect As New Rectangle(x, y, 64, 64) If e.ClipRectangle.IntersectsWith(destrect) Then Dim bufferrect As New Rectangle(x + offsetX, y + offsetY, 64, 64) gBuffer.FillEllipse(New SolidBrush(clr), bufferrect) count = count + 1 End If Next Next e.Graphics.DrawImageUnscaled(buffer, e.ClipRectangle) gBuffer.Dispose() Debug.WriteLine("Count: " & count.ToString) End Sub Protected Overrides Sub OnPaintBackground(ByVal e As System.Windows.Forms.PaintEventArgs) 'Do nothing here. Do not call the base event handler. End Sub End Class ---snip---
Joergen Bech ha scritto: [quoted text, click to view] > 'NO! Do NOT use the system's double buffering. A buffer > matching the > ' full size of the control would be created, even if we are
Hello Joergen, I wanted just let you know I have rewritten the code for layout visualization. I have removed the controls (pages) layed out on a scrolling panel. As you suggested, I have used a viewport with a couple of scrollbars (vertical and horizontal). Only the pages visible are plotted on the viewport and their origin (the "starting point" of layout) is shifted using the bars to give the impression of scrolling. I draw the pages on a bitmap (buffer) which is loaded into the viewport after finishing drawing. The final result is much smoother and faster. I have not measured it, but it's probably more than 10 times faster. I still have to refine some details (there is something strange going on with the horizontal bar) scrolling but I am quite happy with that . Thanks :) -P
Don't see what you're looking for? Try a search.
|