如何在win 32中使用线程概念实现进度条(显示进度)?

时间:2010-03-31 10:33:59

标签: c multithreading progress-bar win32-process

我正在尝试在我的进程正在进行时显示进度条...在我的应用程序中将出现我需要读取文件并操作它们的情况(这需要一些时间才能完成)..想要显示在此操作期间的进度条...我正在调用的特定功能是赢32 ...所以如果你检查下面的代码我在对话框窗口中创建进度条并创建一个线程现在我不知道如何发布消息以及在何处获取消息和处理...请帮助我......提前感谢

    //my  function
    int Myfunction(....)
    {
     MSG msg;
     HWND dialog = CreateWindowEx(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: 使用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);




        }

2 个答案:

答案 0 :(得分:3)

跨线程发送消息时有一些问题。如果SendMessage从线程A到线程B,那么内部发生的是线程A将消息发布到线程B的消息队列。然后它坐下并等待处理消息,然后将结果发送回线程A.这意味着您需要在线程B中抽取消息,否则线程A将会死锁。

关于您的具体问题,您可以在创建进度条后简单地输入以下代码:

SendMessage( pBar, PBM_SETRANGE, 0, MAKELPARAM( 0, noOfFiles ) );

然后你需要将pBar传递给你的线程。这很简单。您会注意到CreateThread允许您将参数作为void *传递给线程函数。所以重新编写你的CreateThread:

HANDLE getHandle = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)SetFilesForOperation(...),
                                (void*)pBar,NULL,0);

然后将您的SetFilesForOperation原型更改为:

LPARAM SetFilesForOperation( HWND pBar );

请注意,您将线程函数转换为正确的格式。所以Windows内部只会传递void *。然后发生隐式转换,你在另一端看到的是HWND而不是void *。通过将指向结构的指针传递给线程函数,可以传递更多数据。只需记住在SetFilesForOperation拥有它需要的信息之前不要释放结构(通过让它退出范围或显式)。你可以通过一个简单的事件来解决这个问题,一旦线程函数获得了它之后的数据,然后在创建事件的线程中等待它就会被触发。

然后只需在循环结束时添加以下消息:

PostMessage( pBar, PBM_SETPOS, (WPARAM)index, 0 );

然后,这将使每个循环通过一个推进。

编辑:正如评论中指出的那样,它只是使用PostMessage,因为它不会等待返回意味着消息只是发布到UI线程的消息队列。但请注意,如果您不抽取该消息队列,您将发送消息,并且您将看不到进度条更新,因为消息将仅备份到队列中。

编辑2:您正在设置消息循环后进度条的范围。所以范围永远不会被设定。你需要事先做到这一点。还值得注意的是,只有在发送WM_QUIT消息时才会退出消息泵。这不太理想。您可以在线程循环结束时发布自己的消息。您需要的更改如下。首先,您需要声明自定义(用户)消息。

#define WM_EXITTHREAD WM_USER + 1

然后将您的消息循环更改为以下内容:

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); 
}

最后在你的主题结尾处有以下内容:

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:如果你使用像这样的偷看消息循环会怎样?

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 );
    }
}

答案 1 :(得分:0)

我在线程调用中更改了Postmessage并且它有效...

while(PeekMessage( &msg, NULL, NULL, NULL, PM_NOREMOVE))
                {


                    AfxGetThread()->PumpMessage();
                    Sleep(10);
}