MFC下一个通用非阻塞的等待执行结束的对话框类
头文件:CPictureEx用于显示一个等待动画
#pragma once#include"afxwin.h"#include"resource.h"#include"PictureEx.h"#include<thread> //CWaitDlg 对话框 classCWaitSingleEvent {public:
CWaitSingleEvent()
: handle_(nullptr){
handle_=CreateEvent(nullptr, TRUE, FALSE, nullptr);
}~CWaitSingleEvent(){if(handle_) {
CloseHandle(handle_);
}
}operator bool()const{return handle_ !=nullptr;
}int Wait(constDWORD wait_time) {
DWORD retval= 0;if(handle_) {
retval=WaitForSingleObject(handle_, wait_time);
ResetEvent(handle_);
}returnretval;
}voidNotify() {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 : publicCDialogEx
{
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 boolis_quit_thread_;
std::thread*wait_to_exec_thread_;
CWaitSingleEvent wait_to_exec_condition_;voidwait_to_exec_callback();protected:virtual void DoDataExchange(CDataExchange* pDX); //DDX/DDV 支持 DECLARE_MESSAGE_MAP()public:virtualBOOL OnInitDialog();
CPictureEx m_show_gif_;virtual voidOnCancel();virtual voidOnOK();
};
代码实现:
//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) {returnFALSE;
}
DWORD dwSize=SizeofResource(NULL, hRsrc);
HGLOBAL hGlobal=LoadResource(NULL, hRsrc);if (NULL ==hGlobal) {
CloseHandle(hRsrc);returnFALSE;
}
unsignedchar* pBuffer = (unsigned char*)LockResource(hGlobal);if (NULL ==pBuffer) {
CloseHandle(hRsrc);
FreeResource(hGlobal);returnFALSE;
}//判断是否为GIF文件 if(pBuffer[0] != 0x47 && pBuffer[1] != 0x49 && pBuffer[2] != 0x46 && pBuffer[3] != 0x38){returnFALSE;
}//读取宽高 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);returnTRUE;
}
}
UnlockResource(hGlobal);
FreeResource(hGlobal);returnFALSE;
}
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 }voidCWaitDlg::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_= newstd::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();
}voidCWaitDlg::OnCancel()
{//TODO: 在此添加专用代码和/或调用基类//CDialogEx::OnCancel(); }voidCWaitDlg::OnOK()
{//TODO: 在此添加专用代码和/或调用基类//暂时允许关闭 CDialogEx::OnOK();
}
使用示例:
typedef structset_xxx_info_st {intindex;
CString strXxxInfo;
}set_xxx_info_st;voidCXXXParamDlg::OnClickedBtnWriteXxx()
{
CString strXxxC= _T("strXxxC");//必须使用堆内存,调用会立即返回,但对象的使用,却在线程中 set_xxx_info_st* inn_param = newset_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) {deleteset_param;
}return 0;
}