all groups > dotnet drawing api > may 2005 >
dotnet drawing api :
Invalidating a region and having only that region drawn
Hello, In my application I perform all the drawing operations from within the form's OnPaint method (the form is ultimately a TabPage derivative) ie protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); //the base class LayerView.OnPaint handles things like AutoScrollPosition int s = 1; // temporary dummy scale value m_building.DrawBuildingLayer(g,s,this.Name); m_columns.DrawColumnsLayer(g,s,this.Name); } The drawing works well and smoothly handles operations such as scrolling. It is my understanding that when Invalidate() is called ie with no parameters, the entire client area of the form is added to the update region and a paint message is sent that raises the Paint event which is handled by the OnPaint handler. OK When Invalidate(region) is called, I believe that only that region is added to the form's update region resulting in only that region being redrawn at the next Paint message. Either way, calling Invalidate results in OnPaint to be executed. When I call Invalidate() the entire client area is redrawn with both drawing functions called and this is exactly the outcome that I want for that scenario. The problem is that when I only want to redraw a invalidated region of this form, the entire form is redrawn( which is causing objects to be appear incorrectly). ie When I call Invalidate(with a specific region) in order to only have that region redrawn I do NOT intend for the likes of DrawBuildingLayer nor DrawColumnsLayer to be called. Obviously they are being called because of their presence in OnPaint(). I cannot think of any other place where I could call these draw functions other than OnPaint and I want to steer clear of CreateGraphics. Are there any suggestions regarding a strategy of how I could call Invalidate(region) and only have that region redrawn ? Thanks Andrew.
Does anyone have any feedback regarding this post ? [quoted text, click to view] "Andrew" wrote: > Hello, > > In my application I perform all the drawing operations from within the form's > OnPaint method (the form is ultimately a TabPage derivative) ie > > protected override void OnPaint(PaintEventArgs e) > { > base.OnPaint(e); > //the base class LayerView.OnPaint handles things like AutoScrollPosition > int s = 1; // temporary dummy scale value > m_building.DrawBuildingLayer(g,s,this.Name); > m_columns.DrawColumnsLayer(g,s,this.Name); > } > > The drawing works well and smoothly handles operations such as scrolling. > > It is my understanding that when Invalidate() is called ie with no > parameters, the entire client area of the form is added to the update region > and a paint message is sent that raises the Paint event which is handled by > the OnPaint handler. OK > > When Invalidate(region) is called, I believe that only that region is added > to the form's update region resulting in only that region being redrawn at > the next Paint message. > > Either way, calling Invalidate results in OnPaint to be executed. > > When I call Invalidate() the entire client area is redrawn with both drawing > functions called and this is exactly the outcome that I want for that > scenario. > > The problem is that when I only want to redraw a invalidated region of this > form, > the entire form is redrawn( which is causing objects to be appear > incorrectly). > > ie When I call Invalidate(with a specific region) in order to only have that > region redrawn I do NOT intend for the likes of DrawBuildingLayer nor > DrawColumnsLayer > to be called. Obviously they are being called because of their presence in > OnPaint(). > > I cannot think of any other place where I could call these draw functions > other than OnPaint and I want to steer clear of CreateGraphics. > > Are there any suggestions regarding a strategy of how I could call > Invalidate(region) and only have that region redrawn ? > > > Thanks > > Andrew.
Painting works like this: The system stores the results of invalidate calls internally. Invalidate without parameters will mark a whole window for refreshing, invalidate with parameters will add regions to the list of "dirty" areas maintained by the system. When the queue is empty and there is nothing else to do, the system checks for dirty areas and issues a WM_PAINT message if any are found, otherwise it issues a WM_ENTERIDLE message to kick-off idle time processing. In all cases the result of the WM_PAINT message, for Windows Forms programs, is to run the OnPaint override which in turn kicks of the Paint event. The clipping region set in the OnPaint event arguments will be the sum of all the regions or the whole window depending on whether Invalidate was called without parameters. It's up to your code to either keep a list of its own dirty rectangles / regions OR to do output based on the bounds of the clipping region provided by the paint event arguments. Whatever paint strategies you devise, such as only drawing partial content or layers, is entirely up to you and needs to be managed by you. The system doesn't care about reporting anything except that there is an area of screen marked as being in need of a refresh. -- Bob Powell [MVP] Visual C#, System.Drawing 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] "Andrew" <Andrew@discussions.microsoft.com> wrote in message news:B82AC0B1-5BFF-4867-A7A6-B8E0DB074432@microsoft.com... > Hello, > > In my application I perform all the drawing operations from within the > form's > OnPaint method (the form is ultimately a TabPage derivative) ie > > protected override void OnPaint(PaintEventArgs e) > { > base.OnPaint(e); > //the base class LayerView.OnPaint handles things like > AutoScrollPosition > int s = 1; // temporary dummy scale value > m_building.DrawBuildingLayer(g,s,this.Name); > m_columns.DrawColumnsLayer(g,s,this.Name); > } > > The drawing works well and smoothly handles operations such as scrolling. > > It is my understanding that when Invalidate() is called ie with no > parameters, the entire client area of the form is added to the update > region > and a paint message is sent that raises the Paint event which is handled > by > the OnPaint handler. OK > > When Invalidate(region) is called, I believe that only that region is > added > to the form's update region resulting in only that region being redrawn at > the next Paint message. > > Either way, calling Invalidate results in OnPaint to be executed. > > When I call Invalidate() the entire client area is redrawn with both > drawing > functions called and this is exactly the outcome that I want for that > scenario. > > The problem is that when I only want to redraw a invalidated region of > this > form, > the entire form is redrawn( which is causing objects to be appear > incorrectly). > > ie When I call Invalidate(with a specific region) in order to only have > that > region redrawn I do NOT intend for the likes of DrawBuildingLayer nor > DrawColumnsLayer > to be called. Obviously they are being called because of their presence in > OnPaint(). > > I cannot think of any other place where I could call these draw functions > other than OnPaint and I want to steer clear of CreateGraphics. > > Are there any suggestions regarding a strategy of how I could call > Invalidate(region) and only have that region redrawn ? > > > Thanks > > Andrew. >
Thanks, I will need to rethink my drawing strategy paying closer attention to the clipping region. [quoted text, click to view] "Bob Powell [MVP]" wrote: > Painting works like this: > > The system stores the results of invalidate calls internally. Invalidate > without parameters will mark a whole window for refreshing, invalidate with > parameters will add regions to the list of "dirty" areas maintained by the > system. > > When the queue is empty and there is nothing else to do, the system checks > for dirty areas and issues a WM_PAINT message if any are found, otherwise it > issues a WM_ENTERIDLE message to kick-off idle time processing. > > In all cases the result of the WM_PAINT message, for Windows Forms programs, > is to run the OnPaint override which in turn kicks of the Paint event. > > The clipping region set in the OnPaint event arguments will be the sum of > all the regions or the whole window depending on whether Invalidate was > called without parameters. > > It's up to your code to either keep a list of its own dirty rectangles / > regions OR to do output based on the bounds of the clipping region provided > by the paint event arguments. Whatever paint strategies you devise, such as > only drawing partial content or layers, is entirely up to you and needs to > be managed by you. The system doesn't care about reporting anything except > that there is an area of screen marked as being in need of a refresh. > > -- > Bob Powell [MVP] > Visual C#, System.Drawing > > 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. > > > > > > "Andrew" <Andrew@discussions.microsoft.com> wrote in message > news:B82AC0B1-5BFF-4867-A7A6-B8E0DB074432@microsoft.com... > > Hello, > > > > In my application I perform all the drawing operations from within the > > form's > > OnPaint method (the form is ultimately a TabPage derivative) ie > > > > protected override void OnPaint(PaintEventArgs e) > > { > > base.OnPaint(e); > > //the base class LayerView.OnPaint handles things like > > AutoScrollPosition > > int s = 1; // temporary dummy scale value > > m_building.DrawBuildingLayer(g,s,this.Name); > > m_columns.DrawColumnsLayer(g,s,this.Name); > > } > > > > The drawing works well and smoothly handles operations such as scrolling. > > > > It is my understanding that when Invalidate() is called ie with no > > parameters, the entire client area of the form is added to the update > > region > > and a paint message is sent that raises the Paint event which is handled > > by > > the OnPaint handler. OK > > > > When Invalidate(region) is called, I believe that only that region is > > added > > to the form's update region resulting in only that region being redrawn at > > the next Paint message. > > > > Either way, calling Invalidate results in OnPaint to be executed. > > > > When I call Invalidate() the entire client area is redrawn with both > > drawing > > functions called and this is exactly the outcome that I want for that > > scenario. > > > > The problem is that when I only want to redraw a invalidated region of > > this > > form, > > the entire form is redrawn( which is causing objects to be appear > > incorrectly). > > > > ie When I call Invalidate(with a specific region) in order to only have > > that > > region redrawn I do NOT intend for the likes of DrawBuildingLayer nor > > DrawColumnsLayer > > to be called. Obviously they are being called because of their presence in > > OnPaint(). > > > > I cannot think of any other place where I could call these draw functions > > other than OnPaint and I want to steer clear of CreateGraphics. > > > > Are there any suggestions regarding a strategy of how I could call > > Invalidate(region) and only have that region redrawn ? > > > > > > Thanks > > > > Andrew. > > > >
Hi Andrew, I could be wrong but I get the feeling you haven't fully understood what Bob was saying. You shouldn't be attempting to use clipping at all to manipulate the logical content of a window. The job of a paint handler is *just* to paint part or all of a window with the correct content of the moment as ascertained from state maintained external to the whole painting paradigm. You should remember that Windows itself can invalidate any part of your window at any time. This is not specific to .NET but is simply how Windows has always worked. Cheers Doug Forster [quoted text, click to view] "Andrew" <Andrew@discussions.microsoft.com> wrote in message news:18697CA9-3687-425F-8458-1E9FA99BAC84@microsoft.com... > Thanks, > > I will need to rethink my drawing strategy paying closer attention to the > clipping region. > > > "Bob Powell [MVP]" wrote: > >> Painting works like this: >> >> The system stores the results of invalidate calls internally. Invalidate >> without parameters will mark a whole window for refreshing, invalidate >> with >> parameters will add regions to the list of "dirty" areas maintained by >> the >> system. >> >> When the queue is empty and there is nothing else to do, the system >> checks >> for dirty areas and issues a WM_PAINT message if any are found, otherwise >> it >> issues a WM_ENTERIDLE message to kick-off idle time processing. >> >> In all cases the result of the WM_PAINT message, for Windows Forms >> programs, >> is to run the OnPaint override which in turn kicks of the Paint event. >> >> The clipping region set in the OnPaint event arguments will be the sum of >> all the regions or the whole window depending on whether Invalidate was >> called without parameters. >> >> It's up to your code to either keep a list of its own dirty rectangles / >> regions OR to do output based on the bounds of the clipping region >> provided >> by the paint event arguments. Whatever paint strategies you devise, such >> as >> only drawing partial content or layers, is entirely up to you and needs >> to >> be managed by you. The system doesn't care about reporting anything >> except >> that there is an area of screen marked as being in need of a refresh. >> >> -- >> Bob Powell [MVP] >> Visual C#, System.Drawing >> >> 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. >> >> >> >> >> >> "Andrew" <Andrew@discussions.microsoft.com> wrote in message >> news:B82AC0B1-5BFF-4867-A7A6-B8E0DB074432@microsoft.com... >> > Hello, >> > >> > In my application I perform all the drawing operations from within the >> > form's >> > OnPaint method (the form is ultimately a TabPage derivative) ie >> > >> > protected override void OnPaint(PaintEventArgs e) >> > { >> > base.OnPaint(e); >> > //the base class LayerView.OnPaint handles things like >> > AutoScrollPosition >> > int s = 1; // temporary dummy scale value >> > m_building.DrawBuildingLayer(g,s,this.Name); >> > m_columns.DrawColumnsLayer(g,s,this.Name); >> > } >> > >> > The drawing works well and smoothly handles operations such as >> > scrolling. >> > >> > It is my understanding that when Invalidate() is called ie with no >> > parameters, the entire client area of the form is added to the update >> > region >> > and a paint message is sent that raises the Paint event which is >> > handled >> > by >> > the OnPaint handler. OK >> > >> > When Invalidate(region) is called, I believe that only that region is >> > added >> > to the form's update region resulting in only that region being redrawn >> > at >> > the next Paint message. >> > >> > Either way, calling Invalidate results in OnPaint to be executed. >> > >> > When I call Invalidate() the entire client area is redrawn with both >> > drawing >> > functions called and this is exactly the outcome that I want for that >> > scenario. >> > >> > The problem is that when I only want to redraw a invalidated region of >> > this >> > form, >> > the entire form is redrawn( which is causing objects to be appear >> > incorrectly). >> > >> > ie When I call Invalidate(with a specific region) in order to only have >> > that >> > region redrawn I do NOT intend for the likes of DrawBuildingLayer nor >> > DrawColumnsLayer >> > to be called. Obviously they are being called because of their presence >> > in >> > OnPaint(). >> > >> > I cannot think of any other place where I could call these draw >> > functions >> > other than OnPaint and I want to steer clear of CreateGraphics. >> > >> > Are there any suggestions regarding a strategy of how I could call >> > Invalidate(region) and only have that region redrawn ? >> > >> > >> > Thanks >> > >> > Andrew. >> > >> >> >>
Doug, Thanks for your comment. Andrew. [quoted text, click to view] "Doug Forster" wrote: > Hi Andrew, > > I could be wrong but I get the feeling you haven't fully understood what Bob > was saying. You shouldn't be attempting to use clipping at all to manipulate > the logical content of a window. The job of a paint handler is *just* to > paint part or all of a window with the correct content of the moment as > ascertained from state maintained external to the whole painting paradigm. > You should remember that Windows itself can invalidate any part of your > window at any time. This is not specific to .NET but is simply how Windows > has always worked. > > Cheers > Doug Forster > > "Andrew" <Andrew@discussions.microsoft.com> wrote in message > news:18697CA9-3687-425F-8458-1E9FA99BAC84@microsoft.com... > > Thanks, > > > > I will need to rethink my drawing strategy paying closer attention to the > > clipping region. > > > > > > "Bob Powell [MVP]" wrote: > > > >> Painting works like this: > >> > >> The system stores the results of invalidate calls internally. Invalidate > >> without parameters will mark a whole window for refreshing, invalidate > >> with > >> parameters will add regions to the list of "dirty" areas maintained by > >> the > >> system. > >> > >> When the queue is empty and there is nothing else to do, the system > >> checks > >> for dirty areas and issues a WM_PAINT message if any are found, otherwise > >> it > >> issues a WM_ENTERIDLE message to kick-off idle time processing. > >> > >> In all cases the result of the WM_PAINT message, for Windows Forms > >> programs, > >> is to run the OnPaint override which in turn kicks of the Paint event. > >> > >> The clipping region set in the OnPaint event arguments will be the sum of > >> all the regions or the whole window depending on whether Invalidate was > >> called without parameters. > >> > >> It's up to your code to either keep a list of its own dirty rectangles / > >> regions OR to do output based on the bounds of the clipping region > >> provided > >> by the paint event arguments. Whatever paint strategies you devise, such > >> as > >> only drawing partial content or layers, is entirely up to you and needs > >> to > >> be managed by you. The system doesn't care about reporting anything > >> except > >> that there is an area of screen marked as being in need of a refresh. > >> > >> -- > >> Bob Powell [MVP] > >> Visual C#, System.Drawing > >> > >> 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. > >> > >> > >> > >> > >> > >> "Andrew" <Andrew@discussions.microsoft.com> wrote in message > >> news:B82AC0B1-5BFF-4867-A7A6-B8E0DB074432@microsoft.com... > >> > Hello, > >> > > >> > In my application I perform all the drawing operations from within the > >> > form's > >> > OnPaint method (the form is ultimately a TabPage derivative) ie > >> > > >> > protected override void OnPaint(PaintEventArgs e) > >> > { > >> > base.OnPaint(e); > >> > //the base class LayerView.OnPaint handles things like > >> > AutoScrollPosition > >> > int s = 1; // temporary dummy scale value > >> > m_building.DrawBuildingLayer(g,s,this.Name); > >> > m_columns.DrawColumnsLayer(g,s,this.Name); > >> > } > >> > > >> > The drawing works well and smoothly handles operations such as > >> > scrolling. > >> > > >> > It is my understanding that when Invalidate() is called ie with no > >> > parameters, the entire client area of the form is added to the update > >> > region > >> > and a paint message is sent that raises the Paint event which is > >> > handled > >> > by > >> > the OnPaint handler. OK > >> > > >> > When Invalidate(region) is called, I believe that only that region is > >> > added > >> > to the form's update region resulting in only that region being redrawn > >> > at > >> > the next Paint message. > >> > > >> > Either way, calling Invalidate results in OnPaint to be executed. > >> > > >> > When I call Invalidate() the entire client area is redrawn with both > >> > drawing > >> > functions called and this is exactly the outcome that I want for that > >> > scenario. > >> > > >> > The problem is that when I only want to redraw a invalidated region of > >> > this > >> > form, > >> > the entire form is redrawn( which is causing objects to be appear > >> > incorrectly). > >> > > >> > ie When I call Invalidate(with a specific region) in order to only have > >> > that > >> > region redrawn I do NOT intend for the likes of DrawBuildingLayer nor > >> > DrawColumnsLayer > >> > to be called. Obviously they are being called because of their presence > >> > in > >> > OnPaint(). > >> > > >> > I cannot think of any other place where I could call these draw > >> > functions > >> > other than OnPaint and I want to steer clear of CreateGraphics. > >> > > >> > Are there any suggestions regarding a strategy of how I could call > >> > Invalidate(region) and only have that region redrawn ? > >> > > >> > > >> > Thanks > >> > > >> > Andrew. > >> > > >> > >> > >> > >
Hi Andrew, No doubt there are many approaches, but I would usually keep a bounds rectangle with each logical object and simply test it for visibility within the clip rectangle before drawing it. Windows clipping is fairly efficient so I would just leave it to deal with the finer details. You could, with some programming effort, subset your objects to the clip region (or rectangle) and just draw those bits but I doubt that you would be better off unless your objects are very large (*perhaps* it might be worth it for large bitmaps). You can keep the clip rectangle smaller by forcing repaints as you invalidate and invalidating as little as possible. The only issues that I can think of that really matter are flicker and user response time. Unless you actually have a problem with these its usually not worth spending too much effort on clipping. Cheers Doug Forster
Hi Doug and Bob, Having 'returned' from another section of my project, I have now had a better chance to digest the responses that have been provided on my original post. I now have a clearer understanding of how painting works, however my original question still remains ie just where does one place one's drawing code such that it does not get unncessarily called during the paint event handling operation ? I have placed my layer drawing routines in my TabPage derived OnPaint handler because that drawing code requires a Graphics object and without resorting to CreateGraphics() where else can I get a graphics object other than from the PaintEventArgs object of OnPaint ?? My application has five such TabPage derived classes which exist in a TabControl. Clicking on any TabPage draws that 'view' by calling specific drawlayer routines such as the one I originally described. Because OnPaint is called quite often (such as just after window creation, window resizing(not relevant here), window refocus; this was another reason for placing my drawlayer routines in OnPaint becasue it effectivley displays an initial number of graphical objects. When such initial detail is displayed, the stage is set on that view for users to alter the appearance, add delete to the initial content. And as the designer, I want the 'behind the scenes' drawing operation to be as efficient as possible. Take one such example where this initial view portrays a large rectangle with ruler lines and dimension numbers - that represent a plan view of the building outer. Now within this exist say half a dozen pairs of small rectangles that represent the structural supports of the building outer. A user selects one of these support rectangles which changes both their color (and that of their dimensions/rulers) from gray to blue ie the select color. The user can then reposition that support rectangle pair. Behind the scenes: A. for the object selecting operation, I invalidate two rectangles that represent the rectangle pair and its ruler/dimension situated above that pair. B. For the resizing code, after data validation, I invalidate the entire client area because many other support rectangles could also be moved. The problem is that with operation A. I believe that the clip region of PaintEventArgs contains both of my invalidated regions and hence I would only expect those parts of the view to be redrawn - however because my drawlayer code is situated in OnPaint (for the reasons mentioned above) the entire initial structure is redrawn. It looks fine however I only want the invalidated sections to be redrawn. I am now writing small graphical objects which will represent locks (that will act to lock the position of any selected support frame pair) and I certainly do not want to have to redraw the entire initial structure when the user simply clicks to change to graphical appearance of one of these lock objects. So considering all of the above, do you have any suggestions regarding how to handle the objectives of initial display and fine detail update ? Many thanks Andrew. [quoted text, click to view] "Doug Forster" wrote: > Hi Andrew, > > I could be wrong but I get the feeling you haven't fully understood what Bob > was saying. You shouldn't be attempting to use clipping at all to manipulate > the logical content of a window. The job of a paint handler is *just* to > paint part or all of a window with the correct content of the moment as > ascertained from state maintained external to the whole painting paradigm. > You should remember that Windows itself can invalidate any part of your > window at any time. This is not specific to .NET but is simply how Windows > has always worked. > > Cheers > Doug Forster > > "Andrew" <Andrew@discussions.microsoft.com> wrote in message > news:18697CA9-3687-425F-8458-1E9FA99BAC84@microsoft.com... > > Thanks, > > > > I will need to rethink my drawing strategy paying closer attention to the > > clipping region. > > > > > > "Bob Powell [MVP]" wrote: > > > >> Painting works like this: > >> > >> The system stores the results of invalidate calls internally. Invalidate > >> without parameters will mark a whole window for refreshing, invalidate > >> with > >> parameters will add regions to the list of "dirty" areas maintained by > >> the > >> system. > >> > >> When the queue is empty and there is nothing else to do, the system > >> checks > >> for dirty areas and issues a WM_PAINT message if any are found, otherwise > >> it > >> issues a WM_ENTERIDLE message to kick-off idle time processing. > >> > >> In all cases the result of the WM_PAINT message, for Windows Forms > >> programs, > >> is to run the OnPaint override which in turn kicks of the Paint event. > >> > >> The clipping region set in the OnPaint event arguments will be the sum of > >> all the regions or the whole window depending on whether Invalidate was > >> called without parameters. > >> > >> It's up to your code to either keep a list of its own dirty rectangles / > >> regions OR to do output based on the bounds of the clipping region > >> provided > >> by the paint event arguments. Whatever paint strategies you devise, such > >> as > >> only drawing partial content or layers, is entirely up to you and needs > >> to > >> be managed by you. The system doesn't care about reporting anything > >> except > >> that there is an area of screen marked as being in need of a refresh. > >> > >> -- > >> Bob Powell [MVP] > >> Visual C#, System.Drawing > >> > >> 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. > >> > >> > >> > >> > >> > >> "Andrew" <Andrew@discussions.microsoft.com> wrote in message > >> news:B82AC0B1-5BFF-4867-A7A6-B8E0DB074432@microsoft.com... > >> > Hello, > >> > > >> > In my application I perform all the drawing operations from within the > >> > form's > >> > OnPaint method (the form is ultimately a TabPage derivative) ie > >> > > >> > protected override void OnPaint(PaintEventArgs e) > >> > { > >> > base.OnPaint(e); > >> > //the base class LayerView.OnPaint handles things like > >> > AutoScrollPosition > >> > int s = 1; // temporary dummy scale value > >> > m_building.DrawBuildingLayer(g,s,this.Name); > >> > m_columns.DrawColumnsLayer(g,s,this.Name); > >> > } > >> > > >> > The drawing works well and smoothly handles operations such as > >> > scrolling. > >> > > >> > It is my understanding that when Invalidate() is called ie with no
Invalidation schemes that work well often take notice of the intersection of the clipping region with the objects drawn. It's neccesary to draw all of any object that impinges upon that region but the unused pixels are suppressed by the clipper. -- Bob Powell [MVP] Visual C#, System.Drawing 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] "Andrew" <Andrew@discussions.microsoft.com> wrote in message news:D69DBE21-D87B-4B7B-9672-4DAE630C90A8@microsoft.com... > Thanks Doug, > > As mentioned, my drawlayer code is situated in my OnPaint handler. > > With no attention paid to double buffering, I am getting what *appears* to > be good drawing performance regardless of whether my code is invalidating > the > entire screen or a rectangle. There is a slight flicker which I will fix > with > double buffering. > > When I invalidate a rectangle, YES it appears that only that rectangle is > being redrawn (due to a slight flicker only in that rectangle) however my > debug code indicates that every graphical object is indeed being executed > !!?? > > Of course this is the case due to the location of my drawing code - but > where else can it go. > > Can you explain this apparent contradiction, which seems to make a mockery > of the entire invalidation approach ? > > I have seen a simplistic example in the .NET notes where a rcDraw > rectangle > is generated in OnMouseDown/OnMouseUp handlers which is drawn in the > OnPaint > handler. In trying to relate this to my situation, I do not explicity draw > an > invalidated rectangle. Yes I am invalidating rectangles and Yes I assume > that > they are accumulating in the clipping region, but again, I do not actually > mention any such rectangles in the draw layer routines. > > I do have a bounds rectangle for each graphical object, however each > object > is stored in a SortedList derived class, the contents of which are being > sequentially called by the draw layer routines. > > It is curious that when I invalidate a region, whilst only the object in > that region appears to be drawn, the draw code for every object is > actually > being called, but produces absolutely no flicker (just as if it were not > being redrawn at all) ?? > > I am trying to achieve a situation where : When I invalidate a rectangle, > not only does it appear that only the contents of the rectangle is being > redrawn, ONLY the draw code for the objects in that rectangle is executed. > > Thanks > > Andrew > "Doug Forster" wrote: > >> Hi Andrew, >> >> No doubt there are many approaches, but I would usually keep a bounds >> rectangle with each logical object and simply test it for visibility >> within >> the clip rectangle before drawing it. Windows clipping is fairly >> efficient >> so I would just leave it to deal with the finer details. You could, with >> some programming effort, subset your objects to the clip region (or >> rectangle) and just draw those bits but I doubt that you would be better >> off >> unless your objects are very large (*perhaps* it might be worth it for >> large >> bitmaps). You can keep the clip rectangle smaller by forcing repaints as >> you >> invalidate and invalidating as little as possible. >> The only issues that I can think of that really matter are flicker and >> user >> response time. Unless you actually have a problem with these its usually >> not >> worth spending too much effort on clipping. >> >> Cheers >> Doug Forster >> >> >>
Thanks Doug, As mentioned, my drawlayer code is situated in my OnPaint handler. With no attention paid to double buffering, I am getting what *appears* to be good drawing performance regardless of whether my code is invalidating the entire screen or a rectangle. There is a slight flicker which I will fix with double buffering. When I invalidate a rectangle, YES it appears that only that rectangle is being redrawn (due to a slight flicker only in that rectangle) however my debug code indicates that every graphical object is indeed being executed !!?? Of course this is the case due to the location of my drawing code - but where else can it go. Can you explain this apparent contradiction, which seems to make a mockery of the entire invalidation approach ? I have seen a simplistic example in the .NET notes where a rcDraw rectangle is generated in OnMouseDown/OnMouseUp handlers which is drawn in the OnPaint handler. In trying to relate this to my situation, I do not explicity draw an invalidated rectangle. Yes I am invalidating rectangles and Yes I assume that they are accumulating in the clipping region, but again, I do not actually mention any such rectangles in the draw layer routines. I do have a bounds rectangle for each graphical object, however each object is stored in a SortedList derived class, the contents of which are being sequentially called by the draw layer routines. It is curious that when I invalidate a region, whilst only the object in that region appears to be drawn, the draw code for every object is actually being called, but produces absolutely no flicker (just as if it were not being redrawn at all) ?? I am trying to achieve a situation where : When I invalidate a rectangle, not only does it appear that only the contents of the rectangle is being redrawn, ONLY the draw code for the objects in that rectangle is executed. Thanks Andrew [quoted text, click to view] "Doug Forster" wrote: > Hi Andrew, > > No doubt there are many approaches, but I would usually keep a bounds > rectangle with each logical object and simply test it for visibility within > the clip rectangle before drawing it. Windows clipping is fairly efficient > so I would just leave it to deal with the finer details. You could, with > some programming effort, subset your objects to the clip region (or > rectangle) and just draw those bits but I doubt that you would be better off > unless your objects are very large (*perhaps* it might be worth it for large > bitmaps). You can keep the clip rectangle smaller by forcing repaints as you > invalidate and invalidating as little as possible. > The only issues that I can think of that really matter are flicker and user > response time. Unless you actually have a problem with these its usually not > worth spending too much effort on clipping. > > Cheers > Doug Forster > >
Hi Andrew, [quoted text, click to view] > As mentioned, my drawlayer code is situated in my OnPaint handler.
As it should be [quoted text, click to view] > When I invalidate a rectangle, YES it appears that only that rectangle is > being redrawn (due to a slight flicker only in that rectangle) however my > debug code indicates that every graphical object is indeed being executed > !!??
Yes, as I tried to say, you have to explicitly manage this yourself [quoted text, click to view] > Can you explain this apparent contradiction, which seems to make a mockery > of the entire invalidation approach ?
Its not a contradiction, it is simply how Windows works. I think your expectations are incorrect. [quoted text, click to view] > I do have a bounds rectangle for each graphical object, however each > object > is stored in a SortedList derived class, the contents of which are being > sequentially called by the draw layer routines.
So all you have to do is test for intersection with the clip rectangle and not draw the object if no intersection [quoted text, click to view] > It is curious that when I invalidate a region, whilst only the object in > that region appears to be drawn, the draw code for every object is > actually > being called, but produces absolutely no flicker (just as if it were not > being redrawn at all) ??
Again, this is how Windows clipping works. Although you execute the motions of drawing, Windows ensures only pixels in the invalid region are actually drawn. [quoted text, click to view] > I am trying to achieve a situation where : When I invalidate a rectangle, > not only does it appear that only the contents of the rectangle is being > redrawn, ONLY the draw code for the objects in that rectangle is executed.
Once again, YOU have to deal with this. There is no underlying magic (apart from clipping) that does it for you. Cheers Doug Forster
Thanks Bob, Yes, even as I was writing my posts, I was doubting the effectiveness of my drawing strategy. I am going to rethink my approach, reflecting upon the comments that have been provided (thanks). Due to the pressures of this project I have to get on and implement more of the graphics functionality. However as I proceed I will be scrutinising just how I go about drawing any items on the screen. I will let you know how things progress. Regards Andrew. Tamworth N.S.W, Australia. [quoted text, click to view] "Bob Powell [MVP]" wrote: > Invalidation schemes that work well often take notice of the intersection of > the clipping region with the objects drawn. > > It's neccesary to draw all of any object that impinges upon that region but > the unused pixels are suppressed by the clipper. > > > -- > Bob Powell [MVP] > Visual C#, System.Drawing > > 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. > > > > > > "Andrew" <Andrew@discussions.microsoft.com> wrote in message > news:D69DBE21-D87B-4B7B-9672-4DAE630C90A8@microsoft.com... > > Thanks Doug, > > > > As mentioned, my drawlayer code is situated in my OnPaint handler. > > > > With no attention paid to double buffering, I am getting what *appears* to > > be good drawing performance regardless of whether my code is invalidating > > the > > entire screen or a rectangle. There is a slight flicker which I will fix > > with > > double buffering. > > > > When I invalidate a rectangle, YES it appears that only that rectangle is > > being redrawn (due to a slight flicker only in that rectangle) however my > > debug code indicates that every graphical object is indeed being executed > > !!?? > > > > Of course this is the case due to the location of my drawing code - but > > where else can it go. > > > > Can you explain this apparent contradiction, which seems to make a mockery > > of the entire invalidation approach ? > > > > I have seen a simplistic example in the .NET notes where a rcDraw > > rectangle > > is generated in OnMouseDown/OnMouseUp handlers which is drawn in the > > OnPaint > > handler. In trying to relate this to my situation, I do not explicity draw > > an > > invalidated rectangle. Yes I am invalidating rectangles and Yes I assume > > that > > they are accumulating in the clipping region, but again, I do not actually > > mention any such rectangles in the draw layer routines. > > > > I do have a bounds rectangle for each graphical object, however each > > object > > is stored in a SortedList derived class, the contents of which are being > > sequentially called by the draw layer routines. > > > > It is curious that when I invalidate a region, whilst only the object in > > that region appears to be drawn, the draw code for every object is > > actually > > being called, but produces absolutely no flicker (just as if it were not > > being redrawn at all) ?? > > > > I am trying to achieve a situation where : When I invalidate a rectangle, > > not only does it appear that only the contents of the rectangle is being > > redrawn, ONLY the draw code for the objects in that rectangle is executed. > > > > Thanks > > > > Andrew > > "Doug Forster" wrote: > > > >> Hi Andrew, > >> > >> No doubt there are many approaches, but I would usually keep a bounds > >> rectangle with each logical object and simply test it for visibility > >> within > >> the clip rectangle before drawing it. Windows clipping is fairly > >> efficient > >> so I would just leave it to deal with the finer details. You could, with > >> some programming effort, subset your objects to the clip region (or > >> rectangle) and just draw those bits but I doubt that you would be better > >> off > >> unless your objects are very large (*perhaps* it might be worth it for > >> large > >> bitmaps). You can keep the clip rectangle smaller by forcing repaints as > >> you > >> invalidate and invalidating as little as possible. > >> The only issues that I can think of that really matter are flicker and > >> user > >> response time. Unless you actually have a problem with these its usually > >> not > >> worth spending too much effort on clipping. > >> > >> Cheers > >> Doug Forster > >> > >> > >> > >
Thanks Doug, A couple of days ago, after rethinking my drawing approach and reflecting on the comments that were provided, I devised an approach that exactly coincides with your last advise. I am in the middle of implementing the changes now and (as you and Bob have been implying) yes the concept of invalidating and drawing rectangles is quite straight forward. So far the required changes to my drawing code are minimal. I am soon to test the revised drawing strategy and will let you know how things go. Regards Andrew. [quoted text, click to view] "Doug Forster" wrote: > Hi Andrew, > > > As mentioned, my drawlayer code is situated in my OnPaint handler. > > As it should be > > > When I invalidate a rectangle, YES it appears that only that rectangle is > > being redrawn (due to a slight flicker only in that rectangle) however my > > debug code indicates that every graphical object is indeed being executed > > !!?? > > Yes, as I tried to say, you have to explicitly manage this yourself > > > Can you explain this apparent contradiction, which seems to make a mockery > > of the entire invalidation approach ? > > Its not a contradiction, it is simply how Windows works. I think your > expectations are incorrect. > > > I do have a bounds rectangle for each graphical object, however each > > object > > is stored in a SortedList derived class, the contents of which are being > > sequentially called by the draw layer routines. > > So all you have to do is test for intersection with the clip rectangle and > not draw the object if no intersection > > > It is curious that when I invalidate a region, whilst only the object in > > that region appears to be drawn, the draw code for every object is > > actually > > being called, but produces absolutely no flicker (just as if it were not > > being redrawn at all) ?? > > Again, this is how Windows clipping works. Although you execute the motions > of drawing, Windows ensures only pixels in the invalid region are actually > drawn. > > > I am trying to achieve a situation where : When I invalidate a rectangle, > > not only does it appear that only the contents of the rectangle is being > > redrawn, ONLY the draw code for the objects in that rectangle is executed. > > Once again, YOU have to deal with this. There is no underlying magic (apart > from clipping) that does it for you. > > Cheers > Doug Forster > >
Hi Bob and Doug, My drawing strategy is now working fine ! I am only drawing a graphical object if it lies within the PaintEvent's ClipRectangle. Yes I can see that even if accumulate several dirty rectangles via several calls to Invalidate(rectangle) - Windows handles the situation very efficiently by sending ONE WM_PAINT message. Only the draw code for the objects that exist within the Invalidated region(s) is executed. The drawing performance is great (and I am confident of correcting the slight flicker with double buffering). Thanks for your help. Regards Andrew. Australia. [quoted text, click to view] "Doug Forster" wrote: > Hi Andrew, > > > As mentioned, my drawlayer code is situated in my OnPaint handler. > > As it should be > > > When I invalidate a rectangle, YES it appears that only that rectangle is > > being redrawn (due to a slight flicker only in that rectangle) however my > > debug code indicates that every graphical object is indeed being executed > > !!?? > > Yes, as I tried to say, you have to explicitly manage this yourself > > > Can you explain this apparent contradiction, which seems to make a mockery > > of the entire invalidation approach ? > > Its not a contradiction, it is simply how Windows works. I think your > expectations are incorrect. > > > I do have a bounds rectangle for each graphical object, however each > > object > > is stored in a SortedList derived class, the contents of which are being > > sequentially called by the draw layer routines. > > So all you have to do is test for intersection with the clip rectangle and > not draw the object if no intersection > > > It is curious that when I invalidate a region, whilst only the object in > > that region appears to be drawn, the draw code for every object is > > actually > > being called, but produces absolutely no flicker (just as if it were not > > being redrawn at all) ?? > > Again, this is how Windows clipping works. Although you execute the motions > of drawing, Windows ensures only pixels in the invalid region are actually > drawn. > > > I am trying to achieve a situation where : When I invalidate a rectangle, > > not only does it appear that only the contents of the rectangle is being > > redrawn, ONLY the draw code for the objects in that rectangle is executed. > > Once again, YOU have to deal with this. There is no underlying magic (apart > from clipping) that does it for you. > > Cheers > Doug Forster > >
Don't see what you're looking for? Try a search.
|
|
|