6

I have a large MFC based application that includes some potentially very slow tasks in the main thread. This can give the appearance that the application has hung when it is actually working its way through a long task. From a usability point of view, I'd like to be giving the user some more feedback on progress, and have an option to abort the task in a clean manner. While hiving the long tasks off into separate threads would be a better long term solution, I'm thinking a pragmatic short term solution is create a new GUI thread encapsulated in its own object complete with dialog including progress bar and cancel button, used in a similar manner to a CWait object. The main thread monitors the cancel status via an IsCancelled method, and finishes via a throw when required.

Is this a reasonable approach, and if so is there some MFC code out there already that I can use, or should I roll my own? First sketch looks like this

class CProgressThread : public CWinThread
{
public:
    CProgressThread(int ProgressMax);      
    ~CProgressThread()
    void SetProgress(int Progress);
    BOOL IsCancelled();
private:
   CProgressDialog  *theDialog;
}

void MySlowTask()
{
   CProgressThread PT(MaxProgress);
   try
   {
       {
           {  // deep in the depths of my slow task
              PT.SetProgress(Progress);
              if (PT.IsCancelled())
                 throw new CUserHasHadEnough; 
           }
        }
    }
    catch (CUserHasHadEnough *pUserHasHadEnough)
    {
        // Clean-up
    }
}    

As a rule, I tend to have one GUI thread and many worker threads, but this approach could possibly save me a bunch of refactoring and testing. Any serious potential pitfalls?

4

1 回答 1

3

简短的回答,是的,您可以在 MFC 中拥有多个 GUI 线程。但是除了创建的线程之外,您不能直接访问 GUI 组件。原因是 MFC 下的 Win32 存储基于每个线程的 GUI 处理程序。这意味着一个线程中的处理程序对另一个线程不可见。如果您跳转到 CWinThread 类源代码,您可以在那里找到一个处理程序映射属性。

Windows (MFC) 在工作线程和 GUI 线程之间没有硬性区别。任何线程都可以在创建消息队列后更改为 GUI 线程,消息队列是在与消息相关的第一次调用之后创建的,例如 GetMessage()。

在上面的代码中,如果进度条是在一个线程中创建的,并且 MySlowWork() 在另一个线程中被调用。您只能使用CProgressThread属性而不触及 Win32 GUI 相关函数,例如 close、setText、SetProgress...,因为它们都需要 GUI 处理程序。如果您确实调用了这些函数,则错误将是找不到指定的窗口,因为该处理程序不在线程处理程序映射中。

如果您确实需要更改 GUI,则需要将消息发送到该进度条所有者线程。让该线程通过 PostThreadMessage 自己处理消息(消息处理程序),详细参考 MSDN

于 2013-09-20T00:37:07.527 回答