How to unload a form while its still busy with Form_Paint
Author |
Message |
Pete #1 / 25
|
 How to unload a form while its still busy with Form_Paint
Dear all In the Form_Paint event I am drawing alot on the form and the whole Paint Event can sometimes take upto several minutes. Usually that is OK but in case the user does not want to wait for a new drawing I want to offer him the possibility to close the form via the X in the control box. Now I have seen that pressing the X has no effect in case the Sub Form_Paint is still running? How can I detect that the user has pressed the X to interupt Form_Paint and close the form? Unload and QueryUnload did not fire when Form_Paint was busy. Regards Peter
|
Sat, 18 Jun 2011 04:53:21 GMT |
|
 |
Pete #2 / 25
|
 How to unload a form while its still busy with Form_Paint
I just like to add that I use DoEvents in Form_Paint and minimizing and maximizing the Form via the control box works fine during Form_Paint. Just closing the form via X does not work. Regards Peter "Peter" <-> schrieb im Newsbeitrag
Quote: > Dear all > In the Form_Paint event I am drawing alot on the form and the whole Paint > Event can sometimes take upto several minutes. Usually that is OK but in > case the user does not want to wait for a new drawing I want to offer him > the possibility to close the form via the X in the control box. > Now I have seen that pressing the X has no effect in case the Sub > Form_Paint is still running? > How can I detect that the user has pressed the X to interupt Form_Paint > and close the form? > Unload and QueryUnload did not fire when Form_Paint was busy. > Regards > Peter
|
Sat, 18 Jun 2011 04:59:50 GMT |
|
 |
Larry Serflate #3 / 25
|
 How to unload a form while its still busy with Form_Paint
"Peter" <-> wrote Quote: > In the Form_Paint event I am drawing alot on the form and the whole Paint > Event can sometimes take upto several minutes.
Zoinks Scub! That's like way too much information! Quote: > Usually that is OK
Really? Is there no way to cache some of that between Paints? Quote: > but in case the user does not want to wait for a new drawing I want to offer him > the possibility to close the form via the X in the control box. > Now I have seen that pressing the X has no effect in case the Sub Form_Paint > is still running?
Interesting.... I had not noticed that before, but it appears you are correct! Quote: > How can I detect that the user has pressed the X to interupt Form_Paint and > close the form? > Unload and QueryUnload did not fire when Form_Paint was busy.
Others may have a different solution, but one way to catch that would be to add a timer to your form with an interval of 1. Then do your painting in the Timer event. In the Paint event, all you do is enable the timer. Then somewhere in your painting code add this where it will get called somewhere around 2 per second: DoEvents If Me.Visible = False Then Exit Sub Using a DoEvents in the Timer event will allow the X button to hide the form. When it is hid, the visible property is false so the next statement exits out of the Timer code, allowing the form to be unloaded. EX: Private Sub Form_Paint() Timer1.Enabled = True End Sub Private Sub Timer1_Timer() Timer1.Enabled = False For idx = 1 To ObjectsToPaint.Count ' ... code to paint object idx ' Occasional X Button test If (idx Mod 20) = 0 Then DoEvents If Me.Visible = False Then Exit Sub End If Next End Sub HTH LFS
|
Sat, 18 Jun 2011 05:20:24 GMT |
|
 |
Jeff Johnso #4 / 25
|
 How to unload a form while its still busy with Form_Paint
Quote:
> In the Form_Paint event I am drawing alot on the form and the whole Paint > Event can sometimes take upto several minutes. Usually that is OK
That is NEVER okay. Quote: > but in case the user does not want to wait for a new drawing I want to > offer him the possibility to close the form via the X in the control box. > Now I have seen that pressing the X has no effect in case the Sub > Form_Paint is still running? > How can I detect that the user has pressed the X to interupt Form_Paint > and close the form? > Unload and QueryUnload did not fire when Form_Paint was busy.
The Paint event, as you have seen, is "special" as far as Windows events go, and it should do its work as quickly as possible. I highly recommend you adopt a new strategy. Why not use a background process similar to what Larry talked about and draw to an in-memory bitmap? Then, when it's done, you invalidate the form (call Refresh) and the only thing your Paint handler has to do is draw this bitmap to the form. While you're in a re-calculation scenario, you could either blank out the existing image on the form or, if the user might want to review the current image while the new one is drawing, you could put a message on a status bar or in a modeless dialog indicating that you're currently composing the new image. I'm really curious: what does this app do that it takes so long to paint?
|
Sat, 18 Jun 2011 06:01:38 GMT |
|
 |
