Re: How to display messages to the user during long processes!!
 
On Sep 24, 10:16 pm, Joseph M. Newcomer <newco...@flounder.com> wrote:
See below...
On Wed, 24 Sep 2008 08:58:58 -0700 (PDT), ragh...@gmail.com wrote:
On Sep 24, 7:42 am, Joseph M. Newcomer <newco...@flounder.com> wrote:
That's why I hook the node-builder event. It allows me to show actual =
progress. In my
PowerPoint indexer I am able to determine the total number of slides a=
nd that makes it
pretty easy, but at each #include I add a new progress bar and let it =
run. This is much
better than having a single progress bar whose contents you can never =
interpret, as it
makes N passes but you have no idea what 'progress' it is really showi=
ng.
I added the XML progress bar even though it takes under a minute to re=
ad and parse the
file because the customer really wanted a visble progress bar for any =
operation that took
longer than a few seconds (5 seconds was the nominal acceptable delay =
time without a
progress bar). In the library I use, the node-hook is called each time=
 a node is started,
and when you call the reader, you give it an LPVOID userData type of p=
arameter. So I just
packaged the CFile* into the structure I passed in, which let me get t=
he file position
each time a node is built. A small data file can have perhaps 10,000 n=
odes, a large one
perhaps 250,000. In practice, we seemed to hover around 25,000-40,000 =
nodes, and this
exceeded the 5-second limit.
joe
On Tue, 23 Sep 2008 14:30:11 -0700, "Tom Serface" <tom.nos...@camaswoo=
d.com> wrote:
I think an approx. progress bar is better than none, but one that jum=
ps from
0 to 100 is pretty useless. The thing to strive for is periodic feedb=
ack if
the process is going to take a long time. I'm not sure why this is th=
e case
with an XML file unless it is huge. I can parse a 500K line XML file =
before
the progress bar even displays so I haven't found it useful to show t=
hat
kind of feedback.
Tom
"Joseph M. Newcomer" <newco...@flounder.com> wrote in message
news:rfhid494n5j1nf5rjsktvddtr8e515ljak@4ax.com...
I have an article inwww.codeguru.com(linkedto from my Web site) on h=
ow
to put progress
controls on a status bar.
In my PowerPoint Indexer, I have a dialog that does nested progress=
 bars
as various
#includes are processed (I allow the user to start with one present=
ation
and pull in a
second one for a composite index). The whole point was to allow for=
 early
termination.
Many parsing libraries have hooks for various events; the XML libra=
ries I
use all do.
That's where I just ask the current file position of the input file=
.. It
isn't quite
dead-on because it represents where the file pointer is, not where =
the
internal buffers
are, but it is a good enough approximation for a progress bar.
joe
Joseph M. Newcomer [MVP]
email: newco...@flounder.com
Web:http://www.flounder.com
MVP Tips:http://www.flounder.com/mvp_tips.htm-Hide quoted text -
- Show quoted text -
Hi all,
Thanks to all for the replies but i feel your solution is rather bit
complicated
My solution is simple but not fully implemented i need you guys help
In my code
First i call to start the message:
                                   =
      theApp.m_dlgMain-
PostMessage(WM_SHOWMSG,1,0);
****
As soon as I see something callling a method of the CWinApp class, I know=
 I'm seeing a
very, very suspect design decision.  Assume that you never HEARD of the=
 CWinApp-derived
class EXCEPT in the implementation module for the CWinApp class, and that=
 never, ever,
under any conditions imaginable will ever refer to the 'theApp' variable.=
  In order to do
that, you need the header file for the CWinApp class included, and the fi=
rst thing you
should do in any sane design is delete that #include from your modules (M=
icrosoft LOVES to
put it in, but putting it in is always wrong)
NEVER use WM_ as a prefix for a user-defined message, ever.  It makes f=
uture maintenance
difficult.
What are the meanings of 1 and 0?  If WPARAM is a boolean, you would us=
e TRUE or FALSE; if
LPARAM is not used, you would not even mention it.
****
           /*
                                   =
    lengthy process which takes
lot of time like connecting to device and .Xml parsing
                               */
                           Then i want to e=
nd the message
_dlgMain-
PostMessage(WM_SHOWMSG,0,0);
****
Looks to me like these should have been
        ->PostMessage(UWM_SHOWMSG, TRUE);
and
        ->PostMessage(UWM_SHOWMSG, FALSE);
