📄 kcbusyprogressctrl.cpp
字号:
/****************************************************************************
* class : CKCBusyProgressCtrl
* author : Peter Mares / kinkycode.com (gui@ch.co.za)
* base class : CStatic (MFC)
* notes : Control to be used for progress indication when there are
* no lower and upper bounds available for a progress bar.
* Can also be used as a normal progress bar
*
* Disclaimer : Its free, it feels good and its from South Africa :)
****************************************************************************
* Version History:
*
* v0.1 (2003-04-21)
*
* - First public release
*
* v0.2 (2003-04-22)
*
* - Added support for WM_SYSCOLORCHANGE
* - Added flag for whether background colour was a system colour (true by default)
* - Modified ON_MESSAGE handlers to return LRESULT instead of void for
* VC++.NET compatibility
* - Added "Busy Type" flag to support different motion while in busy mode.
* Current modes supported are : BPC_BUSY_PINGPONG
* BPC_BUSY_LTR (left to right)
* BPC_BUSY_RTL (right to left)
* - Added "Busy Fill" flag to support different filling methods while in
* busy mode.
* Current modes supported are : BPC_BUSYFILL_BLOCK (block filling)
* BPC_BUSYFILL_SMOOTH (smooth filling)
* - Fixed bug in percentage fill calculation
*
* v0.21 (2003-04-30)
*
* - Fixed a threading bug (identified by Mark Richards - thanks)
*
* v0.3 (2003-05-02)
*
* - Added the outstanding BPM_XXXXX Messages and handlers to the control
*
****************************************************************************/
#include "stdafx.h"
#include "KCBusyProgressCtrl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CKCBusyProgressCtrl
CKCBusyProgressCtrl::CKCBusyProgressCtrl(int nNumSteps, int nCurPos)
: m_nNumSteps(nNumSteps)
, m_nStep(1)
, m_nCurPos(nCurPos)
, m_colBkg( GetSysColor( COLOR_BTNFACE ) )
, m_colBlockFace( RGB(160, 190, 220) )
, m_colBlockEdge( RGB(50, 90, 135) )
, m_colBlockFaceHi( RGB(190, 220, 255) )
, m_colBlockEdgeHi( RGB(50, 90, 135) )
, m_pOldBmp(NULL)
, m_nIBPadding(1)
, m_rect(0,0,0,0)
, m_dBlockHeight(0.0L)
, m_dBlockWidth(0.0L)
, m_bBusyThrd(false)
, m_pThrd(NULL)
, m_nSpeed(100)
, m_nMode(BPC_MODE_BUSY)
, m_nLower(0)
, m_nUpper(100)
, m_bUseSysColBkg(true)
, m_nBusyType(BPC_BUSY_PINGPONG)
, m_nBusyFill(BPC_BUSYFILL_BLOCK)
, m_nGranularity(5)
, m_nNumStepsSmooth( m_nNumSteps * m_nGranularity )
{
}
/////////////////////////////////////////////////////////////////////////////
CKCBusyProgressCtrl::~CKCBusyProgressCtrl()
{
if ( m_pOldBmp )
{
m_memDC.SelectObject(m_pOldBmp);
m_memBmp.DeleteObject();
m_memDC.DeleteDC();
}
}
/////////////////////////////////////////////////////////////////////////////
BEGIN_MESSAGE_MAP(CKCBusyProgressCtrl, CStatic)
//{{AFX_MSG_MAP(CKCBusyProgressCtrl)
ON_WM_PAINT()
ON_WM_SIZE()
ON_WM_SYSCOLORCHANGE()
//}}AFX_MSG_MAP
ON_MESSAGE(BPM_SETNUMSTEPS, OnSetNumSteps)
ON_MESSAGE(BPM_SETCURPOS, OnSetCurPos)
ON_MESSAGE(BPM_SETIBPAD, OnSetIBPad)
ON_MESSAGE(BPM_SETSPEED, OnSetSpeed)
ON_MESSAGE(BPM_SETRANGE, OnSetRange)
ON_MESSAGE(BPM_SETMODE, OnSetMode)
ON_MESSAGE(BPM_STARTBUSY, OnStartBusy)
ON_MESSAGE(BPM_ENDBUSY, OnEndBusy)
ON_MESSAGE(BPM_STEPIT, OnStepIt)
// new in version 0.3
ON_MESSAGE(BPM_SETBUSYTYPE, OnSetBusyType)
ON_MESSAGE(BPM_SETBUSYFILL, OnSetBusyFill)
ON_MESSAGE(BPM_SETGRANULARITY, OnSetGranularity)
ON_MESSAGE(BPM_SETCOLBKG, OnSetColBkg)
ON_MESSAGE(BPM_SETCOLBFACE, OnSetColBFace)
ON_MESSAGE(BPM_SETCOLBEDGE, OnSetColBEdge)
ON_MESSAGE(BPM_SETCOLBFACEHI, OnSetColBFaceHi)
ON_MESSAGE(BPM_SETCOLBEDGEHI, OnSetColBEdgeHi)
ON_MESSAGE(BPM_RECALC, OnRecalc)
ON_MESSAGE(BPM_RESET, OnReset)
ON_MESSAGE(BPM_USESYSCOL, OnUseSysCol)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CKCBusyProgressCtrl message handlers
void CKCBusyProgressCtrl::PreSubclassWindow()
{
DWORD dwStyle = GetStyle();
// dwStyle |= SS_OWNERDRAW;
CStatic::PreSubclassWindow();
Recalc();
}
/////////////////////////////////////////////////////////////////////////////
BOOL CKCBusyProgressCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
{
BOOL bResult = CWnd::Create(_T("STATIC"), _T("BusyProgressCtrl"), dwStyle, rect, pParentWnd, nID, pContext);
Recalc();
return bResult;
}
/////////////////////////////////////////////////////////////////////////////
// function : Recalc()
// description : Function used to recalculate the block sizes and
// optionally get the current client area
/////////////////////////////////////////////////////////////////////////////
void CKCBusyProgressCtrl::Recalc()
{
if ( m_rect.IsRectEmpty() )
GetClientRect(&m_rect);
CRect tRect = m_rect;
tRect.right -= (m_nNumSteps * m_nIBPadding);
m_dBlockWidth = ((double)tRect.Width() / (double)m_nNumSteps);
m_dBlockHeight = tRect.Height();
}
/////////////////////////////////////////////////////////////////////////////
void CKCBusyProgressCtrl::OnPaint()
{
CPaintDC dc(this); // device context for painting
// create a memory dc if needs be
if ( !m_memDC.m_hDC )
{
m_memDC.CreateCompatibleDC(&dc);
m_memBmp.CreateCompatibleBitmap(&dc, m_rect.Width(), m_rect.Height());
m_pOldBmp = m_memDC.SelectObject(&m_memBmp);
}
DrawBackground(m_memDC, m_rect);
DrawBlocks(m_memDC, m_rect);
// render the final image
dc.BitBlt(0, 0, m_rect.Width(), m_rect.Height(), &m_memDC, 0, 0, SRCCOPY);
}
/////////////////////////////////////////////////////////////////////////////
void CKCBusyProgressCtrl::DrawBackground(CDC& dc, CRect& rect)
{
dc.FillSolidRect( &rect, m_colBkg );
}
/////////////////////////////////////////////////////////////////////////////
void CKCBusyProgressCtrl::DrawBlocks(CDC& dc, CRect& rect)
{
CRect bRect;
double dXOffset = 0;
int i;
CPen nPen, *pOldPen = NULL;
CBrush nBrush, *pOldBrush = NULL;
// create some drawing tools
nPen.CreatePen( PS_SOLID, 0, m_colBlockEdge );
nBrush.CreateSolidBrush( m_colBlockFace );
pOldPen = dc.SelectObject(&nPen);
pOldBrush = dc.SelectObject(&nBrush);
// create the initial rectangle
bRect.top = 0; bRect.bottom = (int) m_dBlockHeight;
bRect.left = 0; bRect.right = (int) m_dBlockWidth;
for ( i = 0; i < m_nNumSteps; i++ )
{
if ( m_nMode & BPC_MODE_BUSY )
{
switch ( m_nBusyFill )
{
case BPC_BUSYFILL_BLOCK:
{
if ( i == m_nCurPos )
DrawHiliteBlock(dc, bRect);
else
DrawBlock(dc, bRect);
}
break;
case BPC_BUSYFILL_SMOOTH:
{
double dDiff = (double)m_nNumStepsSmooth;
double dPerc = ((double) m_nCurPos / dDiff);
int nFull = (int) (dPerc*(double)m_nNumSteps)-1;
double dPerc2 = (((dPerc * (double)m_nNumSteps)-1) - nFull);
int nPartial = (int)(m_dBlockWidth * dPerc2);
if ( i <= nFull )
DrawHiliteBlock(dc, bRect);
else
{
DrawBlock(dc, bRect);
if ( i == nFull + 1 && nPartial )
DrawPartialBlock(dc, bRect, nPartial);
}
}
break;
}
}
else if ( m_nMode & BPC_MODE_PROGRESS )
{
double dDiff = (double)(m_nUpper - m_nLower);
double dPerc = ((double) m_nCurPos / dDiff);
int nFull = (int) (dPerc*(double)m_nNumSteps)-1;
double dPerc2 = (((dPerc * (double)m_nNumSteps)-1) - nFull);
int nPartial = (int)(m_dBlockWidth * dPerc2);
if ( i <= nFull )
DrawHiliteBlock(dc, bRect);
else
{
DrawBlock(dc, bRect);
if ( i == nFull + 1 && nPartial )
DrawPartialBlock(dc, bRect, nPartial);
}
}
// offset the rectangle a bit
dXOffset += m_dBlockWidth + (double) m_nIBPadding;
bRect.left = (int) dXOffset;
bRect.right = (int)(dXOffset + m_dBlockWidth);
}
// cleanup after ourselves...
dc.SelectObject(pOldPen);
dc.SelectObject(pOldBrush);
nPen.DeleteObject();
nBrush.DeleteObject();
}
/////////////////////////////////////////////////////////////////////////////
void CKCBusyProgressCtrl::DrawBlock(CDC& dc, CRect& rect)
{
dc.Rectangle(&rect);
}
/////////////////////////////////////////////////////////////////////////////
void CKCBusyProgressCtrl::DrawHiliteBlock(CDC& dc, CRect& rect)
{
CPen nPen, *pOldPen = NULL;
CBrush nBrush, *pOldBrush = NULL;
// use the correct tools ;)
nPen.CreatePen( PS_SOLID, 0, m_colBlockEdgeHi );
nBrush.CreateSolidBrush( m_colBlockFaceHi );
pOldPen = dc.SelectObject(&nPen);
pOldBrush = dc.SelectObject(&nBrush);
// draw the block
dc.Rectangle(&rect);
// cleanup
dc.SelectObject(pOldPen);
dc.SelectObject(pOldBrush);
nPen.DeleteObject();
nBrush.DeleteObject();
}
/////////////////////////////////////////////////////////////////////////////
void CKCBusyProgressCtrl::DrawPartialBlock(CDC& dc, CRect& rect, int nPartial)
{
CRect pRect = rect;
pRect.DeflateRect(1, 1);
pRect.right = pRect.left + nPartial;
if ( pRect.right >= rect.right )
pRect.right = rect.right - 1;
dc.FillSolidRect(&pRect, m_colBlockFaceHi);
}
/////////////////////////////////////////////////////////////////////////////
void CKCBusyProgressCtrl::OnSize(UINT nType, int cx, int cy)
{
CStatic::OnSize(nType, cx, cy);
GetClientRect(&m_rect);
if ( m_memDC.m_hDC )
{
// delete the dc to allow OnPaint to recreate the DC for the new size
m_memDC.SelectObject(m_pOldBmp);
m_memBmp.DeleteObject();
m_memDC.DeleteDC();
}
}
/////////////////////////////////////////////////////////////////////////////
void CKCBusyProgressCtrl::StepIt()
{
int nNumSteps = 0;
if ( m_nMode & BPC_MODE_BUSY)
{
switch ( m_nBusyFill )
{
case BPC_BUSYFILL_BLOCK:
nNumSteps = m_nNumSteps;
break;
case BPC_BUSYFILL_SMOOTH:
nNumSteps = m_nNumStepsSmooth;
break;
}
switch ( m_nBusyType )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -