在长时间处理期间与 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
;
getFilePath
和 update
的实现将取决于您使用的平台/gui 框架
【讨论】:
谢谢你的回答,不幸的是我想比这更通用,所以我可以请求不同类型的数据而不仅仅是字符串。 @TomP89,你可以用GuiCallback
中的任何返回类型声明你喜欢的任何函数@以上是关于在长时间处理期间与 GUI 交互的主要内容,如果未能解决你的问题,请参考以下文章