我是 GUI C++新手,正在修改随机器发送给我的代码,我想在单击按钮时进行 while 循环,我尝试了线程,它仍然卡住了。
void CDlgWriteEPC::loop()
{
// Do something
}
void CDlgWriteEPC::OnBnClickedOk()
{
std::thread loadingThread(&CDlgWriteEPC::loop, this);
loadingThread.join();
}
join 会阻止当前线程,直到另一个线程完成,所以这没有帮助。您应该启动工作线程,立即返回和工作线程完成后应该发送某种消息。
示例代码中的函数名称似乎来自 MSVC++ MFC应用程序,因此我们将使用它。
简而言之,Windows GUI 应用程序是事件驱动的,每次事件发生时,都会发生发送WM_MESSAGE。框架接收这些消息并调用相应的函数来处理它。我们可以定义自己的消息和消息处理程序。这样,工作线程可以将此类消息发送到框架,它将调用我们的处理程序函数。
WM_APP被定义为私人用户消息的起点,因此不会有与现有系统消息的任何冲突。
(https://msdn.microsoft.com/en-us/library/windows/desktop/ms644930%28v=vs.85%29.aspx)
因此,假设我们正在构建一个 MFC 对话框应用程序,用于搜索文件中的某些内容。如果文件很大,则可能需要很长时间,并防止阻塞主线程和收到"窗口没有响应"消息,我们需要在工作线程中执行此操作。我们可能会例如,还需要一个进度条。
首先,我们在现有的 dialog 类中定义我们自己的消息,从 WM_APP + 1 开始我们添加处理程序函数,这些函数必须属于以下类型: afx_msg LRESULT (CWnd::*)(WPARAM, LPARAM)
WPARAM 和 LPARAM 是发布消息时传递的参数,您可以使用它们发送自定义数据。在我们的示例中,我们可以使用它们来发送进度条的进度百分比。
(https://msdn.microsoft.com/en-us/library/k35k2bfs.aspx)
class CMyAppDlg : public CDialogEx
{
public:
//Public so the worker thread class can use these same sames when posting a message.
enum Messages
{
MSG_ThreadProgress = WM_APP + 1,
MSG_ThreadDone
};
private:
afx_msg LRESULT OnThreadProgress(WPARAM wParam, LPARAM lParam)
{
ProgressBar->SetPos(wParam); //Worker thread posts progress as wParam
};
afx_msg LRESULT OnThreadDone(WPARAM wParam, LPARAM lParam)
{
//Get result from worker thread class and use it...
};
};
然后我们需要将我们的消息和处理程序添加到消息映射中,您应该将它们添加到已经对话框/文档的.cpp文件中的现有消息映射。
BEGIN_MESSAGE_MAP(CMyAppDlg, CDialogEx)
ON_MESSAGE(MSG_ThreadProgress, &CMyAppDlg::OnThreadProgress)
ON_MESSAGE(MSG_ThreadDone, &CMyAppDlg::OnThreadDone)
END_MESSAGE_MAP()
现在我们可以简单地将这些消息发布在我们的工作线程中,框架主线程将处理消息并更新进度条或使用结果:
class ThreadClass
{
public:
//Constructor takes a reference to our dialog class because we need the window handle
//to post a message
ThreadClass(CMyAppDlg& MyAppDlg) : mMyAppDlg(MyAppDlg) {};
void operator()() //Thread worker code...
{
while (what_we_look_for_not_found)
{
int Progress = 0;
//Search for a while and update progress variable...
//Post message to dialog asking it to update the progressbar
PostMessage(mMyAppDlg.m_hWnd, CMyAppDlg::MSG_ThreadProgress, Progress, 0);
}
//Finished searching...
StoreResult();
//Post message to dialog informing it thread is done and result can be retrieved.
PostMessage(mMyAppDlg.m_hWnd, CMyAppDlg::MSG_ThreadDone, 0, 0);
}
private:
CMyAppDlg& mMyAppDlg;
};
QT使用与SIGNAL和SLOT类似的系统,其他框架肯定有自己的等效系统。如果您使用的是MSVC++ MFC以外的其他东西,您应该能够在手册中找到更多信息。