Painting Dialogs on Long Operations

If I have a dialog as a main window with an Update button, clicking this button performs an update on a collection of files in a for loop. However, each file takes a couple seconds to update, during which time I can drag something like Calculator over my app and completely grey it out. After each update, I PeekMessage, and of course there are WM_PAINT messages, so the dialog restores itself. I tried "peeking" at strategic points during the updates (this file class is independent of the dialog class), but this didn't seem to help. Essentially, I'd like a dialog that would paint nicely during this long update operation with no flickering. What is the best way to do this? Would multithreading help? If anyone can point me to any examples on this, it would be greatly appreciated. TIA
davevAsked:
Who is Participating?
 
peterchen092700Connect With a Mentor Commented:
I agree w/ james, a worker thread would be the "perfect solution" here.

just to add a note: Peeking the message loop won't help to repaint, as Paint messages are generated only when there are not other messages waiting (except WM_TIMER).to fore an update, you have to call UpdateWindow().

There's an article about worker threads at
http://www.codeproject.com/threads/usingworkerthreads.asp
(I didn't read it, but Paul writes great articles - so I trust him ;)

Peter
0
 
jtwine100697Commented:
> What is the best way to do this? Would multithreading help?

Yep.  IMHO, this is a prime use for a "worker thread", which would be a thread created for the sole use of looping through the files that need to be updated.

The other benefit you gain is that if you need to provide some kind of [Cancel] button to stop the update, the button will respond quickly as well.  (Your worker thread would be checking an variable or a Win32 Event Object to see if it should stop looping through the files.)

-=- James.

0
 
DanRollinsCommented:
You need to do more than "peek" the message.  You need to take action on it!  Make this fn:

void PumpAllMsgs() {
   MSG rMsg;
   while (::PeekMessage(&rMsg,0,0,0,PM_NOREMOVE)){
       AfxGetApp()->PumpMessage();
   }
}

And insert calls to PumpAllMsgs() it at appropiate places (eg, while in the loop that reads a file).  Your app will respond to ui actions such as the user dragging the window it will be repainted as neeeded.  Take care with command message handlers, tho...  

Note that unless you disable some buttons, their associated commands will get executed.  For isntance, if this whole process started with a click of the [Do It] button, then you need to disable that button to keep the user from clicking it again!
=-=-=-=-=-=-=-=-=-=-=-=-=-
One general tip:
Avoid multithreading and its hidden headaches -- whenever possible.

-- Dan
0
Introducing Cloud Class® training courses

Tech changes fast. You can learn faster. That’s why we’re bringing professional training courses to Experts Exchange. With a subscription, you can access all the Cloud Class® courses to expand your education, prep for certifications, and get top-notch instructions.

 
jtwine100697Commented:
> void PumpAllMsgs() [...]

The problem with this solution, besides being considered "old hat" by some (we are not in Win16 anymore), is that this method occasionally requires "tweaking" ("where should I paste the call to this function?") to get the application's response times just right, depending on the target hardware.

> Avoid multithreading and its hidden headaches -- whenever possible.

Just as an aside, what "hidden headaches" are you referring to?  Hopefully not about MFC and multithreading, because using MFC across threads just requires an understanding of how MFC works.  IME, just about any experienced developer can handle multithreading.

-=- James.
0
 
peterchen092700Commented:
Multithreading has hidden headaches - you need to understand the concept, how to sychronize correctly, and the API for this.

However,it's the best solution for this problem. And not too hard to do.

Peter
0
 
jtwine100697Commented:
> [...] you need to understand the concept, how to sychronize correctly, and the API for this.

Right.  As I said above:

> > IME, just about any experienced developer can handle multithreading.

Note that "experienced" may mean different things to different people! :)

-=- James.
0
 
davevAuthor Commented:
Thanks for pointing me to codeproject.com. I'm pretty sure the article will help me out as I am familiar with threading and there's lots of other good stuff there too. :) I had tried the strategic placement of PumpMessage, but it didn't do very much in helping with WM_PAINT messages, as was pointed out. Thanks again.
0
 