Mike William #5 / 25
|
 How to unload a form while its still busy with Form_Paint
Quote:
> I just like to add that I use DoEvents in Form_Paint and > minimizing and maximizing the Form via the control box > works fine during Form_Paint. Just closing the form via > X does not work.
A Form will not unload while it is running code in its Paint or Resize event. As Larry and Jeff have said there are ways around this problem, but I wonder whether your drawing code really should take as long as several minutes? What is it exactly you are drawing. Also, if you have drawing code in the Paint event then that drawing will be done repeatedly as the user moves the Form partially on and off the edges of the display or as he expands its size, which will take a lot of processor time if the drawing takes as long as you have said. Do you really need to perform such a lengthy drawing task repeatedly under these conditions when you could simply set Autoredraw to True and draw it just once to achieve persistence. Or are you doing it for some other reason? Also, are you sure that your drawing code cannot be made to run any faster? Several minutes seems a very long time to me unless you are doing something extremely complex. Mike
|
Sat, 18 Jun 2011 06:26:40 GMT |
|
 |
Pete #6 / 25
|
 How to unload a form while its still busy with Form_Paint
Many Thanks Larry and Jeff I put the code of Sub Form_Paint into a timer as Larry suggested and this seems to work fine now! about to draw to an in-memory bitmap? Jeff, can you please explain me how I can do this? Currently, my Form_Paint has a lot of Paintpicture, Line and Print(with CurrentX,CurrentY) instructions. Can I just add a picturebox to my form, make it invisible and use my Paintpicture,Line,Print Methods to draw onto the picturebox instead of the form? And when finished just make the picture visible? Regards Peter
Quote:
>> In the Form_Paint event I am drawing alot on the form and the whole Paint >> Event can sometimes take upto several minutes. Usually that is OK > That is NEVER okay. >> but in case the user does not want to wait for a new drawing I want to >> offer him the possibility to close the form via the X in the control box. >> Now I have seen that pressing the X has no effect in case the Sub >> Form_Paint is still running? >> How can I detect that the user has pressed the X to interupt Form_Paint >> and close the form? >> Unload and QueryUnload did not fire when Form_Paint was busy. > The Paint event, as you have seen, is "special" as far as Windows events > go, and it should do its work as quickly as possible. I highly recommend > you adopt a new strategy. Why not use a background process similar to what > Larry talked about and draw to an in-memory bitmap? Then, when it's done, > you invalidate the form (call Refresh) and the only thing your Paint > handler has to do is draw this bitmap to the form. While you're in a > re-calculation scenario, you could either blank out the existing image on > the form or, if the user might want to review the current image while the > new one is drawing, you could put a message on a status bar or in a > modeless dialog indicating that you're currently composing the new image. > I'm really curious: what does this app do that it takes so long to paint?
|
Sat, 18 Jun 2011 06:42:48 GMT |
|
 |
Jeff Johnso #7 / 25
|
 How to unload a form while its still busy with Form_Paint
Quote:
> Many Thanks Larry and Jeff > I put the code of Sub Form_Paint into a timer as Larry suggested and this > seems to work fine now! > about to draw to an in-memory bitmap? > Jeff, can you please explain me how I can do this? > Currently, my Form_Paint has a lot of Paintpicture, Line and Print(with > CurrentX,CurrentY) instructions. > Can I just add a picturebox to my form, make it invisible and use my > Paintpicture,Line,Print Methods to draw onto the picturebox instead of the > form? And when finished just make the picture visible?
That should work as well. Since you were doing such heavy graphics work, I thought you might be using API functions to draw directly with GDI, so I figured you'd know what I meant by drawing to an in-memory bitmap. Since that's not the case, and things are working for you now, you don't need to worry about it, as it's far more complex than what you're currently doing. You might want to look into it for any future graphics-intensive work you plan to do, though.
|
Sat, 18 Jun 2011 06:54:35 GMT |
|
 |
