// cpp:
// ProgressWnd.cpp : implementation file
//
// Written by Chris Maunder (Chris.Maunder@cbr.clw.csiro.au)
// Copyright 1998.
//
// CProgressWnd is a drop-in popup progress window for use in
// programs that a time consuming. Check out the header file
// or the accompanying HTML doc file for details.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed by any means PROVIDING it is not sold for
// profit without the authors written consent, and providing that this
// notice and the authors name is included. If the source code in
// this file is used in any commercial application then an email to
// the me would be nice.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability if it causes any damage to your
// computer, causes your pet cat to fall ill, increases baldness or
// makes you car start emitting strange noises when you start it up.
//
// Expect bugs.
//
// Please use and enjoy. Please let me know of any bugs/mods/improvements
// that you have found/implemented and I will fix/incorporate them into this
// file.
#include "stdafx.h"
#include "ProgressWnd.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define IDC_CANCEL 10
#define IDC_TEXT 11
#define IDC_PROGRESS 12
/
// CProgressWnd
CProgressWnd::CProgressWnd()
{
CommonConstruct();
}
CProgressWnd::CProgressWnd(CWnd* pParent, LPCTSTR pszTitle, BOOL bSmooth /* = FALSE */)
{
CommonConstruct();
m_strTitle = pszTitle;
Create(pParent, pszTitle, bSmooth);
}
void CProgressWnd::CommonConstruct()
{
m_nNumTextLines = 4;
m_nPrevPos = 0;
m_nPrevPercent = 0;
m_nStep = 1;
m_nMinValue = 0;
m_nMaxValue = 100;
m_strTitle = _T("Progress");
m_bCancelled = FALSE;
m_bSuccess = FALSE;
}
CProgressWnd::~CProgressWnd()
{
DestroyWindow();
}
BOOL CProgressWnd::Create(CWnd* pParent, LPCTSTR pszTitle, BOOL bSmooth /* = FALSE */)
{
// Register window class
CString csClassName = AfxRegisterWndClass(CS_OWNDC|CS_HREDRAW|CS_VREDRAW,
::LoadCursor(NULL, IDC_APPSTARTING),
CBrush(::GetSysColor(COLOR_BTNFACE)));
// Get the system window message font for use in the cancel button and text area
NONCLIENTMETRICS ncm;
ncm.cbSize = sizeof(NONCLIENTMETRICS);
VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
m_font.CreateFontIndirect(&(ncm.lfMessageFont));
// If no parent supplied then try and get a pointer to it anyway
if (!pParent)
pParent = AfxGetMainWnd();
// Create popup window
m_bSuccess = CreateEx(WS_EX_DLGMODALFRAME, // Extended style
csClassName, // Classname
pszTitle, // Title
WS_POPUP|WS_BORDER|WS_CAPTION, // style
0,0, // position - updated soon.
390,130, // Size - updated soon
pParent->GetSafeHwnd(), // handle to parent
0, // No menu
NULL);
if (!m_bSuccess) return FALSE;
// Now create the controls
CRect TempRect(0,0,10,10);
m_bSuccess = m_Text.Create(_T(""), WS_CHILD|WS_VISIBLE|SS_NOPREFIX|SS_LEFTNOWORDWRAP, TempRect, this, IDC_TEXT);
if (!m_bSuccess) return FALSE;
DWORD dwProgressStyle = WS_CHILD|WS_VISIBLE;
#ifdef PBS_SMOOTH
if (bSmooth)
dwProgressStyle |= PBS_SMOOTH;
#endif
m_bSuccess = m_wndProgress.Create(dwProgressStyle, TempRect, this, IDC_PROGRESS);
if (!m_bSuccess) return FALSE;
m_bSuccess = m_CancelButton.Create(_T("Cancel"), WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON,
TempRect, this, IDC_CANCEL);
if (!m_bSuccess) return FALSE;
m_CancelButton.SetFont(&m_font, TRUE);
m_Text.SetFont(&m_font, TRUE);
// Resize the whole thing according to the number of text lines, desired window
// width and current font.
SetWindowSize(m_nNumTextLines, 390);
// Center and show window
CenterWindow();
Show();
return TRUE;
}
void CProgressWnd::SetWindowSize(int nNumTextLines, int nWindowWidth /*=390*/)
{
int nMargin = 10;
CRect TextRect, CancelRect, ProgressRect;
CSize CancelSize;
// Set up a default size for the text area in case things go wrong
TextRect.SetRect(nMargin,nMargin, nWindowWidth-2*nMargin, 100+2*nMargin);
// Get DrawText to tell us how tall the text area will be (while we're at
// it, we'll see how big the word "Cancel" is)
CDC* pDC = GetDC();
if (pDC) {
CFont* pOldFont = pDC->SelectObject(&m_font);
CString str = _T("M");
for (int i = 0; i < nNumTextLines-1; i++) str += _T("/nM");
pDC->DrawText(str, TextRect, DT_CALCRECT|DT_NOCLIP|DT_NOPREFIX);
TextRect.right = TextRect.left + nWindowWidth;
CancelSize = pDC->GetTextExtent(_T(" Cancel "))+CSize(8,6);
pDC->SelectObject(pOldFont);
ReleaseDC(pDC);
}
// Work out how big (and where) the cancel button should be
CancelRect.SetRect(TextRect.right-CancelSize.cx, TextRect.bottom+nMargin,
TextRect.right, TextRect.bottom+nMargin + CancelSize.cy);
// Work out how big (and where) the progress control should be
ProgressRect.SetRect(TextRect.left, TextRect.bottom+nMargin,
CancelRect.left-nMargin, CancelRect.bottom);
// Resize the main window to fit the controls
CSize ClientSize(nMargin + TextRect.Width() + nMargin,
nMargin + TextRect.Height() + nMargin + CancelRect.Height() + nMargin);
CRect WndRect, ClientRect;
GetWindowRect(WndRect); GetClientRect(ClientRect);
WndRect.right = WndRect.left + WndRect.Width()-ClientRect.Width()+ClientSize.cx;
WndRect.bottom = WndRect.top + WndRect.Height()-ClientRect.Height()+ClientSize.cy;
MoveWindow(WndRect);
// Now reposition the controls...
m_wndProgress.MoveWindow(ProgressRect);
m_CancelButton.MoveWindow(CancelRect);
m_Text.MoveWindow(TextRect);
}
void CProgressWnd::Clear()
{
SetText(_T(""));
SetPos(0);
m_bCancelled = FALSE;
m_nPrevPos = 0;
if (m_bSuccess)
UpdateWindow();
}
void CProgressWnd::Hide()
{
if (!m_bSuccess || !::IsWindow(GetSafeHwnd())) return;
Clear();
if (::GetWindowLong(GetSafeHwnd(), GWL_STYLE) & WS_VISIBLE)
{
ShowWindow(SW_HIDE);
ModifyStyle(WS_VISIBLE, 0);
}
}
void CProgressWnd::Show()
{
if (!m_bSuccess || !::IsWindow(GetSafeHwnd())) return;
if ((::GetWindowLong(GetSafeHwnd(), GWL_STYLE) & WS_VISIBLE) == 0)
{
ModifyStyle(0, WS_VISIBLE);
ShowWindow(SW_SHOWNA);
RedrawWindow(NULL,NULL,RDW_ERASE|RDW_FRAME|RDW_INVALIDATE);
}
}
void CProgressWnd::SetRange(int nLower, int nUpper, int nStep /* = 1 */)
{
if (!m_bSuccess) return;
// To take advantage of the Extended Range Values we use the PBM_SETRANGE32
// message intead of calling CProgressCtrl::SetRange directly. If this is
// being compiled under something less than VC 5.0, the necessary defines
// may not be available.
#ifdef PBM_SETRANGE32
ASSERT(-0x7FFFFFFF <= nLower && nLower <= 0x7FFFFFFF);
ASSERT(-0x7FFFFFFF <= nUpper && nUpper <= 0x7FFFFFFF);
m_wndProgress.SendMessage(PBM_SETRANGE32, (WPARAM) nLower, (LPARAM) nUpper);
#else
ASSERT(0 <= nLower && nLower <= 65535);
ASSERT(0 <= nUpper && nUpper <= 65535);
m_wndProgress.SetRange(nLower, nUpper);
#endif
m_nMaxValue = nUpper;
m_nMinValue = nLower;
m_nStep = nStep;
m_wndProgress.SetStep(nStep);
}
int CProgressWnd::OffsetPos(int nPos)
{
if (!m_bSuccess) return m_nPrevPos;
return SetPos(m_nPrevPos + nPos);
}
int CProgressWnd::StepIt()
{
if (!m_bSuccess) return m_nPrevPos;
return SetPos(m_nPrevPos + m_nStep);
}
int CProgressWnd::SetStep(int nStep)
{
int nOldStep = m_nStep;
m_nStep = nStep;
if (!m_bSuccess) return nOldStep;
return m_wndProgress.SetStep(nStep);
}
int CProgressWnd::SetPos(int nPos)
{
#ifdef PBM_SETRANGE32
ASSERT(-0x7FFFFFFF <= nPos && nPos <= 0x7FFFFFFF);
#else
ASSERT(0 <= nPos && nPos =< 65535);
#endif
if (!m_bSuccess) return m_nPrevPos;
CString strTitle;
int nPercentage;
m_nPrevPos = nPos;
if (m_nMaxValue > m_nMinValue)
nPercentage = (nPos*100)/(m_nMaxValue - m_nMinValue);
else
nPercentage = 0;
if (nPercentage != m_nPrevPercent)
{
m_nPrevPercent = nPercentage;
strTitle.Format(_T("%s [%d%%]"),m_strTitle,nPercentage);
SetWindowText(strTitle);
}
return m_wndProgress.SetPos(nPos);
}
void CProgressWnd::SetText(LPCTSTR fmt, ...)
{
if (!m_bSuccess) return;
va_list args;
TCHAR buffer[512];
va_start(args, fmt);
_vstprintf(buffer, fmt, args);
va_end(args);
m_Text.SetWindowText(buffer);
}
BEGIN_MESSAGE_MAP(CProgressWnd, CWnd)
//{{AFX_MSG_MAP(CProgressWnd)
ON_WM_ERASEBKGND()
//}}AFX_MSG_MAP
ON_BN_CLICKED(IDC_CANCEL, OnCancel)
END_MESSAGE_MAP()
/
// CProgressWnd message handlers
BOOL CProgressWnd::OnEraseBkgnd(CDC* pDC)
{
// Fill background with Catchment background colour
CBrush backBrush(GetSysColor(COLOR_BTNFACE));
CBrush* pOldBrush = pDC->SelectObject(&backBrush);
CRect rect;
pDC->GetClipBox(&rect); // Erase the area needed
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
pDC->SelectObject(pOldBrush);
return TRUE;
}
void CProgressWnd::OnCancel()
{
m_bCancelled = true;
}
// h:
// ProgressWnd.h : header file
//
// Written by Chris Maunder (Chris.Maunder@cbr.clw.csiro.au)
// Copyright 1998.
//
// CProgressWnd is a drop-in popup progress window for use in
// programs that a time consuming. Check out the accompanying HTML
// doc file for details.
//
// This code may be used in compiled form in any way you desire. This
// file may be redistributed by any means PROVIDING it is not sold for
// profit without the authors written consent, and providing that this
// notice and the authors name is included. If the source code in
// this file is used in any commercial application then an email to
// me would be nice.
//
// This file is provided "as is" with no expressed or implied warranty.
// The author accepts no liability if it causes any damage to your
// computer, causes your pet cat to fall ill, increases baldness or
// makes you car start emitting strange noises when you start it up.
//
// Expect bugs.
//
// Please use and enjoy. Please let me know of any bugs/mods/improvements
// that you have found/implemented and I will fix/incorporate them into this
// file.
#ifndef _INCLUDE_PROGRESSWND_H
#define _INCLUDE_PROGRESSWND_H
/
// CProgressWnd window
class CProgressWnd : public CWnd
{
// Construction/Destruction
public:
CProgressWnd();
CProgressWnd(CWnd* pParent, LPCTSTR pszTitle, BOOL bSmooth = FALSE);
virtual ~CProgressWnd();
BOOL Create(CWnd* pParent, LPCTSTR pszTitle, BOOL bSmooth = FALSE);
protected:
void CommonConstruct();
// Operations
public:
void SetRange(int nLower, int nUpper, int nStep = 1);
// Set range and step size
int OffsetPos(int nPos); // Same as CProgressCtrl
int StepIt(); // "
int SetStep(int nStep); // "
int SetPos(int nPos); // "
void SetText(LPCTSTR fmt, ...); // Set text in text area
void Clear(); // Clear text, reset bar
void Hide(); // Hide window
void Show(); // Show window
BOOL Success() { return m_bSuccess; } // Was the creation successful?
BOOL Cancelled() {return m_bCancelled == true;} // Was "Cancel" hit?
void SetWindowSize(int nNumTextLines, int nWindowWidth = 390);
// Implementation
protected:
BOOL m_bSuccess;
bool m_bCancelled;
int m_nPrevPos, m_nPrevPercent;
int m_nStep;
int m_nMaxValue, m_nMinValue;
int m_nNumTextLines;
CStatic m_Text;
CProgressCtrl m_wndProgress;
CButton m_CancelButton;
CString m_strTitle;
CFont m_font;
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CProgressWnd)
//}}AFX_VIRTUAL
// Generated message map functions
protected:
//{{AFX_MSG(CProgressWnd)
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
//}}AFX_MSG
afx_msg void OnCancel();
DECLARE_MESSAGE_MAP()
};
#endif
/
/使用:
#include "ProgressWnd.h"
void CMainFrame::OnTestSmoothbar()
{
CProgressWnd wndProgress(this, "Progress", TRUE);
wndProgress.SetRange(0,5000);
wndProgress.SetText("This is a progress window.../n/n"
"Try dragging it around or hitting Cancel.");
for (int i = 0; i < 5000; i++) {
wndProgress.StepIt();
PeekAndPump();
if (wndProgress.Cancelled()) {
MessageBox("Progress Cancelled");
break;
}
}
}
void CMainFrame::OnTestStdbar()
{
CProgressWnd wndProgress(this, "Progress");
wndProgress.SetRange(0,5000);
wndProgress.SetText("This is a progress window.../n/n"
"Try dragging it around or hitting Cancel.");
for (int i = 0; i < 5000; i++) {
wndProgress.StepIt();
PeekAndPump();
if (wndProgress.Cancelled()) {
MessageBox("Progress Cancelled");
break;
}
}
}