Solved

Painting Dialogs on Long Operations

Posted on 2001-09-02
14
240 Views
Last Modified: 2013-11-20
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
0
Comment
Question by:davev
  • 5
  • 3
  • 3
  • +2
14 Comments
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6449741
> 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
 
LVL 7

Accepted Solution

by:
peterchen092700 earned 100 total points
ID: 6450005
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
 
LVL 49

Expert Comment

by:DanRollins
ID: 6452298
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
Migrating Your Company's PCs

To keep pace with competitors, businesses must keep employees productive, and that means providing them with the latest technology. This document provides the tips and tricks you need to help you migrate an outdated PC fleet to new desktops, laptops, and tablets.

 
LVL 4

Expert Comment

by:jtwine100697
ID: 6452999
> 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
 
LVL 7

Expert Comment

by:peterchen092700
ID: 6453420
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
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6453485
> [...] 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
 

Author Comment

by:davev
ID: 6454379
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
 
LVL 49

Expert Comment

by:DanRollins
ID: 6454480
"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
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6455029
>  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
 

Author Comment

by:davev
ID: 6455060
> 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
 
LVL 49

Expert Comment

by:DanRollins
ID: 6456129
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
 
LVL 7

Expert Comment

by:peterchen092700
ID: 6456830
hehe Dan, sound cool!
0
 
LVL 4

Expert Comment

by:jtwine100697
ID: 6456966
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
 

Expert Comment

by:acheive
ID: 6915010

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

Featured Post

ScreenConnect 6.0 Free Trial

Explore all the enhancements in one game-changing release, ScreenConnect 6.0, based on partner feedback. New features include a redesigned UI, app configurations and chat acknowledgement to improve customer engagement!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
iSeries DB2 Query 2 95
Unix Command -- Challenging  question 7 90
Change to event 1 112
Problem to App source 6 40
Introduction: Finishing the grid – keyboard support for arrow keys to manoeuvre, entering the numbers.  The PreTranslateMessage function is to be used to intercept and respond to keyboard events. Continuing from the fourth article about sudoku. …
Introduction: Database storage, where is the exe actually on the disc? Playing a game selected randomly (how to generate random numbers).  Error trapping with try..catch to help the code run even if something goes wrong. Continuing from the seve…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
Along with being a a promotional video for my three-day Annielytics Dashboard Seminor, this Micro Tutorial is an intro to Google Analytics API data.

809 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question