Mike #8 / 25
|
 How to unload a form while its still busy with Form_Paint
Quote:
>> In the Form_Paint event I am drawing alot on the form and the whole Paint >> Event can sometimes take upto several minutes. Usually that is OK > That is NEVER okay.
In general, I would tend to agree, but we don't know what he's drawing or the nature of the app or anything else. Bottom line is if USERS are OK with it. -- Mike
|
Sat, 18 Jun 2011 10:03:34 GMT |
|
 |
Mike William #9 / 25
|
 How to unload a form while its still busy with Form_Paint
Quote:
> Can I just add a picturebox to my form, make it invisible and > use my Paintpicture,Line,Print Methods to draw onto the > picturebox instead of the form? And when finished just make > the picture visible?
Yes, as long as you set the picture box's Autoredraw property to True. It would be better to create your own memory bitmap in code though and draw into it using the GDI drawing methods. But personally I would first look at the time taken by your calculation and drawing code to see if you can speed it up as it stands. I do realise that some tasks can take a number of minutes or even longer, even when optimised, especially if you are doing something complex like filtering noise from a waveform or something, but there are usually ways to speed things up. For example, are you by any chance drawing more lines or points on the display than is necessary (drawing every twip for example when every pixel is the smallest unit you actually need to draw)? Or are you using any relatively slow methods or functions in your code, such as using x = y ^ 2 when x = y * y is up to twenty times faster. Mike Quote: > Regards > Peter
>>> In the Form_Paint event I am drawing alot on the form and the whole >>> Paint Event can sometimes take upto several minutes. Usually that is OK >> That is NEVER okay. >>> but in case the user does not want to wait for a new drawing I want to >>> offer him the possibility to close the form via the X in the control >>> box. >>> Now I have seen that pressing the X has no effect in case the Sub >>> Form_Paint is still running? >>> How can I detect that the user has pressed the X to interupt Form_Paint >>> and close the form? >>> Unload and QueryUnload did not fire when Form_Paint was busy. >> The Paint event, as you have seen, is "special" as far as Windows events >> go, and it should do its work as quickly as possible. I highly recommend >> you adopt a new strategy. Why not use a background process similar to >> what Larry talked about and draw to an in-memory bitmap? Then, when it's >> done, you invalidate the form (call Refresh) and the only thing your >> Paint handler has to do is draw this bitmap to the form. While you're in >> a re-calculation scenario, you could either blank out the existing image >> on the form or, if the user might want to review the current image while >> the new one is drawing, you could put a message on a status bar or in a >> modeless dialog indicating that you're currently composing the new image. >> I'm really curious: what does this app do that it takes so long to paint?
|
Sat, 18 Jun 2011 13:48:22 GMT |
|
 |
Pete #10 / 25
|
 How to unload a form while its still busy with Form_Paint
