2

我正在尝试在我的过程进行时显示进度条...在我的应用程序中,会出现我必须读取文件并操作它们的情况(需要一些时间才能完成)..想要显示进度条在此操作期间..我正在调用的特定函数是 win 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);




        }
4

2 回答 2

3

跨线程发送消息时有一些陷阱。如果您从线程 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:如果你使用这样的 peek 消息循环会发生什么?

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 );
    }
}
于 2010-03-31T10:46:03.873 回答
0

我在线程调用中更改了 Postmessage 并且它起作用了......

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


                    AfxGetThread()->PumpMessage();
                    Sleep(10);
}
于 2010-04-02T11:52:22.010 回答