版权声明:本文为博主原创文章,不需博主允许即可随意转载。 https://blog.csdn.net/a_dev/article/details/84579678
项目中,从对用户友好的方面来讲,耗时功能需要给个进度条是非常有必要的。
一般来说,对已知上限的循环(比如for循环),用正常的进度条就可以了,而对于事先不知上限的循环(比如while循环),无限循环进度条就比较适合。
本例为一个无限循环进度条,有限循环进度条与之类似。
首先,设计窗体界面:
窗体资源ID为IDD_DIALOG_PROGRESS,包含一个进度条,ID为IDC_PROGRESS_INFO,一个进度文本框,ID为IDC_PROGRESS_TIP。
窗体设置Border为“对话框外观”,Style为Popup弹出式,Topmost属性为true即进行置顶。
在.rc文件中,该窗体资源如下:
IDD_DIALOG_PROGRESS DIALOGEX 0, 0, 381, 55 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_TOPMOST FONT 8, "MS Shell Dlg", 400, 0, 0x1 BEGIN CONTROL "",IDC_PROGRESS_INFO,"msctls_progress32",WS_BORDER,7,8,367,21 LTEXT "当前正在读取...",IDC_PROGRESS_TIP,7,33,367,13 END
接下来,为窗体添加一个类,名为CDialogProgress,并为两个控件添加对应的成员变量,添加实现虚函数。
完整的头文件如下:
#pragma once #include "resource.h" // CDialogProgress 对话框 class CDialogProgress : public CDialog { DECLARE_DYNAMIC(CDialogProgress) public: CDialogProgress(CWnd* pParent = nullptr); // 标准构造函数 virtual ~CDialogProgress(); // 对话框数据 //#ifdef AFX_DESIGN_TIME enum { IDD = IDD_DIALOG_PROGRESS }; //#endif protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 DECLARE_MESSAGE_MAP() public: virtual BOOL OnInitDialog(); void StepIt(); void SetTip(CString sTip); void Stop(); afx_msg void OnClose(); private: CStatic m_progressTip; CProgressCtrl m_progressInfo; bool m_bProcessing; };
设置进度范围为0~10,实现窗体初始化、更新进度、更新提示信息、停止进度等方法。完整的CPP文件如下:
// CDialogProgress.cpp: 实现文件 // #include "stdafx.h" #include "CDialogProgress.h" //#include "afxdialogex.h" CDialogProgress* g_pDialogProgress = NULL; // CDialogProgress 对话框 IMPLEMENT_DYNAMIC(CDialogProgress, CDialog) CDialogProgress::CDialogProgress(CWnd* pParent /*=nullptr*/) : CDialog(IDD_DIALOG_PROGRESS, pParent) { } CDialogProgress::~CDialogProgress() { } void CDialogProgress::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); DDX_Control(pDX, IDC_PROGRESS_TIP, m_progressTip); DDX_Control(pDX, IDC_PROGRESS_INFO, m_progressInfo); } BEGIN_MESSAGE_MAP(CDialogProgress, CDialog) ON_WM_CLOSE() END_MESSAGE_MAP() // CDialogProgress 消息处理程序 BOOL CDialogProgress::OnInitDialog() { CDialog::OnInitDialog(); // TODO: 在此添加额外的初始化 m_progressInfo.SetRange32(0, 10); m_progressInfo.SetStep(1); m_progressInfo.SetPos(0); m_progressTip.SetWindowTextW(_T("正在等待执行...")); m_bProcessing = false; return TRUE; // return TRUE unless you set the focus to a control // 异常: OCX 属性页应返回 FALSE } void CDialogProgress::StepIt() { // TODO: 在此处添加实现代码. m_bProcessing = true; if (m_progressInfo.GetPos() >= 10) { m_progressInfo.SetPos(0); } else { m_progressInfo.StepIt(); } m_progressInfo.SetRedraw(TRUE); } void CDialogProgress::SetTip(CString sTip) { // TODO: 在此处添加实现代码. m_bProcessing = true; m_progressTip.SetWindowTextW(sTip); m_progressTip,SetRedraw(TRUE); } void CDialogProgress::Stop() { // TODO: 在此处添加实现代码. m_bProcessing = false; m_progressInfo.SetPos(10); m_progressTip.SetWindowTextW(_T("结束...")); SetRedraw(TRUE); } void CDialogProgress::OnClose() { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (m_bProcessing) return; CDialog::OnClose(); }
需要注意的是,我们定义了一个窗体指针变量g_pDialogProgress,供外部调用。
调用时,首先导入进度窗体:
extern CDialogProgress* g_pDialogProgress;
窗体控制(创建、显示、进度与提示更新、结束、销毁)示例代码如下:
BOOL CDialogXXX::GetFeatureClassInfo(IWorkspacePtr ipWorkspace, std::deque<FeatureClassArchitecture> &arrFeatureClass, CString sUser = "") { if (nullptr == ipWorkspace) return FALSE; if (NULL == g_pDialogProgress) { g_pDialogProgress = new CDialogProgress(); } g_pDialogProgress->Create(CDialogProgress::IDD, GetDlgItem(IDD_DIALOG_PROGRESS)); g_pDialogProgress->ShowWindow(SW_NORMAL); CString sTip; IEnumDatasetPtr ipEnumDataSet; HRESULT hr = ipWorkspace->get_Datasets(esriDatasetType::esriDTFeatureDataset, &ipEnumDataSet); if (SUCCEEDED(hr)) { IDatasetPtr ipDataset = NULL; while (SUCCEEDED(ipEnumDataSet->Next(&ipDataset)) && (NULL != ipDataset)) { doevents(NULL); g_pDialogProgress->StepIt(); BSTR bsDsName = NULL; if (SUCCEEDED(ipDataset->get_Name(&bsDsName))) { CString sDatasetFullName = bsDsName; CString sUserName = ""; CString sDatasetName = ""; SplitName(sDatasetFullName, sUserName, sDatasetName); sTip = _T("正在获取【") + sUserName + _T("】用户【") + sDatasetName + _T("】数据集下的图层信息..."); g_pDialogProgress->SetTip(sTip); if (sUser.IsEmpty() || 0 == sUser.CompareNoCase(sUserName)) { std::vector<IFeatureClassPtr> vecFeatureClass; GetFeatureClassFromDataset(ipDataset, vecFeatureClass); auto iter = vecFeatureClass.begin(); for (; iter != vecFeatureClass.end(); iter++) { g_pDialogProgress->StepIt(); IFeatureClassPtr ipFeatureClass = *iter; BSTR bsFeatureClassFullName = NULL; BSTR bsAlias = NULL; esriFeatureType eFeatureType; esriGeometryType eGeometryType; GetFeatureClassNameInfo(ipFeatureClass, bsFeatureClassFullName, bsAlias, eFeatureType, eGeometryType); CString sFeatureClassFullName = bsFeatureClassFullName; CString sFeatureClassName = ""; SplitName(sFeatureClassFullName, sUserName, sFeatureClassName); sTip = _T("正在获取【") + sUserName + _T("】用户【") + sDatasetName + _T("】数据集下的【") + sFeatureClassName + _T("】图层信息..."); g_pDialogProgress->SetTip(sTip); arrFeatureClass.push_back(FeatureClassArchitecture(sFeatureClassName, eFeatureType, eGeometryType, (CString)bsAlias, sDatasetName)); SysFreeString(bsFeatureClassFullName); SysFreeString(bsAlias); } SysFreeString(bsDsName); } } } } ipEnumDataSet = NULL; hr = ipWorkspace->get_Datasets(esriDatasetType::esriDTFeatureClass, &ipEnumDataSet); if (SUCCEEDED(hr)) { IDatasetPtr ipDataset = NULL; while (SUCCEEDED(ipEnumDataSet->Next(&ipDataset)) && nullptr != ipDataset) { doevents(NULL); g_pDialogProgress->StepIt(); IFeatureClassPtr ipFeatureClass = ipDataset; if (nullptr != ipFeatureClass) { BSTR bsName = NULL; BSTR bsAlias = NULL; esriFeatureType eFeatureType; esriGeometryType eGeometryType; GetFeatureClassNameInfo(ipFeatureClass, bsName, bsAlias, eFeatureType, eGeometryType); CString sFullName = (CString)bsName; CString sUserName = ""; CString sFeatureClassName = ""; SplitName(sFullName, sUserName, sFeatureClassName); sTip = _T("正在获取【") + sUserName + _T("】用户的【") + sFeatureClassName + _T("】图层信息..."); g_pDialogProgress->SetTip(sTip); if (sUser.IsEmpty() || 0 == sUser.CompareNoCase(sUserName)) { arrFeatureClass.push_back(FeatureClassArchitecture(sFeatureClassName, eFeatureType, eGeometryType, (CString)bsAlias)); } SysFreeString(bsName); SysFreeString(bsAlias); } } } g_pDialogProgress->Stop(); if (NULL != g_pDialogProgress) { if (TRUE == ::IsWindow(g_pDialogProgress->GetSafeHwnd())) { g_pDialogProgress->DestroyWindow(); } delete g_pDialogProgress; g_pDialogProgress = NULL; } }
跑起来,效果如下:
需要注意的是:
1.当正在执行进度时,不要允许进度窗体关闭
2.进度窗体调用完成时,需先销毁窗体,再删除窗体指针
3.添加窗体要继承自CDialog而不要继承CDialogEx
4.添加窗体后,默认编译不过,需要取消cpp包含dialogex.h,头文件添加包含resource.h
转载请标明出处:MFC无限循环进度条示例
文章来源: MFC无限循环进度条示例