Many Thanks for all your answers. Regarding my application and why it needs so much time with its Sub Form_Paint: I have written a kind of thumbnail browser, that shows pictures of digital cameras as thumbnails on the screen. Main requirement is to have thumbnails upto a size of 400X300 and to support (almost) unlimited number of pictures(in practice these can be 5000-8000 pictures). Thanks to Larry's post I took his concept loading each picture "on the fly" with the code below: Private Sub Form_Paint() Dim idx As Long, Y As Long Dim pic As StdPicture idx = TopIndex Do While Y < ScaleHeight Set pic = LoadPicture(File1.Path & "\" & File1.List(idx)) PaintPicture pic, 0, Y, 400, 300 Y = Y + 301 idx = idx + 1 If idx = File1.ListCount Then ' paint rest of form white Line (0, Y)-Step(400, ScaleHeight), vbWhite, BF Exit Sub End If Loop End Sub Of course, I modified that code to have correct aspect ratio and multiple colums but I still use the same concept to load the (visible) pictures in Form_Paint. On a 1024X768 screen you can nicely see 4 thumbnails each 400X300. Depending on the size of the original pictures function FormLoad() usually takes about 500ms per pic. With some overhead I typically reach a total time of 2300ms, that is when Form_Paint loads 4 Thumbnails each 400X300. On the other hand my app also allows the user to downsize the thumbnails to 40X30. Then typically 117 thumbnails(13horX9vert) can be displayed on the screen. This leads to a total time of about 61s until all thumbnails are created. Ok, "several minutes" was not exactly correct but if you sit in front of the screen and wait for all 117 thumbnails that it "feels like" 3 or 5 minutes. Thanks to your answers I began to analyze the time that is spent beside function LoadPicture() since I can't speedup LoadPicture() any more, can I?. I have another function that shrinks the pictures to the thumbnail size and maintains their aspect ratio. This function uses StrechBlt for shrinking and returns a StdPicture back. At the beginning I used HALFTONE as the StretchBltMode which increased the total time to about 72s. Now I use COLORONCOLOR, I measure the time using t=GetTickCount() and Debug.Print GetTickCount-t I always get value 0 returned(which leads to the total time of 61s). Then I made a comparisson with Irfanview freeware software, It is a lot faster but still take some time(about 12 seconds) to fill up the screen with144 thumbnails each 50X50. Because I used the same pictures I assume that it uses a much faster function to load the pictures into memory. So the main question is: Is there a way to speed up function LoadPicture() ? What about LoadImage() API function? Does anybody know whether it will be faster than LoadPicture()? Regards Peter "Peter" <-> schrieb im Newsbeitrag
Quote: > Many Thanks Larry and Jeff > I put the code of Sub Form_Paint into a timer as Larry suggested and this > seems to work fine now! > about to draw to an in-memory bitmap? > Jeff, can you please explain me how I can do this? > Currently, my Form_Paint has a lot of Paintpicture, Line and Print(with > CurrentX,CurrentY) instructions. > Can I just add a picturebox to my form, make it invisible and use my > Paintpicture,Line,Print Methods to draw onto the picturebox instead of the > form? And when finished just make the picture visible? > Regards > Peter
>>> In the Form_Paint event I am drawing alot on the form and the whole >>> Paint Event can sometimes take upto several minutes. Usually that is OK >> That is NEVER okay. >>> but in case the user does not want to wait for a new drawing I want to >>> offer him the possibility to close the form via the X in the control >>> box. >>> Now I have seen that pressing the X has no effect in case the Sub >>> Form_Paint is still running? >>> How can I detect that the user has pressed the X to interupt Form_Paint >>> and close the form? >>> Unload and QueryUnload did not fire when Form_Paint was busy. >> The Paint event, as you have seen, is "special" as far as Windows events >> go, and it should do its work as quickly as possible. I highly recommend >> you adopt a new strategy. Why not use a background process similar to >> what Larry talked about and draw to an in-memory bitmap? Then, when it's >> done, you invalidate the form (call Refresh) and the only thing your >> Paint handler has to do is draw this bitmap to the form. While you're in >> a re-calculation scenario, you could either blank out the existing image >> on the form or, if the user might want to review the current image while >> the new one is drawing, you could put a message on a status bar or in a >> modeless dialog indicating that you're currently composing the new image. >> I'm really curious: what does this app do that it takes so long to paint?
|
Sun, 19 Jun 2011 04:51:46 GMT |
|
 |
Mike William #11 / 25
|
 How to unload a form while its still busy with Form_Paint
Quote:
> Depending on the size of the original pictures function > FormLoad() usually takes about 500ms per pic.
That seems quite a lot of time, but then you might be using a fairly slow machine. On my system it takes about 100 milliseconds to load a typical 1600 x 1200 pixel jpg using the same method you are using. Most of the time (in both cases) is spent analyzing the jpg and decoding it. A similar bmp file would typically load very quickly by comparison, even though the file size of the bmp is much larger than the jpg. Quote: > Thanks to your answers I began to analyze the time > that is spent beside function LoadPicture() since I > can't speedup LoadPicture() any more, can I?.
Yes, you can. Well, you can't actually speed up the VB LoadPicture method, but you can speed up the loading and decoding of the jpg by using a different method instead. Quote: > What about LoadImage() API function? Does anybody > know whether it will be faster than LoadPicture()?
You cannot use the LoadImage API function to load a jpg. LoadImage is for loading bitmaps. However, you can use something different. GDI+ is capable of loading jpegs, and it probably does it quite quickly, but I've never used that method myself and so I don't know how quick it would be. There is some code on VBAccelerator that shows you how to use GDI+ for this task. Check out: http://vbaccelerator.com/home/VB/Code/vbMedia/Using_GDI_Plus/Reading_... There is also an Intel DLL that is capable of performing all sorts of tasks with jpgs, including loading them of course, and it loads and decodes them quite quickly, about four times faster than the VB LoadPicture method you are currently using. This reduces the loading and decoding time on my machine from just over 100 milliseconds to about 25 milliseconds, so it should reduce your loading and conversion time from your current 500 milliseconds (on your fairly slow machine) down to about 120 milliseconds, which should get your overall time to load the jpeg and draw the thumbnail to something approaching the speed you are getting out of the IrfanView software. Check out the example at: http://www.vbaccelerator.com/home/VB/Code/vbMedia/Saving_Pictures_to_... The code at the above link loads the jpg into a DIBSection, and you can draw the DIBSection to your Form or PictureBox at whatever thumbnail size you require using StretchBlt. Mike
|
Sun, 19 Jun 2011 06:07:33 GMT |
|
 |
