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

标签 c multithreading progress-bar win32-process

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

编辑2: 使用 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);




        }

最佳答案

跨线程发送消息时存在一些问题。如果您从线程 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 原型(prototype)更改为:

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

关于c - 如何在 win 32 中使用线程概念实现进度条(显示进度)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2552101/

相关文章:

java - JProgressBar 未按预期工作

c - 具有动态内存分配的 C 追加函数

c++ - OpenMP "master"编译指示不得包含在 "parallel for"编译指示中

在 C 中使用 atoi 命令行 arg 到 int

java - Executors 相对于 new Thread 的优势

multithreading - 在线程内创建共享变量可以吗?

c - 是否有任何 C 库为 GNU/Linux 实现 C11 线程?

python - Tkinter 中的进度条,里面有标签

c - 一种将代码的运行时间从O(n ^ 2)减少到更少的方法

c - 当不能接受精度损失时,是否有合理的理由使用 double 来存储整数?