486 lines
14 KiB
C++
486 lines
14 KiB
C++
// ProgressWnd.cpp : implementation file
|
|
//
|
|
// Written by Chris Maunder (chrismaunder@codeguru.com)
|
|
// 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.
|
|
//
|
|
// Updated May 18 1998 - added PeekAndPump function to allow modal operation,
|
|
// with optional "Cancel on ESC" (Michael <mbh-ep@post5.tele.dk>)
|
|
// Nov 27 1998 - Removed modal stuff from PeekAndPump
|
|
// Dec 18 1998 - added WS_EX_TOPMOST to the creation flag
|
|
|
|
|
|
#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
|
|
|
|
LPCTSTR szSection = _T("Settings");
|
|
LPCTSTR szEntryX = _T("X");
|
|
LPCTSTR szEntryY = _T("Y");
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// 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 = 2;
|
|
m_nPrevPos = 0;
|
|
m_nPrevPercent = 0;
|
|
m_nStep = 1;
|
|
m_nMinValue = 0;
|
|
m_nMaxValue = 100;
|
|
|
|
m_strTitle = _T("入库进行中...");
|
|
m_strCancelLabel = _T(" 取消 ");
|
|
m_bCancelled = FALSE;
|
|
m_bModal = FALSE;
|
|
|
|
m_bPersistantPosition = TRUE; // saves and restores position automatically
|
|
}
|
|
|
|
CProgressWnd::~CProgressWnd()
|
|
{
|
|
DestroyWindow();
|
|
}
|
|
|
|
BOOL CProgressWnd::Create(CWnd* pParent, LPCTSTR pszTitle, BOOL bSmooth /* = FALSE */)
|
|
{
|
|
BOOL bSuccess;
|
|
|
|
// 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;
|
|
|
|
//modify by xlc on 090902 R18添加菜单崩溃
|
|
#if ADS<18
|
|
ncm.cbSize = sizeof (NONCLIENTMETRICS);
|
|
#else
|
|
ncm.cbSize = sizeof(NONCLIENTMETRICS) - sizeof(ncm.iPaddedBorderWidth);
|
|
#endif
|
|
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
|
|
bSuccess = CreateEx(WS_EX_DLGMODALFRAME|WS_EX_TOPMOST, // Extended style
|
|
csClassName, // Classname
|
|
pszTitle, // Title
|
|
WS_POPUP|WS_BORDER|WS_CAPTION, // style
|
|
0,0, // position - updated soon.
|
|
390,80, // Size - updated soon
|
|
pParent->GetSafeHwnd(), // handle to parent
|
|
0, // No menu
|
|
NULL);
|
|
if (!bSuccess) return FALSE;
|
|
|
|
// Now create the controls
|
|
CRect TempRect(0,0,10,10);
|
|
|
|
bSuccess = m_Text.Create(_T(""), WS_CHILD|WS_VISIBLE|SS_NOPREFIX|SS_LEFTNOWORDWRAP,
|
|
TempRect, this, IDC_TEXT);
|
|
if (!bSuccess) return FALSE;
|
|
|
|
DWORD dwProgressStyle = WS_CHILD|WS_VISIBLE;
|
|
#ifdef PBS_SMOOTH
|
|
if (bSmooth)
|
|
dwProgressStyle |= PBS_SMOOTH;
|
|
#endif
|
|
bSuccess = m_wndProgress.Create(dwProgressStyle, TempRect, this, IDC_PROGRESS);
|
|
if (!bSuccess) return FALSE;
|
|
|
|
bSuccess = m_CancelButton.Create(m_strCancelLabel,
|
|
WS_CHILD|WS_VISIBLE|WS_TABSTOP| BS_PUSHBUTTON,
|
|
TempRect, this, IDC_CANCEL);
|
|
if (!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
|
|
if (m_bPersistantPosition)
|
|
GetPreviousSettings();
|
|
else
|
|
CenterWindow();
|
|
|
|
Show();
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CProgressWnd::GoModal(LPCTSTR pszTitle /*=_T("Progress")"*/, BOOL bSmooth /*=FALSE*/)
|
|
{
|
|
CWnd *pMainWnd = AfxGetMainWnd();
|
|
|
|
if (!::IsWindow(m_hWnd) && !Create(pMainWnd, pszTitle, bSmooth))
|
|
return FALSE;
|
|
|
|
// Disable main window
|
|
if (pMainWnd)
|
|
pMainWnd->EnableWindow(FALSE);
|
|
|
|
// Re-enable this window
|
|
EnableWindow(TRUE);
|
|
|
|
m_bModal = TRUE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CProgressWnd::SetWindowSize(int nNumTextLines, int nWindowWidth /*=390*/)
|
|
{
|
|
int nMargin = 10;
|
|
CSize EdgeSize(::GetSystemMetrics(SM_CXEDGE), ::GetSystemMetrics(SM_CYEDGE));
|
|
|
|
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(m_strCancelLabel + _T(" ")) +
|
|
CSize(EdgeSize.cx*4, EdgeSize.cy*3);
|
|
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, CancelRect.top + EdgeSize.cy,
|
|
CancelRect.left-nMargin, CancelRect.bottom - EdgeSize.cy);
|
|
|
|
|
|
// 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 (::IsWindow(GetSafeHwnd()))
|
|
UpdateWindow();
|
|
}
|
|
|
|
void CProgressWnd::Hide()
|
|
{
|
|
if (!::IsWindow(GetSafeHwnd()))
|
|
return;
|
|
|
|
if (IsWindowVisible())
|
|
{
|
|
ShowWindow(SW_HIDE);
|
|
ModifyStyle(WS_VISIBLE, 0);
|
|
}
|
|
}
|
|
|
|
void CProgressWnd::Show()
|
|
{
|
|
if (!::IsWindow(GetSafeHwnd()))
|
|
return;
|
|
|
|
if (!IsWindowVisible())
|
|
{
|
|
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 (!::IsWindow(GetSafeHwnd()))
|
|
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 (!::IsWindow(GetSafeHwnd()))
|
|
return m_nPrevPos;
|
|
|
|
Show();
|
|
|
|
return SetPos(m_nPrevPos + nPos);
|
|
}
|
|
|
|
int CProgressWnd::StepIt()
|
|
{
|
|
if (!::IsWindow(GetSafeHwnd()))
|
|
return m_nPrevPos;
|
|
|
|
Show();
|
|
|
|
return SetPos(m_nPrevPos + m_nStep);
|
|
}
|
|
|
|
int CProgressWnd::SetStep(int nStep)
|
|
{
|
|
int nOldStep = m_nStep;
|
|
m_nStep = nStep;
|
|
if (!::IsWindow(GetSafeHwnd()))
|
|
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 (!::IsWindow(GetSafeHwnd()))
|
|
return m_nPrevPos;
|
|
|
|
Show();
|
|
|
|
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%%]"), (const TCHAR *)m_strTitle,nPercentage); // ZJQ modify here
|
|
SetWindowText(strTitle);
|
|
}
|
|
return m_wndProgress.SetPos(nPos);
|
|
}
|
|
|
|
void CProgressWnd::SetText(LPCTSTR fmt, ...)
|
|
{
|
|
if (!::IsWindow(GetSafeHwnd()))
|
|
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;
|
|
Hide();
|
|
|
|
if (m_bModal)
|
|
SendMessage(WM_CLOSE);
|
|
|
|
CWnd *pWnd = AfxGetMainWnd();
|
|
if (pWnd && ::IsWindow(pWnd->m_hWnd))
|
|
pWnd->SetForegroundWindow();
|
|
}
|
|
|
|
|
|
BOOL CProgressWnd::DestroyWindow()
|
|
{
|
|
if (m_bPersistantPosition)
|
|
SaveCurrentSettings();
|
|
|
|
if (m_bModal)
|
|
{
|
|
m_bModal = FALSE;
|
|
CWnd *pMainWnd = AfxGetMainWnd();
|
|
|
|
if (pMainWnd)
|
|
pMainWnd->EnableWindow(TRUE);
|
|
}
|
|
|
|
return CWnd::DestroyWindow();
|
|
}
|
|
|
|
// Message pumping function that can either be used to pump messages during
|
|
// long operations. This version will only pass messages to this window (and
|
|
// all child windows). (Thanks to Michael <mbh-ep@post5.tele.dk> for this)
|
|
void CProgressWnd::PeekAndPump(BOOL bCancelOnESCkey /*= TRUE*/)
|
|
{
|
|
if (m_bModal && ::GetFocus() != m_hWnd)
|
|
SetFocus();
|
|
|
|
MSG msg;
|
|
while (!m_bCancelled && ::PeekMessage(&msg, NULL,0,0,PM_NOREMOVE))
|
|
{
|
|
if (bCancelOnESCkey && (msg.message == WM_CHAR) && (msg.wParam == VK_ESCAPE))
|
|
OnCancel();
|
|
|
|
// Cancel button disabled if modal, so we fake it.
|
|
if (m_bModal && (msg.message == WM_LBUTTONUP))
|
|
{
|
|
CRect rect;
|
|
m_CancelButton.GetWindowRect(rect);
|
|
if (rect.PtInRect(msg.pt))
|
|
OnCancel();
|
|
}
|
|
|
|
if (!AfxGetApp()->PumpMessage())
|
|
{
|
|
::PostQuitMessage(0);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Retores the previous window size from the registry
|
|
void CProgressWnd::GetPreviousSettings()
|
|
{
|
|
int x = AfxGetApp()->GetProfileInt(szSection, szEntryX, -1);
|
|
int y = AfxGetApp()->GetProfileInt(szSection, szEntryY, -1);
|
|
|
|
if (x >= 0 && x < GetSystemMetrics(SM_CXSCREEN) &&
|
|
y >= 0 && y < GetSystemMetrics(SM_CYSCREEN))
|
|
{
|
|
SetWindowPos(NULL, x,y, 0,0, SWP_NOSIZE|SWP_NOZORDER);
|
|
}
|
|
else
|
|
CenterWindow();
|
|
}
|
|
|
|
// Saves the current window position registry
|
|
void CProgressWnd::SaveCurrentSettings()
|
|
{
|
|
if (!IsWindow(m_hWnd))
|
|
return;
|
|
|
|
CRect rect;
|
|
GetWindowRect(rect);
|
|
|
|
AfxGetApp()->WriteProfileInt(szSection, szEntryX, rect.left);
|
|
AfxGetApp()->WriteProfileInt(szSection, szEntryY, rect.top);
|
|
} |