Larry Serflate #12 / 25
|
 How to unload a form while its still busy with Form_Paint
"Peter" <-> wrote Quote: > I have another function that shrinks the pictures to the thumbnail size and > maintains their aspect ratio. This function uses StrechBlt for shrinking and > returns a StdPicture back. <...> > Then I made a comparisson with Irfanview freeware software, It is a lot > faster but still take some time(about 12 seconds) to fill up the screen > with144 thumbnails each 50X50. Because I used the same pictures I assume > that it uses a much faster function to load the pictures into memory. > So the main question is:
What was the purpose of using a separate procedure to shrink your pictures? Could you not just use the PaintPicture method which has parameters for resizing the image as it is being painted? For example, in a new form: Private Sub Form_Load() AutoRedraw = True ScaleMode = vbPixels PaintPicture Icon, 0, 0, 31, 31 PaintPicture Icon, 140, 0, 120, 120 PaintPicture Icon, 0, 40, 320, 320 End Sub I was thinking that to shrink a loaded picture, you'd have to copy the entire picture to the new size, and then copy that new image to the screen. If you could paint the picture at the new size all in one operation, that would eliminate one of the (relatively) expensive copies.... ??? LFS
|
Sun, 19 Jun 2011 06:38:26 GMT |
|
 |
Pete #13 / 25
|
 How to unload a form while its still busy with Form_Paint
Thanks again for your answers, Mike. Very helpful! About the loading time: I have a P4 3GHz PC with 2GB RAM, but the files I load are typically files from a 6Megapixel camera(2848X2136). If you like you can download such a jpg from here: https://festplatte.aon.at/a/filemanager.get/2610036/Lainer3.jpg Would be nice if you could tell me how log Loadpicture() will take on your machine with that file. Converting all jpgs to bmps before starting my app would not be an option because I would not have that much diskspace available(5000-8000 files). About GDI+: I already use some GDI plus code in this app to rotate the jpgs. I use GdipCreateBitmapFromFile() to load the jpg before rotating it. I do not have any experiences with GDI+, I already found a sample code on the internet. That sample code includes a wrapperfunction LoadPicturePlus() which seems to be the GDI+ alternative to LoadPicture(). However, in my tests LoadPicturePlus() was almost as slow as LoadPicture(). About the Intel DLL: That sounds good although in general I do not like to have external dlls. I will check it out soon. On your link they mention a speed difference of 2:1 but lets see... Kind Regards Peter
Quote:
>> Depending on the size of the original pictures function >> FormLoad() usually takes about 500ms per pic. > That seems quite a lot of time, but then you might be using a fairly slow > machine. On my system it takes about 100 milliseconds to load a typical > 1600 x 1200 pixel jpg using the same method you are using. Most of the > time (in both cases) is spent analyzing the jpg and decoding it. A similar > bmp file would typically load very quickly by comparison, even though the > file size of the bmp is much larger than the jpg. >> Thanks to your answers I began to analyze the time >> that is spent beside function LoadPicture() since I >> can't speedup LoadPicture() any more, can I?. > Yes, you can. Well, you can't actually speed up the VB LoadPicture method, > but you can speed up the loading and decoding of the jpg by using a > different method instead. >> What about LoadImage() API function? Does anybody >> know whether it will be faster than LoadPicture()? > You cannot use the LoadImage API function to load a jpg. LoadImage is for > loading bitmaps. However, you can use something different. GDI+ is capable > of loading jpegs, and it probably does it quite quickly, but I've never > used that method myself and so I don't know how quick it would be. There > is some code on VBAccelerator that shows you how to use GDI+ for this > task. Check out: > http://vbaccelerator.com/home/VB/Code/vbMedia/Using_GDI_Plus/Reading_... > There is also an Intel DLL that is capable of performing all sorts of > tasks with jpgs, including loading them of course, and it loads and > decodes them quite quickly, about four times faster than the VB > LoadPicture method you are currently using. This reduces the loading and > decoding time on my machine from just over 100 milliseconds to about 25 > milliseconds, so it should reduce your loading and conversion time from > your current 500 milliseconds (on your fairly slow machine) down to about > 120 milliseconds, which should get your overall time to load the jpeg and > draw the thumbnail to something approaching the speed you are getting out > of the IrfanView software. Check out the example at: > http://www.vbaccelerator.com/home/VB/Code/vbMedia/Saving_Pictures_to_... > The code at the above link loads the jpg into a DIBSection, and you can > draw the DIBSection to your Form or PictureBox at whatever thumbnail size > you require using StretchBlt. > Mike
|
Sun, 19 Jun 2011 07:35:02 GMT |
|
 |
