在长时间处理期间与 GUI 交互

Posted

技术标签:

【中文标题】在长时间处理期间与 GUI 交互【英文标题】:Interacting with GUI during long processing 【发布时间】: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 数组,并让窗口填充它。 【参考方案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中的任何返回类型声明你喜欢的任何函数@

以上是关于在长时间处理期间与 GUI 交互的主要内容,如果未能解决你的问题,请参考以下文章

gui在处理过程中没有响应?

Qt学习笔记8.Qt中的多线程

在长时间运行期间泵送 Windows 消息?

使用 ReSharper,如何在长时间运行的单元测试期间显示调试输出?

Swing GUI 在数据处理期间不更新

PyQt 和 QML:如何在一个插槽或函数中处理多个信号