CShowProgressDlg.h 头文件
// 显示一个进度条
class CShowProgressDlg
{
public:
CShowProgressDlg();
~CShowProgressDlg();
//进程外进度对话框会一直监视该窗口句柄,如果它变的无效就自动退出进度对话框,
//防止调用程序崩溃后进度对话框还一直存在
void SetWatchWnd(HWND hWatchWnd);
//得到监视窗口
HWND GetWatchWnd() const;
//得到等待对话框的窗口句柄(注意, 这是一个进程外的窗口)
HWND GetWnd() const;
//设置是否允许取消
void SetEnableCancel(BOOL bEnableCancel=FALSE);
//设置进度范围,消息可以有两行,中间用\n分隔
void SetRange(LPCTSTR szMsg,short int nMinPos,short int nMaxPos);
//得到设置的进度范围
void GetRange(short int &nMinPos,short int &nMaxPos) const;
//设置进度,消息可以有两行,中间用\n分隔
void SetPos(LPCTSTR szMsg,short int nPos);
//得到当前进度
short int GetPos() const;
//关闭进度对话框
void Close();
//返回是否用户取消了
BOOL GetIsCanceled() const;
private:
HWND m_hWatchWnd;
HWND m_hProgressDlgWnd;
BOOL m_bEnableCancel;
HANDLE m_hMemFile;
PROGRESSDLGDATA *m_pData;
short int m_nMinPos;
short int m_nMaxPos;
short int m_nCurPos;
};
CShowProgressDlg.cpp 源文件
// ProgressDlg.cpp : implementation file
#include "stdafx.h"
#include "ProgressDlg.h"
#include "HYWaitDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// CProgressDlg dialog
CProgressDlg::CProgressDlg(CWnd* pParent /*=NULL*/)
: CDialog(CProgressDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CProgressDlg)
// NOTE: the ClassWizard will add member initialization here
//}}AFX_DATA_INIT
m_dwTickCount = 0;
m_bCanceled = FALSE;
m_hWatchWnd = NULL;
m_hMemFile = NULL;
}
CProgressDlg::~CProgressDlg()
{
if(m_hMemFile)
{
CloseHandle(m_hMemFile);
}
}
void CProgressDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CProgressDlg)
DDX_Control(pDX, IDC_STATIC_TIME, m_CtlMsgTime);
DDX_Control(pDX, IDC_STATIC_2, m_CtlMsg2);
DDX_Control(pDX, IDC_STATIC_1, m_CtlMsg1);
DDX_Control(pDX, IDC_PROGRESS1, m_CtlProgress);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CProgressDlg, CDialog)
//{{AFX_MSG_MAP(CProgressDlg)
ON_WM_TIMER()
//}}AFX_MSG_MAP
ON_MESSAGE(WM_UPDATEMSG,OnMessage)
ON_WM_CLOSE()
END_MESSAGE_MAP()
/
// CProgressDlg message handlers
BOOL CProgressDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
CGBFWaitDlgApp *pApp = (CGBFWaitDlgApp*)AfxGetApp();
m_hMemFile = OpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,pApp->m_saArgv.GetAt(4));
if(m_hMemFile == NULL)
{
EndDialog(IDCANCEL);
return FALSE;
}
m_pData = (PROGRESSDLGDATA*)MapViewOfFile(m_hMemFile,FILE_MAP_ALL_ACCESS,0,0,0);
m_pData->hProgressDlgWnd = m_hWnd;
m_hWatchWnd = m_pData->hWatchWnd;
CenterWindow();
SetWindowPos(&CWnd::wndTopMost,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
m_CtlMsgTime.ShowWindow(SW_HIDE);
m_CtlMsg1.SetWindowText(_T(""));
m_CtlMsg2.SetWindowText(_T(""));
CMenu* pMenu = this->GetSystemMenu(FALSE);//系统菜单
pMenu->ModifyMenu(SC_CLOSE, MF_BYCOMMAND | MF_GRAYED );//禁用关闭按钮
if(_tcslen(m_pData->cMsg))
{
SplitMsg(m_pData->cMsg);
m_CtlMsg1.SetWindowText(m_sMsg1);
m_CtlMsg2.SetWindowText(m_sMsg2);
}
m_CtlProgress.SetRange( _ttoi( pApp->m_saArgv.GetAt(2)),
_ttoi( pApp->m_saArgv.GetAt(3)));
if(_ttoi(pApp->m_saArgv.GetAt(1)) != 1)
{
GetDlgItem(IDOK)->EnableWindow(FALSE);
}
m_CtlProgress.SetStep(1);
m_dwTickCount = GetTickCount();
SetTimer(1,400,NULL);
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
void CProgressDlg::OnOK()
{
// TODO: Add extra validation here
if(GetDlgItem(IDOK))
{
GetDlgItem(IDOK)->EnableWindow(FALSE);
}
m_bCanceled = TRUE;
}
void CProgressDlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CDialog::OnTimer(nIDEvent);
if(IsWindow(m_hWnd))
{
CRect rc;
GetWindowRect(&rc);
CWnd* pWnd = WindowFromPoint(rc.CenterPoint());
if(pWnd != this)
{
SetForegroundWindow();
SetWindowPos(&CWnd::wndTopMost,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
}
}
if(m_hWatchWnd && (IsWindow(m_hWatchWnd) == FALSE) )
{
KillTimer(nIDEvent);
//AfxMessageBox("对不起,程序发生错误:程序被强制终止(或异常退出)。");
EndDialog(IDOK);
}
}
BOOL CProgressDlg::DestroyWindow()
{
// TODO: Add your specialized code here and/or call the base class
if(m_hMemFile)
{
m_pData->hProgressDlgWnd = NULL;
}
return CDialog::DestroyWindow();
}
extern BOOL MyIsWindowVisible(HWND hWnd);
LRESULT CProgressDlg::OnMessage(WPARAM wParam,LPARAM lParam)
{
switch(wParam)
{
case MSGCODE_EXIT://关闭对话框
{
EndDialog(IDOK);
m_pData->hProgressDlgWnd = NULL;
if(IsWindow(m_hWatchWnd))
{
if(MyIsWindowVisible(m_hWatchWnd) == FALSE)
{
::SetForegroundWindow(m_hWatchWnd);
::SetWindowPos(m_hWatchWnd, HWND_TOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_SHOWWINDOW);
::SetWindowPos(m_hWatchWnd, HWND_NOTOPMOST,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
}
}
}
break;
case MSGCODE_SETPOS://改变进度
if(_tcslen(m_pData->cMsg))
{
SplitMsg(m_pData->cMsg);
m_CtlMsg1.SetWindowText(m_sMsg1);
m_CtlMsg2.SetWindowText(m_sMsg2);
}
m_CtlProgress.SetPos((int)lParam);
ShowTime();
break;
case MSGCODE_SETRANGE://改变范围
if(_tcslen(m_pData->cMsg))
{
SplitMsg(m_pData->cMsg);
m_CtlMsg1.SetWindowText(m_sMsg1);
m_CtlMsg2.SetWindowText(m_sMsg2);
}
m_CtlProgress.SetRange( (short)(lParam&0xFFFF), (short)((lParam&0xFFFF0000)>>16) );
m_dwTickCount = GetTickCount();
m_CtlMsgTime.ShowWindow(SW_HIDE);
break;
case MSGCODE_CHANGEENABLECANCELSTATE:
GetDlgItem(IDOK)->EnableWindow((BOOL)lParam);
break;
case MSGCODE_GETCANCELED:
return m_bCanceled;
break;
case MSGCODE_SETMAINWND:
m_hWatchWnd = (HWND)lParam;
break;
}
return 0;
}
void CProgressDlg::SplitMsg(LPCTSTR szMsg)
{
m_sMsg1 = _T("");
m_sMsg2 = _T("");
if(szMsg != NULL)
{
m_sMsg1 = szMsg;
}
int nPos;
nPos = m_sMsg1.Find(_T('\n'));
if(nPos != -1)
{
m_sMsg2 = m_sMsg1.Mid(nPos+1);
m_sMsg1 = m_sMsg1.Left(nPos);
}
}
void CProgressDlg::ShowTime()
{
if(GetTickCount() - m_dwTickCount < 1000)
{
return;
}
CString sMsg;
int nLower=0,nUpper=100;
int nTime,nHour,nMin,nSec;
m_CtlProgress.GetRange(nLower,nUpper);
if(nUpper == nLower)
{
return;
}
if(m_CtlProgress.GetPos() - nLower == 0)
{
return;
}
nTime = (int) ( (GetTickCount() - m_dwTickCount) * ((double)(nUpper-m_CtlProgress.GetPos())) / ((double)(m_CtlProgress.GetPos() - nLower)) );
nTime /= 1000;
nTime = abs(nTime);
nHour = nTime/3600;
nMin = (nTime/60)%60;
nSec = nTime%60;
if(nHour>0)
{
sMsg.Format(_T("剩余时间: %d 小时 %d 分钟"),nHour,nMin);
}
else if(nMin > 0)
{
sMsg.Format(_T("剩余时间: %d 分 %d 秒"),nMin,nSec);
}
else
{
sMsg.Format(_T("剩余时间: %d 秒"),nSec);
}
m_CtlMsgTime.SetWindowText(sMsg);
if(m_CtlMsgTime.IsWindowVisible() == FALSE)
{
m_CtlMsgTime.ShowWindow(SW_SHOW);
}
}
void CProgressDlg::OnClose()
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CDialog::OnClose();
}
使用过程:
CShowProgressDlg *pProgress = new CShowProgressDlg;
HWND hwnd = AfxGetApp()->GetMainWnd()->GetSafeHwnd();
progress->SetWatchWnd(hwnd);
progress->SetEnableCancel(TRUE);
pProgress->SetRange(_T("数据处理中..."), 0, (short int)vecExcelData.size());
for (unsigned int i = 0; i < vecExcelData.size(); i++)
{
pProgress->SetPos(_T(""), i);
}
pProgress->Close();
delete pProgress;
pProgress = NULL;