进度条窗口的设计与使用

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;

你可能感兴趣的:(MFC,进度条窗口)