How to implement progressbar(to show progress) using threading concept in win 32?
I am trying to show a progress bar while my process is going on...in my application there will be a situation where I gotta read files and manipulate them(it will take some time to complete)..want to display a progress bar during this operation..the particular function I am calling is an win 32 ...so if you check my code below i am upto the point of creating the progress bar in a dialog window and creating a thread Now I dont know how to post the message and where to get the message and handle...Please help me..thanks in advance
//my function
int Myfunction(....)
{
MSG msg;
HWND dialog = Cr开发者_StackOverflow社区eateWindowEx(0,WC_DIALOG,L"Proccessing...",WS_OVERLAPPEDWINDOW|WS_VISIBLE,
600,300,280,120,NULL,NULL,NULL,NULL);
HWND pBar = CreateWindowEx(NULL,PROGRESS_CLASS,NULL,WS_CHILD|WS_VISIBLE,40,20,200, 20,
dialog,(HMENU)IDD_PROGRESS,NULL,NULL);
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
Dispatch(&message);
}
SendMessage(pBar,PBM_SETRANGE,0,MAKELPARAM(0,noOfFile));
HANDLE getHandle = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)SetFilesForOperation(...),
NULL,NULL,0);
}
LPARAM SetFilesForOperation(...)
{
for(int index = 0;index < noOfFiles; index++)
{
*checkstate = *(checkState + index);
if(*checkstate == -1)
{
*(getFiles+i) = new TCHAR[MAX_PATH];
wcscpy(*(getFiles+i),*(dataFiles +index));
i++;
}
else
{
(*tempDataFiles)->Add(*(dataFiles+index));
*(checkState + localIndex) = *(checkState + index);
localIndex++;
}
PostMessage(pBar,PBM_SETPOS,(WPARAM)index,0);
}
}
EDIT2: using AFXTHREAD
//instead of createthread i used AfxBegin thread
ptrThread = AfxBeginThread((AFX_THREADPROC)SetFilesForOperation(pBar,checkstate,checkState,noOfFiles,i,getFilesforcompression,dataFiles,&tempDataFiles,localIndex),
NULL,THREAD_PRIORITY_ABOVE_NORMAL,NULL,NULL,NULL);
for(int index = 0;index < noOfFiles; index++)
{
MSG msg;
*checkstate = *(checkState + index);
if(*checkstate == -1)
{
*(getFilesforcompression+i) = new TCHAR[MAX_PATH];
//*(getFilesforcompression+i) = L"C:\\Documents and Settings\\rakesh\\Desktop\\try2_Extracted";
wcscpy(*(getFilesforcompression+i),*(dataFiles +index));
i++;
}
else
{
(*tempDataFiles)->Add(*(dataFiles+index));
*(checkState + localIndex) = *(checkState + index);
localIndex++;
}
//PostMessage( pBar, PBM_SETPOS, (WPARAM)index, 0 );
PostMessage( pBar, PBM_SETRANGE, 0, MAKELPARAM( 0, noOfFiles ) );
//PostMessage( pBar, PBM_SETPOS, (WPARAM)index, 0 );
PostMessage( pBar, PBM_STEPIT, (WPARAM)index, 0 );
PostMessage( pBar, MSG_PROGRESS_VALUE, 0, 0 );
while(1)
{
while(PeekMessage( &msg, NULL, NULL, NULL, PM_NOREMOVE))
{
AfxGetThread()->PumpMessage();
Sleep(10);
}
There are a few gotchas when sending messages across threads. If you SendMessage from Thread A to Thread B then what happens internally is that Thread A posts the message to Thread B's message queue. It then sits and waits for the message to be processed before sending the result back to Thread A. This means that you need to be pumping messages in Thread B or Thread A will deadlock.
As to your specific problem you can simply put the following code after you create the progress bar:
SendMessage( pBar, PBM_SETRANGE, 0, MAKELPARAM( 0, noOfFiles ) );
Then you need to pass pBar into your thread. This is pretty easy. You'll note that CreateThread allows you to pass a parameter to the thread function as a void*. So re-write your CreateThread as:
HANDLE getHandle = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)SetFilesForOperation(...),
(void*)pBar,NULL,0);
Then change your SetFilesForOperation prototype to this:
LPARAM SetFilesForOperation( HWND pBar );
Note thatyou cast the thread function to the right format. So Windows, internally, will just pass the void*. An implicit cast then happens and what you see at the other end is an HWND rather an a void*. You can pass much more data through by passing a pointer to a struct to the thread function. Just remember not to free the struct (either by letting it drop out of scope or explicitly) before SetFilesForOperation has the info it needs out of it. You can solve this with a simple event that gets fired once the thread function has the data it is after and then waiting in the thread that does the creation for the event to be fired.
Then simply add the following message at the end of the loop:
PostMessage( pBar, PBM_SETPOS, (WPARAM)index, 0 );
This will then advance the bar by one each loop through.
Edit: As pointed out in the comments its worth just using PostMessage as it won't wait for the return meaning that the message is simply posted to the UI thread's message queue. Do note, though, that if you don't pump that message queue you'll be sending messages across and you won't see the progress bar updating as the messages will just back up in the queue.
Edit 2: You are setting the range of your progress bar AFTER the message loop. So the range never gets set. You need to do that before hand. Its also worth noting that your message pump will only exit when you send a WM_QUIT message. This is not ideal. You could though post a message of your own at the end of your thread loop. The changes you would need are as follows. Firstly you need to declare the custom (User) message.
#define WM_EXITTHREAD WM_USER + 1
Then change your message loop to the following:
SendMessage(pBar,PBM_SETRANGE,0,MAKELPARAM(0,noOfFile));
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
if ( msg.message == WM_EXITTHREAD )
{
break;
}
TranslateMessage(&msg);
Dispatch(&msg);
}
And finally have the following at the end of your thread:
PostMessage( pBar, WM_EXITTHREAD, 0, 0 );
EndThread( 0 ); // This is the preferred way of exiting a thread in C
return 0; // This is the preferred way of exiting a thread in C++ so that destructors get called.
Edit3: What happens if you use a peek message loop like this?
while( 1 )
{
MSG msg;
if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
if ( msg.message == WM_EXITTHREAD )
{
break;
}
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
Sleep( 0 );
}
}
I changed the Postmessage in the thread call and it worked...
while(PeekMessage( &msg, NULL, NULL, NULL, PM_NOREMOVE))
{
AfxGetThread()->PumpMessage();
Sleep(10);
}
精彩评论