【问题标题】:Interacting with GUI during long processing在长时间处理期间与 GUI 交互
【发布时间】:2012-11-01 13:45:14
【问题描述】:

我有一个类层次结构:

类 BaseProcess { 公共虚拟无效执行()= 0; }; 类子进程:BaseProcess { 公共虚拟无效执行() { //做点什么 //这里需要回调GUI,可能是从文件选择器中获取文件路径 //做其他事情 //现在想用操作的进度更新GUI //更多处理 } };

假设从 GUI 按钮事件处理程序创建和调用 SubProcess 对象...

我的问题是从 Execute() 函数中与 GUI 交互的最佳方式是什么? (同时假设 Execute() 可能在不同的线程上运行)

我的想法是将回调传递给 SubProcess 对象,因为这将允许我向 GUI 发送信息,但是对于文件选择器,将数据返回到的最佳方法是什么子进程对象?我希望解决方案尽可能通用,以便我可以根据请求返回不同类型的数据。

注意:请忽略任何代码错误,我快速将示例拼凑在一起只是为了说明问题

更新:

很抱歉,这将在 Windows、MFC 上。我不确定这有多重要,因为我认为整体设计应该适用于大多数 GUI 框架?

【问题讨论】:

  • 线程。获取一个线程来完成真正的工作,并告诉它在完成后将结果发布回 GUI。
  • 如果这是 Windows,您将使用 SendMessage()。
  • 没关系,但如果我想在执行过程中发布进度怎么办?另外,如果我需要来自 GUI 的输入而不仅仅是输出到 GUI,该怎么办?
  • 你可以使用 SendMessage 来做这两件事。您将创建自定义消息(WM_USER+1 等)并将它们发送到您的窗口。您也可以传递一个 char 数组,并让窗口填充它。

标签: c++ user-interface mfc


【解决方案1】:
class SubProcess : BaseProcess
{
    public virtual void Execute()
    {
        //Do Something

        char file_name[MAX_PATH +1];
        myWindow->SendMessage(WM_GETFILE, max_path, (LPARAM)file_name); 

        //Do Something Else

        myWindow->SendMessage(WM_UPDATE, 50);

        //More processing   
    }
};

在窗口类中:

#define WM_GETFILE (WM_USER+1)
#define WM_UPDATE (WM_USER+2)

BEGIN_MESSAGE_MAP(CMyWindow, CWnd)
    ON_MESSAGE(WM_GETFILE, MyGetFileHandler)
    ON_MESSAGE(WM_UPDATE, MyUpdateHandler)
END_MESSAGE_MAP()

LRESULT CMyWindow::MyGetFileHandler(WPARAM wParam, LPARAM lParam)
{
}
LRESULT CMyWindow::MyUpdateHandler(WPARAM wParam, LPARAM lParam)
{
}

【讨论】:

  • 这正是我一直在寻找的解决方案,谢谢
  • 您还应该使用Event,这样GUI 线程可以在处理WM_GETFILE 消息时提醒工作线程。消息处理程序将包含SetEvent(),工作线程将包含WaitForSingleObject(),直到设置事件。
  • @japreiss SendMessage() 将阻止,因此不需要事件。
【解决方案2】:

我前段时间使用的 MFC 技术是基于标准的Idle Loop 处理。

这是一种简单的方法,因为在主线程中运行,您的工作人员可以直接作用于 GUI 对象。

如果您“足够频繁地”从工作进程调用消息循环,GUI 将保持平稳运行。

如果您能够承受开发周期中的一些复杂性,您可以使用线程来代替,但根据我的经验,它更难。

【讨论】:

    【解决方案3】:

    取决于图形用户界面。如果您在一个 GUI 允许您从不同线程控制它的系统上,那么您可以从 Execute() 中进行直接 GUI 调用。如果 GUI 不允许这样做,那么您可以通过消息与主线程通信,在那里进行 GUI 调用,并将结果返回给 Execute() 线程。

    Qt 是一个 GUI 框架,它使用它的signals and slots mechanism 来实现这一点。

    【讨论】:

      【解决方案4】:
      class GuiCallback
      {
       public:
           string getFilePath () {/*show the dialog and return the path*/}
           void update (/*arguments with data*/) {}
      };
      class BaseProcess
      {
          public virtual void Execute(GuiCallback*) = 0;  
      
      };
      
      class SubProcess : BaseProcess
      {
          public virtual void Execute(GuiCallback* callback)
          {
              //Do Something
      
              string path = callback->getFilePath ();
      
              //Do Something Else
      
              callback->update (...);
      
              //More processing   
          }
      };
      

      getFilePathupdate 的实现将取决于您使用的平台/gui 框架

      【讨论】:

      • 谢谢你的回答,不幸的是我想比这更通用,所以我可以请求不同类型的数据而不仅仅是字符串。
      • @TomP89,你可以用GuiCallback中的任何返回类型声明你喜欢的任何函数@
      猜你喜欢
      • 1970-01-01
      • 2011-05-30
      • 2012-01-09
      • 1970-01-01
      • 2018-11-25
      • 1970-01-01
      • 1970-01-01
      • 2014-07-27
      • 2021-03-25
      相关资源
      最近更新 更多