版权声明:本文为博主原创文章,不需博主允许即可随意转载。 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