Pete #14 / 25
|
 How to unload a form while its still busy with Form_Paint
Thanks for your answer, Larry. At the beginning I also thought that this additional Stretch Function would increase the overall time dramatically but as written in my last post, for tiny 40X30 thumbnail and StretchBltMode=COLORONCOLOR my time measurement(GetTickCount()-t) shows 0 so it doesn't seem to have any affect on the high loading time. The reason why I don't just use PaintPicture is because my Stretch function maintains the aspect ratio and fills the remaining areas(to fit onto a 40x30 picture) with a certain background color. While I have written this answers, I made a test by just omitting my stretch function and directly PaintPicture the loaded pictures. I could not measure any speed increase. So main reason seems to be the slow LoadPicture() function, Mike suggested an external Intel dll, perhaps this could be a solution for me. Regards Peter
Quote: > "Peter" <-> wrote >> I have another function that shrinks the pictures to the thumbnail size >> and >> maintains their aspect ratio. This function uses StrechBlt for shrinking >> and >> returns a StdPicture back. > <...> >> Then I made a comparisson with Irfanview freeware software, It is a lot >> faster but still take some time(about 12 seconds) to fill up the screen >> with144 thumbnails each 50X50. Because I used the same pictures I assume >> that it uses a much faster function to load the pictures into memory. >> So the main question is: > What was the purpose of using a separate procedure to shrink your > pictures? Could you not just use the PaintPicture method which has > parameters for resizing the image as it is being painted? > For example, in a new form: > Private Sub Form_Load() > AutoRedraw = True > ScaleMode = vbPixels > PaintPicture Icon, 0, 0, 31, 31 > PaintPicture Icon, 140, 0, 120, 120 > PaintPicture Icon, 0, 40, 320, 320 > End Sub > I was thinking that to shrink a loaded picture, you'd have to copy > the entire picture to the new size, and then copy that new image to > the screen. If you could paint the picture at the new size all in one > operation, that would eliminate one of the (relatively) expensive > copies.... > ??? > LFS
|
Sun, 19 Jun 2011 07:55:32 GMT |
|
 |
Michael #15 / 25
|
 How to unload a form while its still busy with Form_Paint
Quote:
> Many Thanks for all your answers. > Regarding my application and why it needs so much time with its Sub > Form_Paint: > I have written a kind of thumbnail browser, that shows pictures of digital > cameras as thumbnails on the screen.
Any app that does this will store thumbnails in a seperate file. Windows Explorer stores them in thumbs.db and paint shop pro stores the in pspbrwse.jbf. My application stores them in sqlserver. Michael
|
Sun, 19 Jun 2011 07:56:16 GMT |
|
|
Page 1 of 2
|
[ 25 post ] |
|
Go to page:
[1]
[2] |
|