so why use 0 and 1 as parameters?  Also, I would have passed the CWnd* =
into the thread,
not given it a hardwired member of the CWinApp-derived class.
****
IN the message Handler:
ON_MESSAGE(WM_SHOWMSG,DispMsg)
LRESULT CDlgMain::DispMsg(WPARAM wParam, LPARAM lParam)
{
****
If lParam is not used, the correct prototype is
LRESULT CDlgMain::DispMsg(WPARAM wParam, LPARAM)
otherwise you will get a warning about unused parameters
****
           if(wParam==1)
****
If it is a boolean value, just say
                if((BOOL)wParam)
and forget doing an ==.  Actually, the BOOL cast is redundant, but =
doing things like ==1
and ==0 to convey boolean state is poor practice
****>            {
                                   =
    /*start a message stating
"please wait... Loading in progress" without any controls*/
                                  -->=
but i am not getting how to show
just a message with no controls.I tried creating a dialog box and
using domodal to display the message
                                   =
  but it has a caption which i
cannot remove and also i do not know how to close the dialog box
programmatically without pressing any  cancel  button or ok button.
****
Create the dialog box template without a caption, minimize, maximize, or =
system menu.  I
tend to create them as modeless rather than modal, but if I were creating=
 one modal I
would probably launch the thread from its OnInitDialog handler passing 't=
his' in as the
place to post the messages.
When the thread terminates, you would simply invoke the CDialog::OnOK met=
hod to terminate
a modal dialog box, or call DestroyWindow to terminate a modeless dialog =
box
This assumes your thread does a PostMessage that it has terminated, which=
 is good
practice.  You would also override the OnOK and OnCancel handlers to do=
 nothing, and
remove the buttons, or you would override the OnOK handler to do nothing,=
 but the OnCancel
handler would be something like
void CMyDIalog::OnOK()
{
 //does NOTHING, empty body (except for this comment)
}
void CMyDialog::OnCancel()
   {
    ...request thread shutdown
   }
NOTE THAT THERE IS NO CDialog::OnCancel call issued by the OnCancel handl=
er.  Then you
would do something like
LRESULT CMyDIalog::OnThreadTerminated(WPARAM wParam, LPARAM)
   {
    ...thread terminated due to cancellation: wParam is TRUE
    ...thread terminatived because it ran to completion: wParam is FA=
LSE
    BOOL ProcessingAborted = (BOOL)wParam;
    if(ProcessingAborted)
        CDialog::OnCancel();
    else
        CDialog::OnOK();
    return 0;
   }
Note that I roll this code into a more general method later in this discu=
ssion.
 so a message or atleast a
dialogbox with no caption and displaying the message is just fine
           }
           else
           {
                   /*Stop the message when wparam i=
s 0*/
                   the dialogbox or message should =
close without any button click by
****
See my code above.  You would call CDialog::OnOK because it was a succe=
ssful termination.
Or you would pass in information saying whether it was a successful termi=
nation or a
cancellation, e.g.,
typedef enum {THREAD_STARTING, THREAD_FINISHED, THREAD_CANCELLED} ThreadS=
tate;
/************************************************************************=
**=AD*******************
*                                    =
UWM_THREAD_STATE
* Inputs:
*      WPARAM: (WPARAM)(ThreadState) the state of the thread
*      LPARAM:
*       THREAD_STARTING: (LPARAM)(CString*) The message to show
*                               Note: the r=
eceiver must delete this CString*
*       THREAD_FINISHED: unused
*       THREAD_CANCELLED: unused
* Result: LRESULT
*      Logically void, 0, always
* Effect:
*     THREAD_STARTING: shows the text in the dialog box
*     THREAD_FINISHED: Closes the dialog with OK status
*     THREAD_CANCELLED: Closes the dialog with cancelled status
*************************************************************************=
**=AD****************/
....define UWM_THREAD_STATE here, I would write
static const UINT UWM_THREAD_STATE = ::RegisterWindowMessage(_T("UWM_TH=
READ_STATE")
_T("{guid-here}"));
Note that if your definition of your message DOES NOT INCLUDE THE ABOVE D=
OCUMENTATION, YOU
NEED TO RETHINK HOW YOU PROGRAM!  Every message is an interface, and ev=
ery interface must
be specified by writing coherent documentation.
Since I'm working on the premise here that you are using a modal dialog, =
I would do the
following:
void CMyWhatever::StartLongProcess()
    {
     CMyProgressDialog dlg;
     dlg.parameters = ...set parameters to thread here...
     switch(dlg.DoModal())
         { /* dlg */
          case IDOK:
                 ...deal with success
                 break;
          case IDCANCEL:
                 ... deal with cancellation
                 break;
          default:
                 ASSERT(FALSE);
                 return;
        } /* dlg */
     }
BOOL CMyProgressDialog::OnInitDialog()
     {
      parameters.wnd = this;   // CWnd * wnd; // Notification w=
indow
      AfxBeginThread(threadfunc, ¶meters);
      return TRUE;
     }
LRESULT CmyProgressDialog::OnThreadState(WPARAM wParam, LPARAM lParam)
     {
      ThreadState state = (ThreadState)wParam;
      switch(state)
          { /* state */
           case THREAD_STARTING:
               {
                CString * s = (CString *)lParam;
                c_Message.SetWindowText(*s);
                delete s;
                break;
              }
           case THREAD_FINISHED:
               CDialog::OnOK();
               break;
          case THREAD_CANCELLED:
               CDialog::OnCancel();
               break;
          default:
               ASSERT(FALSE);
               break;
       } /* state */
     return 0;
   }
*****>user
                               }
   return TRUE;
}
please reply how to do it
Thanks in advance,
RAGHU
Joseph M. Newcomer [MVP]
email: newco...@flounder.com
Web:http://www.flounder.com
MVP Tips:http://www.flounder.com/mvp_tips.htm
Hi Joe,
Thanks for reply.I am not getting the exact flow of what u are saying
What i understood is this:
//Logic is simple i am starting the message "please wait loading in
progress"
theApp.m_dlgMain->PostMessage(UWM_SHOWMSG, TRUE);
/* code for connecting to the device and parsing the .xml file which
will take 1-2 min*/
//Stop the message
theApp.m_dlgMain->PostMessage(UWM_SHOWMSG, FALSE);
ON_MESSAGE(UWM_SHOWMSG,Dispmesg);
LRESULT CDlgMain::Dispmesg(WPARAM wParam, LPARAM)
{
          if((BOOL)wParam)
            {
                   U have written lot of functions and how to call
from here is what i am not getting->can u please give a connection
from here
                     Message "please wait loading in progress" should
start
                     I do not know how to start a message just saying
the above with no controls-->need help here
            }
          else
          {
                 which function to call to terminate ???
                    Message "please wait loading in progress" should
stop
                    I do not know how to stop a message just saying
the above with no controls-->need your help here
          }
    return TRUE;
}