Solved

Painting Dialogs on Long Operations

Posted on 2001-09-02
14
218 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
Comment Utility
> 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
Comment Utility
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
Comment Utility
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
 
LVL 4

Expert Comment

by:jtwine100697
Comment Utility
> 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
Comment Utility
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
Comment Utility
> [...] 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
Comment Utility
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
How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
"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
Comment Utility
>  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
Comment Utility
> 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
Comment Utility
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
Comment Utility
hehe Dan, sound cool!
0
 
LVL 4

Expert Comment

by:jtwine100697
Comment Utility
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
Comment Utility

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

What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Suggested Solutions

Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
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.
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

772 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now