我有一个基于MFC的大型应用程序,它在主线程中包含一些可能非常慢的任务。这可以给出应用程序在实际执行长任务时挂起的外观。从可用性的角度来看,我想向用户提供更多关于进度的反馈,并且可以选择以干净的方式中止任务。虽然将长任务分解为单独的线程将是一个更好的长期解决方案,但我认为一个实用的短期解决方案是创建一个新的GUI线程,封装在自己的对象中,包括进度条和取消按钮,用于与CWait对象类似的方式。主线程通过IsCancelled方法监视取消状态,并在需要时通过throw完成。
这是一种合理的方法,如果有的话,那里有一些我可以使用的MFC代码,或者我应该自己动手?第一张草图看起来像这样
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
}
}
作为一项规则,我倾向于拥有一个GUI线程和许多工作线程,但这种方法可能会为我节省大量的重构和测试。任何严重的潜在陷阱?
答案 0 :(得分:3)
简短回答,是的,您可以在MFC中拥有多个GUI线程。但是除了创建的线程之外,您无法直接访问GUI组件。原因是因为MFC下的Win32存储了每个线程的GUI处理程序。这意味着一个线程中的处理程序对另一个线程不可见。如果跳转到CWinThread类源代码,可以在那里找到处理程序映射属性。
Windows(MFC)在工作线程和工作线程之间没有很大区别。 GUI线程。一旦创建了消息队列,就可以将任何线程更改为GUI线程,该消息队列是在与消息相关的第一次调用之后创建的,例如GetMessage()。
在上面的代码中,如果在一个线程中创建了进度条,而在另一个线程中调用了MySlowWork()。您只能使用 CProgressThread 属性而不触及与Win32 GUI相关的函数,例如close,setText,SetProgress ......因为它们都需要GUI处理程序。如果您确实调用了这些函数,则错误将无法找到指定的窗口,因为该处理程序不在线程处理程序映射中。
如果确实需要更改GUI,则需要将消息发送到该进度条所有者线程。让该线程通过PostThreadMessage refer to MSDN for detail自行处理消息(消息处理程序)。