// ProgressWnd.cpp : implementation file // // Written by Chris Maunder ([email protected]) // 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 <[email protected]>) // 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" #include "resource.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 = 4; m_nPrevPos = 0; m_nPrevPercent = 0; m_nStep = 1; m_nMinValue = 0; m_nMaxValue = 100; m_strTitle.LoadString("进度条"); m_strCancelLabel.LoadString("取消"); 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; 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 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 (!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%%]"),m_strTitle,nPercentage); 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_s(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::OnCancelOk() { m_bCancelled = TRUE; Hide(); if (m_bModal) SendMessage(WM_CLOSE); CWnd *pWnd = AfxGetMainWnd(); if (pWnd && ::IsWindow(pWnd->m_hWnd)) pWnd->SetForegroundWindow(); } void CProgressWnd::OnCancel() { m_bCancelled = TRUE; } 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 <[email protected]> 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); } void CProgressWnd::MakebCancelFalse() { m_bCancelled=false; }
// ProgressWnd.h : header file // // Written by Chris Maunder ([email protected]) // 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); BOOL GoModal(LPCTSTR pszTitle =_T("Progress"), BOOL bSmooth = FALSE); protected: void CommonConstruct(); // Operations public: void MakebCancelFalse(); void SetRange(int nLower, int nUpper, int nStep = 1); void OnCancelOk() ; // 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 Cancelled() { return m_bCancelled; } // Was "Cancel" hit? void SetWindowSize(int nNumTextLines, int nWindowWidth = 390); void PeekAndPump(BOOL bCancelOnESCkey = TRUE); // Message pumping for modal operation // Implementation protected: void GetPreviousSettings(); void SaveCurrentSettings(); protected: BOOL m_bCancelled; BOOL m_bModal; BOOL m_bPersistantPosition; 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, m_strCancelLabel; CFont m_font; // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CProgressWnd) public: virtual BOOL DestroyWindow(); //}}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 /////////////////////////////////////////////////////////////////////////////