DanRollinsCommented:
"Hidden headaches" include:
*) Add an ActiveX control to a dialog and your program crashes.
*) Spend two weeks tracking down why your program is locking up.
*) ODBC Errors: "HSTMT is already in use"
*) Call a public member fn of a CWnd-derived class and the program ASSERTs.
*) Your perfectly-functioning socket code stops working when you add another worker thread.
*) Your cash-cow production code, proven stable and robust on over 30,000 sites turns to dog crap overnight.  You spend two months taking heat from the boss and tech support while you back off all of the multi-threading "enhancements" made by some gungho idealist.

Other than that, I can't think of anything...

-- Dan
0
 
jtwine100697Commented:
>  Add an ActiveX control to a dialog and your program crashes.

COM not initialized on the other threads correctly, or the ActiveX control not being "free" threaded, and the program incorrectly allowing other threads, besides the creation thread, to access the control...?  (Seen this happen before.)

> Spend two weeks tracking down why your program is locking up
> Your perfectly-functioning socket code stops working when you add another worker thread.
> Your cash-cow production code, proven stable and robust on over 30,000 sites turns to dog crap overnight.

The code was *not* written correctly, with regard to multithreading.  Single-threaded code (read: not written with MT in mind) should *never* just be "wrapped" by or "just used by" a thread.  To do so and expect it to work is crazy: the code has to be written correctly in the first place.

> ODBC Errors: "HSTMT is already in use"

Nothing off the top of my head.  Never seen anyone screw-up ODBC in an MT app before.

> Call a public member fn of a CWnd-derived class and the program ASSERTs.

Lack of understanding about how to use MFC across threads.

> You spend two months taking heat from the boss and tech support while you back off all of the multi-threading
> "enhancements" made by some gungho idealist.

Then that "idealist" did not know what the hell (s)he was doing, plain and simple; and you got bitten by that fact.  Multithreading was not bad, its misuse/misunderstanding was.

[ObOT]
> had tried the strategic placement of PumpMessage, but it didn't do very much in helping with WM_PAINT messages

Back to the worker thread idea? :/

-=- James.
0
 
davevAuthor Commented:
> Back to the worker thread idea? :/

Yes, I'm going to give it a try. I'll be back for your expertise if something goes wrong. :) It's nice to have people on here who know a thing or two about programming and who are willing to share than knowledge unselfishly. I'd like to give points to everyone who has helped!
0
 
DanRollinsCommented:
On the other hand... Once you know how to avoid the potholes, a multithreaded app is slickernsnot.  

In a limited beta test with a major information broker --really a sort of showdown between my company and our three main competitors-- our software ran six simultaneous HTTPS sessions while they tried to compete with single-threaded apps.

It was kinda pitiful.  :-)

-- Dan
0
 
peterchen092700Commented:
hehe Dan, sound cool!
0
 
jtwine100697Commented:
There 'ya go! :)  Hehe...

--------------------

davev, IMHO, the easiest way to maintain a status indicator is to have the thread update a variable that contains the percentage of the work complete, and your UI thread can use that value to update a progress indicator (only update it if the value changes, to reduce flicker).  

Yes, there is the chance that your UI and worker threads may be trying to access the variable at the same time, but that should not be a problem here, as it is only used for updating a status value.  It would be a problem for something like two worker threads updating a "files copied" value, where you would want to use something like InterlockedIncrement(...), or a Critical Section.

Your worker thread should also be checking for a "stop" Event to be signaled as part of its work-loop.  That will allow your UI thread to use SetEvent(...) to signal the event, and the thread will pick up on that, and can abort it's work, and die off.

-=- James.
0
 
acheiveCommented:

Hello all

I have somewhat a similar kind of problem. i was thinking just on a hunch that threads would solve my problem. I am complete illiterate in threads, infact i just started to read about them. I havn't got much time with me to solve this problem on my own. Please view my question at

http://www.experts-exchange.com/jsp/qManageQuestion.jsp?ta=mfc&qid=20284347

Any suggestion/help is greatly appreciated.

Thanks
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.