MFC下一个通用非阻塞的等待执行结束的对话框类
头文件:CPictureEx用于显示一个等待动画
#pragma once #include "afxwin.h" #include "resource.h" #include "PictureEx.h" #include <thread> // CWaitDlg 对话框 class CWaitSingleEvent { public: CWaitSingleEvent() : handle_(nullptr){ handle_ = CreateEvent(nullptr, TRUE, FALSE, nullptr); } ~CWaitSingleEvent(){ if(handle_) { CloseHandle(handle_); } } operator bool()const{ return handle_ != nullptr; } int Wait(const DWORD wait_time) { DWORD retval = 0; if(handle_) { retval = WaitForSingleObject(handle_, wait_time); ResetEvent(handle_); } return retval; } void Notify() { if(handle_) { SetEvent(handle_); } } protected: CWaitSingleEvent(const CWaitSingleEvent& rhs){ } CWaitSingleEvent& operator=(const CWaitSingleEvent& rhs){ return *this; } private: HANDLE handle_; }; typedef UINT32 (CDialogEx::*WaitToExec)(void* param); class CWaitDlg : public CDialogEx { DECLARE_DYNAMIC(CWaitDlg) public: CWaitDlg(CWnd* pParent = NULL); // 标准构造函数 virtual ~CWaitDlg(); // 对话框数据 enum { IDD = IDD_DIALOG4 }; //设置执行等待函数 void SetWaitToExec(CWnd* pParent, void* pInnerParam, CDialogEx* pThis, WaitToExec pWaitToExec); private: void* exec_inner_param_; CDialogEx* dialog_this; WaitToExec wait_to_exec_func_pt_; volatile bool is_quit_thread_; std::thread* wait_to_exec_thread_; CWaitSingleEvent wait_to_exec_condition_; void wait_to_exec_callback(); protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); CPictureEx m_show_gif_; virtual void OnCancel(); virtual void OnOK(); };
代码实现:
// WaitDlg.cpp : 实现文件 // #include "stdafx.h" #include "WaitDlg.h" #include "afxdialogex.h" // CWaitDlg 对话框 IMPLEMENT_DYNAMIC(CWaitDlg, CDialogEx) CWaitDlg::CWaitDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CWaitDlg::IDD, pParent), wait_to_exec_func_pt_(nullptr), dialog_this(nullptr) { is_quit_thread_ = false; exec_inner_param_ = NULL; wait_to_exec_thread_ = nullptr; } CWaitDlg::~CWaitDlg() { is_quit_thread_ = true; wait_to_exec_condition_.Notify(); if (nullptr != wait_to_exec_thread_){ if(wait_to_exec_thread_->joinable()) { wait_to_exec_thread_->join(); } wait_to_exec_thread_ = nullptr; } } void CWaitDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_SHOW_GIF, m_show_gif_); } BEGIN_MESSAGE_MAP(CWaitDlg, CDialogEx) END_MESSAGE_MAP() // CWaitDlg 消息处理程序 BOOL GetResGifSize(long nResId, LPCTSTR name, long *lnWidth, long *lnHeight) { HRSRC hRsrc = FindResource(NULL, MAKEINTRESOURCE(nResId), name); if (NULL == hRsrc) { return FALSE; } DWORD dwSize = SizeofResource(NULL, hRsrc); HGLOBAL hGlobal = LoadResource(NULL, hRsrc); if (NULL == hGlobal) { CloseHandle(hRsrc); return FALSE; } unsigned char* pBuffer = (unsigned char*)LockResource(hGlobal); if (NULL == pBuffer) { CloseHandle(hRsrc); FreeResource(hGlobal); return FALSE; } //判断是否为GIF文件 if(pBuffer[0] != 0x47 && pBuffer[1] != 0x49 && pBuffer[2] != 0x46 && pBuffer[3] != 0x38){ return FALSE; } //读取宽高 for(DWORD i = 4; i < dwSize ; i++) { if(pBuffer[i] == 0x00 && pBuffer[i+1] == 0x2c) { *lnWidth = (pBuffer[i+7]<<8) | pBuffer[i+6]; *lnHeight = (pBuffer[i+9]<<8) | pBuffer[i+8]; UnlockResource(hGlobal); FreeResource(hGlobal); return TRUE; } } UnlockResource(hGlobal); FreeResource(hGlobal); return FALSE; } BOOL CWaitDlg::OnInitDialog() { CDialogEx::OnInitDialog(); //设置窗口大小 long nGifWidth = 75; long nGifHeight = 75; if (!GetResGifSize(IDR_WAIT_GIF_1, _T("GIF"), &nGifWidth, &nGifHeight)){ MessageBox(_T("内部错误"),_T("错误"), MB_OK | MB_ICONERROR); } RECT rt; GetClientRect(&rt); //判断窗口是否太大,或者太小,放不下 if ( (rt.right - rt.left - nGifWidth > 64) || (rt.bottom - rt.top - nGifHeight > 64) || (rt.right - rt.left < nGifWidth) || (rt.bottom - rt.top < nGifHeight) ) { RECT rtWin; GetWindowRect(&rtWin); //调整窗口大小 rtWin.right = rtWin.left + nGifWidth + 64; rtWin.bottom = rtWin.top + nGifHeight + 64; MoveWindow(&rtWin); //重新获取客户区大小 GetClientRect(&rt); } CenterWindow(); //计算位置 rt.left = (rt.right - rt.left - nGifWidth)/2; rt.right = rt.left + nGifWidth; rt.top = (rt.bottom - rt.top - nGifHeight)/2; rt.bottom = rt.left + nGifHeight; //转化成屏幕坐标 //ClientToScreen(&rt); m_show_gif_.MoveWindow(&rt, TRUE); SetBackgroundColor(RGB(240,240,240), TRUE); m_show_gif_.SetBkColor(RGB(240,240,240)); if (m_show_gif_.Load(MAKEINTRESOURCE(IDR_WAIT_GIF_1),_T("GIF"))){ m_show_gif_.Draw(); } return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CWaitDlg::wait_to_exec_callback() { if(is_quit_thread_) { return ; } while (!is_quit_thread_){ //等待事件是否过来 wait_to_exec_condition_.Wait(INFINITE); if(is_quit_thread_) {break;} //判断参数是否OK if ((nullptr != dialog_this) && (nullptr != wait_to_exec_func_pt_)){ (dialog_this ->*wait_to_exec_func_pt_)(exec_inner_param_); //执行完一次,那就隐藏一下 if (NULL != m_hWnd) { ShowWindow(SW_HIDE); } } } } //设置执行等待函数 void CWaitDlg::SetWaitToExec(CWnd* pParent, void* pInnerParam, CDialogEx* pThis, WaitToExec pWaitToExec) { exec_inner_param_ = pInnerParam; dialog_this = pThis; wait_to_exec_func_pt_ = pWaitToExec; //通知线程执行 is_quit_thread_ = false; if (wait_to_exec_thread_ == nullptr) { wait_to_exec_thread_ = new std::thread; } if(!wait_to_exec_thread_->joinable()) { *wait_to_exec_thread_ = std::move(std::thread(&CWaitDlg::wait_to_exec_callback, this)); } //显示本窗口 if (NULL == m_hWnd) { Create(IDD_DIALOG4, pParent); } ShowWindow(SW_SHOW); //触发事件 wait_to_exec_condition_.Notify(); } void CWaitDlg::OnCancel() { // TODO: 在此添加专用代码和/或调用基类 //CDialogEx::OnCancel(); } void CWaitDlg::OnOK() { // TODO: 在此添加专用代码和/或调用基类 //暂时允许关闭 CDialogEx::OnOK(); }
使用示例:
typedef struct set_xxx_info_st { int index; CString strXxxInfo; }set_xxx_info_st; void CXXXParamDlg::OnClickedBtnWriteXxx() { CString strXxxC = _T("strXxxC"); // 必须使用堆内存,调用会立即返回,但对象的使用,却在线程中 set_xxx_info_st* inn_param = new set_xxx_info_st; inn_param->index = m_set_cert_index_combo_.GetCurSel() + 1; inn_param->strXxxInfo.Append(strXxxC); //调用线程接口去获取 m_wait_dlg_.SetWaitToExec(GetParent(), inn_param, this, (WaitToExec)&CXXXParamDlg::WaitToExecSetXXXInfo); } UINT32 CXXXParamDlg::WaitToExecSetXXXInfo(void* inn_param) { UINT32 ulRet = -1; set_xxx_info_st* set_param = (set_xxx_info_st*)(inn_param); //禁止父窗口控件 GetParent()->GetParent()->EnableWindow(FALSE); //设置进去 ExecSetXXX(set_param->index, set_param->strXxxInfo); //禁止父窗口控件 GetParent()->GetParent()->EnableWindow(TRUE); if (nullptr != set_param) { delete set_param; } return 0; }
标签:
通用 非阻塞 等待执行结束
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?