MFC无限循环进度条示例

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

猜你喜欢

转载自blog.csdn.net/a_dev/article/details/84579678