http://www.codeproject.com/Articles/4850/CBitmapSlider
试用了很多slider 发现这个还是最稳定 最给力的
相对于作者给出的代码 做了如下修改:
1:添加滚轮事件
2:添加EnableWindow的函数:EnableEx
代码如下:
#ifndef _MEMDC_H_
#define _MEMDC_H_
//////////////////////////////////////////////////
// CMemDC_flicker_free - memory DC
//
// Author: Keith Rule
// Email: keithr@europa.com
// Copyright 1996-2002, Keith Rule
//
// You may freely use or modify this code provided this
// Copyright is included in all derived versions.
//
// History - 10/3/97 Fixed scrolling bug.
// Added print support. - KR
//
// 11/3/99 Fixed most common complaint. Added
// background color fill. - KR
//
// 11/3/99 Added support for mapping modes other than
// MM_TEXT as suggested by Lee Sang Hun. - KR
//
// 02/11/02 Added support for CScrollView as supplied
// by Gary Kirkham. - KR
//
// This class implements a memory Device Context which allows
// flicker free drawing.
//
//
// I made a few changes to support transparency effect
//
// Line 44 : Added bBg parameter.
// Line 83 ~ 87 : If bBg is TRUE, copy background.
//
class CMemDC_flicker_free : public CDC
{
private:
CBitmap m_bitmap; // Offscreen bitmap
CBitmap* m_oldBitmap; // bitmap originally found in CMemDC_flicker_free
CDC* m_pDC; // Saves CDC passed in constructor
CRect m_rect; // Rectangle of drawing area.
BOOL m_bMemDC; // TRUE if CDC really is a Memory DC.
public:
CMemDC_flicker_free(CDC* pDC, const CRect* pRect = NULL, BOOL bBg = FALSE) : CDC()
{
ASSERT(pDC != NULL);
// Some initialization
m_pDC = pDC;
m_oldBitmap = NULL;
m_bMemDC = !pDC->IsPrinting();
// Get the rectangle to draw
if (pRect == NULL) {
pDC->GetClipBox(&m_rect);
} else {
m_rect = *pRect;
}
if (m_bMemDC) {
// Create a Memory DC
CreateCompatibleDC(pDC);
pDC->LPtoDP(&m_rect);
m_bitmap.CreateCompatibleBitmap(pDC, m_rect.Width(), m_rect.Height());
m_oldBitmap = SelectObject(&m_bitmap);
SetMapMode(pDC->GetMapMode());
SetWindowExt(pDC->GetWindowExt());
SetViewportExt(pDC->GetViewportExt());
pDC->DPtoLP(&m_rect);
SetWindowOrg(m_rect.left, m_rect.top);
} else {
// Make a copy of the relevent parts of the current DC for printing
m_bPrinting = pDC->m_bPrinting;
m_hDC = pDC->m_hDC;
m_hAttribDC = pDC->m_hAttribDC;
}
// Fill background
if( bBg )
BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
m_pDC, m_rect.left, m_rect.top, SRCCOPY);
else
FillSolidRect(m_rect, pDC->GetBkColor());
}
~CMemDC_flicker_free()
{
if (m_bMemDC) {
// Copy the offscreen bitmap onto the screen.
m_pDC->BitBlt(m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),
this, m_rect.left, m_rect.top, SRCCOPY);
//Swap back the original bitmap.
SelectObject(m_oldBitmap);
} else {
// All we need to do is replace the DC with an illegal value,
// this keeps us from accidently deleting the handles associated with
// the CDC that was passed to the constructor.
m_hDC = m_hAttribDC = NULL;
}
}
// Allow usage as a pointer
CMemDC_flicker_free* operator->()
{
return this;
}
// Allow usage as a pointer
operator CMemDC_flicker_free*()
{
return this;
}
};
#endif
#if !defined(AFX_BITMAPSLIDER_H__BED36788_B60C_4C9E_AC56_FE430B93A0FD__INCLUDED_)
#define AFX_BITMAPSLIDER_H__BED36788_B60C_4C9E_AC56_FE430B93A0FD__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// BitmapSlider.h : header file
//
/////////////////////////////////////////////////////////////////////////////
//
// CBitmapSlider v1.5
//
// It's free for everywhere - 16/September/2003 - Joon-ho Ryu
//
/////////////////////////////////////////////////////////////////////////////
#include "memdc.h" // "Flicker Free Drawing In MFC" by Keith Rule
#define WM_BITMAPSLIDER_MOVING WM_USER + 9425
#define WM_BITMAPSLIDER_MOVED WM_USER + 9426
class CBitmapSlider : public CStatic
{
// Construction
public:
CBitmapSlider();
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CBitmapSlider)
//}}AFX_VIRTUAL
// Implementation
public:
void GetRange( int &nMin, int &nMax ) { nMin = m_nMin; nMax = m_nMax; };
int GetRangeMax() { return m_nMax; };
int GetRangeMin() { return m_nMin; };
int GetPos() { return m_nPos; };
void SetRange( int nMin, int nMax, BOOL bRedraw=FALSE );
void SetRangeMin(int nMin, BOOL bRedraw = FALSE);
void SetRangeMax( int nMax, BOOL bRedraw = FALSE );
void SetPos( int nPos );
int SetPageSize( int nSize );
BOOL SetBitmapChannel(
UINT nChannelID, UINT nActiveID=NULL, BOOL bTransparent=FALSE,
COLORREF clrpTransColor=0xFF000000, int iTransPixelX=0, int iTransPixelY=0 );
BOOL SetBitmapThumb(
UINT nThumbID, UINT nActiveID=NULL, BOOL bTransparent=FALSE,
COLORREF clrpTransColor=0xFF000000, int iTransPixelX=0, int iTransPixelY=0 );
void SetMargin( int nLeft, int nTop, int nRight, int nBottom );
void SetMarginTop( int nMargin ) { m_nMarginTop = nMargin; };
void SetMarginLeft( int nMargin ) { m_nMarginLeft = nMargin; };
void SetMarginRight( int nMargin ) { m_nMarginRight = nMargin; };
void SetMarginBottom( int nMargin ) { m_nMarginBottom = nMargin; };
void SetVertical( BOOL bVertical=TRUE ) { m_bVertical = bVertical; };
void Enable(BOOL bEnable = TRUE);
void EnableEx(BOOL bEnable = TRUE);
void DrawFocusRect( BOOL bDraw = TRUE, BOOL bRedraw = FALSE );
virtual ~CBitmapSlider();
// Generated message map functions
protected:
void RestoreBackground(
CDC *pDC, int nXDst, int nYDst, int nWidth, int nHeight, CBitmap *pBmSrc);
void CopyBackground(
CDC *pDC, int nXSrc, int nYSrc, int nWidth, int nHeight, CBitmap *pBmDst );
void DrawBitmap(
CDC* pDC, int xStart, int yStart, int wWidth, int wHeight,
CDC* pTmpDC, int xSource, int ySource,
CBitmap *bmMask = NULL, BOOL bTransparent = FALSE );
void DrawTransparentBitmap(
CDC* pDC, int xStart, int yStart, int wWidth, int wHeight,
CDC* pTmpDC, int xSource, int ySource, CBitmap *bmMask );
void PrepareMask(
CBitmap* pBmpSource, CBitmap* pBmpMask,
COLORREF clrpTransColor=0xFF000000, int iTransPixelX=0, int iTransPixelY=0 );
int Pixel2Pos( int nPixel );
int Pos2Pixel( int nPos );
int m_nMax, m_nMin, m_nPos, m_nPage;
CRect m_rect;
int m_nWidth, m_nHeight;
int m_nThumbWidth, m_nThumbHeight;
int m_nMarginLeft, m_nMarginRight, m_nMarginTop, m_nMarginBottom;
int m_nThumbBgX, m_nThumbBgY;
int m_nMouseOffset;
BOOL m_bVertical;
BOOL m_bChannelActive, m_bThumbActive;
BOOL m_bTransparentChannel, m_bTransparentThumb, m_bThumb, m_bChannel;
BOOL m_bLButtonDown, m_bFocus, m_bFocusRect, m_bDrawFocusRect;
BOOL m_bEnable;
BOOL m_bEnableEx;
CBitmap m_bmChannel, m_bmChannelMask, m_bmChannelActive, m_bmChannelActiveMask;
CBitmap m_bmThumb, m_bmThumbMask, m_bmThumbActive, m_bmThumbActiveMask, m_bmThumbBg;
//{{AFX_MSG(CBitmapSlider)
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnPaint();
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg UINT OnGetDlgCode();
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
afx_msg void OnKillFocus(CWnd* pNewWnd);
afx_msg void OnSetFocus(CWnd* pOldWnd);
afx_msg void OnDestroy();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
private:
// This is CStatic method
void SetBitmap( HBITMAP /*hBitmap*/ ) {};
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_BITMAPSLIDER_H__BED36788_B60C_4C9E_AC56_FE430B93A0FD__INCLUDED_)
// BitmapSlider.cpp : implementation file
//
#include "stdafx.h"
#include "BitmapSlider.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
//
// CBitmapSlider v1.5
//
// It's free for everywhere - 16/September/2003 - Joon-ho Ryu
//
/////////////////////////////////////////////////////////////////////////////
CBitmapSlider::CBitmapSlider()
{
m_nPos = m_nMin = 0;
m_nMax = 100;
m_nPage = 20;
m_nMarginLeft = m_nMarginRight = m_nMarginTop = m_nMarginBottom = 0;
m_nThumbWidth = m_nThumbHeight = 0;
m_bChannel = m_bVertical = m_bThumb = m_bLButtonDown = FALSE;
m_bFocusRect = m_bFocus = FALSE;
m_bDrawFocusRect = TRUE;
m_bEnable = TRUE;
m_bEnableEx = TRUE;
m_nThumbBgX = m_nThumbBgY = -1;
}
CBitmapSlider::~CBitmapSlider()
{
}
BEGIN_MESSAGE_MAP(CBitmapSlider, CStatic)
//{{AFX_MSG_MAP(CBitmapSlider)
ON_WM_ERASEBKGND()
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
ON_WM_MOUSEWHEEL()
ON_WM_LBUTTONUP()
ON_WM_GETDLGCODE()
ON_WM_KEYDOWN()
ON_WM_KILLFOCUS()
ON_WM_SETFOCUS()
ON_WM_CREATE()
ON_WM_DESTROY()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CBitmapSlider message handlers
BOOL CBitmapSlider::OnEraseBkgnd(CDC* /*pDC*/)
{
// Do not erase background for the transparency effect
return TRUE;
}
// Draw channel and thumb
//
void CBitmapSlider::OnPaint()
{
CPaintDC dcOrigin(this);
// "Flicker Free Drawing In MFC" by Keith Rule
CMemDC_flicker_free dc( &dcOrigin, &m_rect, m_bTransparentChannel );
CDC dcMem;
dcMem.CreateCompatibleDC( &dc );
CBitmap *pbmTmp;
// Delete focus rectangle for transparent channel
if( m_bFocusRect && ( m_bTransparentChannel || !m_bChannel ) ) {
dc.DrawFocusRect( m_rect );
m_bFocusRect = FALSE;
}
// Draw channel
if( m_bChannel ) {
pbmTmp = dcMem.SelectObject( &m_bmChannel );
// There is a bitmap for active channel
if( m_bChannelActive && m_bEnable ) {
// Vertical slider
if( m_bVertical ) {
// Lower part
DrawBitmap( &dc, 0, Pos2Pixel(m_nPos),
m_nWidth, m_nHeight - Pos2Pixel(m_nPos),
&dcMem, 0, Pos2Pixel(m_nPos),
&m_bmChannelActiveMask, m_bTransparentChannel );
dcMem.SelectObject( &m_bmChannelActive );
// Upper part
DrawBitmap( &dc, 0, 0, m_nWidth, Pos2Pixel(m_nPos),
&dcMem, 0, 0, &m_bmChannelMask, m_bTransparentChannel );
// Horizontal slider
} else {
// Right side
DrawBitmap( &dc, Pos2Pixel(m_nPos), 0,
m_nWidth - Pos2Pixel(m_nPos), m_nHeight,
&dcMem, Pos2Pixel(m_nPos), 0,
&m_bmChannelActiveMask, m_bTransparentChannel );
dcMem.SelectObject( &m_bmChannelActive );
// Left side
DrawBitmap( &dc, 0, 0, Pos2Pixel(m_nPos), m_nHeight,
&dcMem, 0, 0, &m_bmChannelMask, m_bTransparentChannel );
}
// Only one bitmap for channel
} else {
DrawBitmap( &dc, 0, 0, m_nWidth, m_nHeight,
&dcMem, 0, 0, &m_bmChannelMask, m_bTransparentChannel );
}
dcMem.SelectObject( pbmTmp );
}
// If there is a bitmap to restore background image of a thumb
if( m_nThumbBgX != -1 ) {
RestoreBackground(
&dc, m_nThumbBgX, m_nThumbBgY,
m_nThumbWidth, m_nThumbHeight, &m_bmThumbBg );
m_nThumbBgX = -1;
}
// Draw thumb
if( m_bThumb && m_bEnable ) {
if( m_bThumbActive && m_bLButtonDown )
pbmTmp = dcMem.SelectObject( &m_bmThumbActive ); // Active thumb
else
pbmTmp = dcMem.SelectObject( &m_bmThumb ); // Normal thumb
// Vertical slider
if( m_bVertical ) {
// Background image is need to be restored
if( m_bTransparentChannel || !m_bChannel ) {
m_nThumbBgX = m_nMarginLeft;
m_nThumbBgY = Pos2Pixel(m_nPos) - m_nThumbHeight/2;
CopyBackground(
&dc, m_nThumbBgX, m_nThumbBgY,
m_nThumbWidth, m_nThumbHeight, &m_bmThumbBg );
}
DrawBitmap(
&dc, m_nMarginLeft, Pos2Pixel(m_nPos) - m_nThumbHeight/2,
m_nThumbWidth, m_nThumbHeight,
&dcMem, 0, 0, &m_bmThumbMask, m_bTransparentThumb );
// Horizontal slider
} else {
// Background image is need to be restored
if( m_bTransparentChannel || !m_bChannel ) {
m_nThumbBgX = Pos2Pixel(m_nPos) - m_nThumbWidth/2;
m_nThumbBgY = m_nMarginTop;
CopyBackground(
&dc, m_nThumbBgX, m_nThumbBgY,
m_nThumbWidth, m_nThumbHeight, &m_bmThumbBg );
}
DrawBitmap(
&dc, Pos2Pixel(m_nPos) - m_nThumbWidth/2, m_nMarginTop,
m_nThumbWidth, m_nThumbHeight,
&dcMem, 0, 0, &m_bmThumbMask, m_bTransparentThumb );
} // if horizontal
dcMem.SelectObject( pbmTmp );
} // if draw thumb
// Draw focus rectangle
if( m_bDrawFocusRect && m_bFocus && m_bEnable ) {
dc.DrawFocusRect( m_rect );
m_bFocusRect = TRUE;
}
dcMem.DeleteDC();
}
// Sets the maximum range for the slider.
//
// Parameters:
// [IN] nMax
// Maximum position for the slider.
// [IN] bRedraw
// TRUE to redraw after the range is set.
// FALSE to only change maximum position.
//
void CBitmapSlider::SetRangeMax(int nMax, BOOL bRedraw)
{
m_nMax = nMax;
if( bRedraw )
Invalidate();
}
// Sets the minimum range for the slider.
//
// Parameters:
// [IN] nMin
// Minimum position for the slider.
// [IN] bRedraw
// TRUE to redraw after the range is set.
// FALSE to only change minimum position.
//
void CBitmapSlider::SetRangeMin(int nMin, BOOL bRedraw)
{
m_nMin = nMin;
if( bRedraw )
Invalidate();
}
// Sets the range (minimum and maximum positions) for the slider.
//
// Parameters:
// [IN] nMin
// Minimum position for the slider.
// [IN] nMax
// Maximum position for the slider.
// [IN] bRedraw
// TRUE to redraw after the range is set.
// FALSE to only change the range.
//
void CBitmapSlider::SetRange(int nMin, int nMax, BOOL bRedraw)
{
SetRangeMin( nMin, FALSE );
SetRangeMax( nMax, bRedraw );
}
// Sets the current position of the slider.
//
// Parameters:
// [IN] nPos
// Specifies the new slider position.
//
void CBitmapSlider::SetPos(int nPos)
{
m_nPos = nPos;
// Boundary check
if( m_nPos > m_nMax )
m_nPos = m_nMax;
if( m_nPos < m_nMin )
m_nPos = m_nMin;
Invalidate();
}
// Sets the size of the page for a control.
//
// Parameters:
// [IN] nSize
// The new page size of the control.
//
// Return value:
// The previous page size.
//
int CBitmapSlider::SetPageSize(int nSize)
{
int nRet = m_nPage;
m_nPage = nSize;
return nRet;
}
// Sets the left, top, right, and bottom margins for a control
//
void CBitmapSlider::SetMargin(int nLeft, int nTop, int nRight, int nBottom )
{
SetMarginLeft( nLeft );
SetMarginTop( nTop );
SetMarginRight( nRight );
SetMarginBottom( nBottom );
}
// Enables or disables control.
//
// [IN] bEnable
// TRUE to enable control.
// FALSE to disable control.
//
void CBitmapSlider::Enable(BOOL bEnable)
{
m_bEnable = bEnable;
// If control is disabled during dragging
if( !m_bEnable && m_bLButtonDown ) {
m_bLButtonDown = FALSE;
ReleaseCapture();
}
Invalidate();
}
void CBitmapSlider::EnableEx(BOOL bEnable /* = TRUE */)
{
EnableWindow(bEnable);
m_bEnableEx = bEnable;
SetPos(m_nPos);
}
// Specify whether draw focus rectangle or not.
//
// [IN] bDraw
// TRUE to draw focus rectangle.
// FALSE to hide focus rectangle.
//
// [IN] bRedraw
// TRUE to redraw status is changed.
// FALSE to only change the status.
//
void CBitmapSlider::DrawFocusRect(BOOL bDraw, BOOL bRedraw)
{
m_bDrawFocusRect = bDraw;
if( bRedraw )
Invalidate();
}
// Load bitmaps for a channel
//
// Parameters:
// [IN] nChannelID
// ID number of the bitmap resource of the channel.
// [IN] nActiveID
// ID number of the bitmap resource of the active channel.
// [IN] bTransparent
// TRUE to apply transparency effect.
// FALSE to display normal bitmap.
// [IN] clrpTransColor
// RGB color to treat as transparent.
// [IN] iTransPixelX
// Logical x-coordinate of a point.
// It's color will be treated as transparent.
// [IN] iTransPixelY
// Logical y-coordinate of a point.
// It's color will be treated as transparent.
//
// Return value:
// TRUE
// Function succeedes.
// FALSE
// Function failes to load bitmaps.
//
BOOL CBitmapSlider::SetBitmapChannel(
UINT nChannelID, UINT nActiveID , BOOL bTransparent,
COLORREF clrpTransColor, int iTransPixelX, int iTransPixelY )
{
// This control will not have any bitmap for channel
if( !nChannelID ) {
m_bChannel = FALSE;
m_bmChannel.DeleteObject();
m_bmChannelMask.DeleteObject();
m_bmChannelActive.DeleteObject();
m_bmChannelActiveMask.DeleteObject();
return TRUE;
}
// load a bitmap
m_bmChannel.DeleteObject();
if( !m_bmChannel.LoadBitmap( nChannelID ) )
return FALSE;
// Prepare mask for transparency effect.
if( bTransparent ) {
PrepareMask( &m_bmChannel, &m_bmChannelMask,
clrpTransColor, iTransPixelX, iTransPixelY );
}
// Load a bitmap for active state.
if( nActiveID ) {
m_bmChannelActive.DeleteObject();
if( !m_bmChannelActive.LoadBitmap( nActiveID ) ) {
m_bmChannel.DeleteObject();
if( bTransparent )
m_bmChannelMask.DeleteObject();
return FALSE;
}
if( bTransparent ) {
PrepareMask( &m_bmChannelActive, &m_bmChannelActiveMask,
clrpTransColor, iTransPixelX, iTransPixelY );
}
m_bChannelActive = TRUE;
// There is no bitmap for active state.
} else
m_bChannelActive = FALSE;
// Get size of bitmap.
BITMAP bitmap;
m_bmChannel.GetBitmap( &bitmap );
m_nWidth = bitmap.bmWidth;
m_nHeight = bitmap.bmHeight;
// Compare size
if( m_bChannelActive ) {
BITMAP bitmap;
m_bmChannelActive.GetBitmap( &bitmap );
ASSERT( m_nWidth == bitmap.bmWidth && m_nHeight == bitmap.bmHeight );
}
// Change size of control as same as the bitmap.
SetWindowPos(NULL, 0, 0, m_nWidth, m_nHeight, SWP_NOZORDER | SWP_NOMOVE);
GetClientRect( &m_rect );
m_bTransparentChannel = bTransparent;
m_bChannel = TRUE;
return TRUE;
}
// Load bitmaps for a thumb
//
// Parameters:
// [IN] nThumbID
// ID number of the bitmap resource of the thumb
// [IN] nActiveID
// ID number of the bitmap resource of the active thumb
// [IN] bTransparent
// TRUE to apply transparency effect
// FALSE to display normal bitmap
// [IN] clrpTransColor
// RGB color to treat as transparent
// [IN] iTransPixelX
// Logical x-coordinate of a point.
// It's color will be treated as transparent
// [IN] iTransPixelY
// Logical y-coordinate of a point.
// It's color will be treated as transparent
//
// Return value:
// TRUE
// Function succeedes.
// FALSE
// Function failes to load bitmaps.
//
BOOL CBitmapSlider::SetBitmapThumb(
UINT nThumbID, UINT nActiveID, BOOL bTransparent,
COLORREF clrpTransColor, int iTransPixelX, int iTransPixelY )
{
// This control will not have bitmap
if( !nThumbID ) {
m_bThumb = FALSE;
m_bmThumb.DeleteObject();
m_bmThumbMask.DeleteObject();
m_bmThumbActive.DeleteObject();
m_bmThumbActiveMask.DeleteObject();
m_bmThumbBg.DeleteObject();
return TRUE;
}
// load a bitmap
m_bmThumb.DeleteObject();
if( !m_bmThumb.LoadBitmap( nThumbID ) )
return FALSE;
// Prepare mask for transparency effect.
if( bTransparent ) {
PrepareMask( &m_bmThumb, &m_bmThumbMask,
clrpTransColor, iTransPixelX, iTransPixelY );
}
// Load a bitmap for active state.
if( nActiveID ) {
m_bmThumbActive.DeleteObject();
if( !m_bmThumbActive.LoadBitmap( nActiveID ) ) {
m_bmThumb.DeleteObject();
if( bTransparent )
m_bmThumbMask.DeleteObject();
return FALSE;
}
if( bTransparent ) {
PrepareMask( &m_bmThumbActive, &m_bmThumbActiveMask,
clrpTransColor, iTransPixelX, iTransPixelY );
}
m_bThumbActive = TRUE;
// There is no bitmap for active state.
} else
m_bThumbActive = FALSE;
// Get size of the bitmap
BITMAP bitmap;
m_bmThumb.GetBitmap( &bitmap );
m_nThumbWidth = bitmap.bmWidth;
m_nThumbHeight = bitmap.bmHeight;
// Get size of the control if there was no bitmap for channel.
if( !m_bChannel ) {
GetClientRect( &m_rect );
m_nHeight = m_rect.Height();
m_nWidth = m_rect.Width();
}
ASSERT( m_nThumbWidth <= m_nWidth && m_nThumbHeight <= m_nHeight );
// Compare size
if( m_bThumbActive ) {
BITMAP bitmap;
m_bmThumbActive.GetBitmap( &bitmap );
ASSERT(
m_nThumbWidth == bitmap.bmWidth &&
m_nThumbHeight == bitmap.bmHeight );
}
// Set attributes
m_bTransparentThumb = bTransparent;
m_bThumb = TRUE;
return TRUE;
}
// OnLButtonDown
//
// Dragging is started
//
void CBitmapSlider::OnLButtonDown(UINT nFlags, CPoint point)
{
if (!m_bEnable || !m_bEnableEx)
return;
SetCapture();
SetFocus();
m_bLButtonDown = TRUE;
// If mouse button is clicked on the thumb,
// capture the coordinates of mouse pointer and center of thumb
// and calculate distance between them.
if( m_bVertical ) {
if( abs( point.y - Pos2Pixel( m_nPos ) ) <= m_nThumbHeight / 2 )
m_nMouseOffset = point.y - Pos2Pixel( m_nPos );
else
m_nMouseOffset = 0;
} else {
if( abs( point.x - Pos2Pixel( m_nPos ) ) <= m_nThumbWidth / 2 )
m_nMouseOffset = point.x - Pos2Pixel( m_nPos );
else
m_nMouseOffset = 0;
}
OnMouseMove( nFlags, point );
Invalidate();
CStatic::OnLButtonDown(nFlags, point);
}
// OnMouseMove
//
// During dragging
//
void CBitmapSlider::OnMouseMove(UINT nFlags, CPoint point)
{
if (!m_bLButtonDown || !m_bEnable || !m_bEnableEx)
return;
int nPixel;
// Boundary check
if( m_bVertical ) {
nPixel = point.y - m_nMouseOffset;
if( nPixel > m_nHeight - m_nMarginBottom - m_nThumbHeight/2 )
nPixel = m_nHeight - m_nMarginBottom - m_nThumbHeight/2;
if( nPixel < m_nMarginTop + m_nThumbHeight/2 )
nPixel = m_nMarginTop + m_nThumbHeight/2;
} else {
nPixel = point.x - m_nMouseOffset;
if( nPixel < m_nMarginLeft + m_nThumbWidth/2 )
nPixel = m_nMarginLeft + m_nThumbWidth/2;
if( nPixel > m_nWidth - m_nMarginRight - m_nThumbWidth/2 )
nPixel = m_nWidth - m_nMarginRight - m_nThumbWidth/2;
}
// Apply change
if( Pos2Pixel(m_nPos) != nPixel ) {
SetPos( Pixel2Pos( nPixel ) );
::PostMessage(
GetParent()->GetSafeHwnd(), WM_BITMAPSLIDER_MOVING,
GetDlgCtrlID(), m_nPos );
}
CStatic::OnMouseMove(nFlags, point);
}
BOOL CBitmapSlider::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
{
m_nPos += (zDelta < 0 ? 1 : -1);
SetPos(m_nPos);
::PostMessage(
GetParent()->GetSafeHwnd(), WM_BITMAPSLIDER_MOVED,
GetDlgCtrlID(), m_nPos);
return CStatic::OnMouseWheel(nFlags, zDelta, pt);
}
// OnLButtonUp
//
// Dragging is finished
//
void CBitmapSlider::OnLButtonUp(UINT nFlags, CPoint point)
{
if (!m_bEnable || !m_bEnableEx)
return;
ReleaseCapture();
m_bLButtonDown = FALSE;
Invalidate();
::PostMessage(
GetParent()->GetSafeHwnd(), WM_BITMAPSLIDER_MOVED,
GetDlgCtrlID(), m_nPos );
CStatic::OnLButtonUp(nFlags, point);
}
// Calculate point of thumb from position value
//
int CBitmapSlider::Pos2Pixel(int nPos)
{
if( m_bVertical ) {
return
m_nMarginTop + m_nThumbHeight/2 +
(int)(
( m_nHeight - m_nMarginTop - m_nMarginBottom - m_nThumbHeight ) *
((double) ( nPos - m_nMin ) / ( m_nMax - m_nMin ) )
);
} else {
return (int)(
( m_nWidth - m_nMarginLeft - m_nMarginRight - m_nThumbWidth ) *
((double) ( nPos - m_nMin ) / ( m_nMax - m_nMin ) )
) + m_nMarginLeft + m_nThumbWidth/2;
}
}
// Calculate position value from point of mouse
//
int CBitmapSlider::Pixel2Pos(int nPixel)
{
if( m_bVertical ) {
return (int)(
m_nMin +
(double)( nPixel - m_nMarginTop - m_nThumbHeight/2) /
( m_nHeight - m_nMarginBottom - m_nMarginTop - m_nThumbHeight ) *
( m_nMax - m_nMin )
);
} else {
return (int)(
m_nMin +
(double)( nPixel - m_nMarginLeft - m_nThumbWidth/2 ) /
( m_nWidth - m_nMarginLeft - m_nMarginRight - m_nThumbWidth ) *
( m_nMax - m_nMin )
);
}
}
// Copy background image to bitmap
//
void CBitmapSlider::CopyBackground(
CDC *pDC, int nXSrc, int nYSrc, int nWidth, int nHeight, CBitmap *pBmDst)
{
pBmDst->DeleteObject();
pBmDst->CreateCompatibleBitmap( pDC, nWidth, nHeight );
CDC memDC;
memDC.CreateCompatibleDC( pDC );
CBitmap *pBmTmp = memDC.SelectObject( pBmDst );
memDC.BitBlt( 0, 0, nWidth, nHeight, pDC, nXSrc, nYSrc, SRCCOPY );
memDC.SelectObject( pBmTmp );
memDC.DeleteDC();
}
// Restore background image from bitmap
//
void CBitmapSlider::RestoreBackground(
CDC *pDC, int nXDst, int nYDst, int nWidth, int nHeight, CBitmap *pBmSrc)
{
CDC memDC;
memDC.CreateCompatibleDC( pDC );
CBitmap *pBmTmp = memDC.SelectObject( pBmSrc );
pDC->BitBlt( nXDst, nYDst, nWidth, nHeight, &memDC, 0, 0, SRCCOPY );
memDC.SelectObject( pBmTmp );
memDC.DeleteDC();
}
// DrawBitmap
//
// It's for code readability
//
void CBitmapSlider::DrawBitmap(
CDC *pDC, int xStart, int yStart, int wWidth, int wHeight,
CDC *pTmpDC, int xSource, int ySource, CBitmap *bmMask, BOOL bTransparent )
{
if( bTransparent ) {
DrawTransparentBitmap(
pDC, xStart, yStart,
wWidth, wHeight,
pTmpDC, xSource, ySource, bmMask );
} else {
pDC->BitBlt( xStart, yStart,
wWidth, wHeight,
pTmpDC, xSource, ySource, SRCCOPY );
}
}
// PrepareMask
//
// "Drawing Transparent Bitmap with ease with on the fly masks in MFC"
// By Raja Segar
//
// I changed default clrpTransColor value from NULL(black) to 0xFF000000(not RGB color)
//
void CBitmapSlider::PrepareMask(
CBitmap *pBmpSource, CBitmap *pBmpMask,
COLORREF clrpTransColor, int iTransPixelX, int iTransPixelY)
{
BITMAP bm;
// Get the dimensions of the source bitmap
pBmpSource->GetObject(sizeof(BITMAP), &bm);
// Create the mask bitmap
pBmpMask->DeleteObject();
pBmpMask->CreateBitmap( bm.bmWidth, bm.bmHeight, 1, 1, NULL);
// We will need two DCs to work with. One to hold the Image
// (the source), and one to hold the mask (destination).
// When blitting onto a monochrome bitmap from a color, pixels
// in the source color bitmap that are equal to the background
// color are blitted as white. All the remaining pixels are
// blitted as black.
CDC hdcSrc, hdcDst;
hdcSrc.CreateCompatibleDC(NULL);
hdcDst.CreateCompatibleDC(NULL);
// Load the bitmaps into memory DC
CBitmap* hbmSrcT = (CBitmap*) hdcSrc.SelectObject(pBmpSource);
CBitmap* hbmDstT = (CBitmap*) hdcDst.SelectObject(pBmpMask);
// Dynamically get the transparent color
COLORREF clrTrans;
if (clrpTransColor == 0xFF000000)
{
// User did not specify trans color so get it from bmp
clrTrans = hdcSrc.GetPixel(iTransPixelX, iTransPixelY);
}
else
{
clrTrans = clrpTransColor;
}
// Change the background to trans color
COLORREF clrSaveBk = hdcSrc.SetBkColor(clrTrans);
// This call sets up the mask bitmap.
hdcDst.BitBlt(0,0,bm.bmWidth, bm.bmHeight, &hdcSrc,0,0,SRCCOPY);
// Now, we need to paint onto the original image, making
// sure that the "transparent" area is set to black. What
// we do is AND the monochrome image onto the color Image
// first. When blitting from mono to color, the monochrome
// pixel is first transformed as follows:
// if 1 (black) it is mapped to the color set by SetTextColor().
// if 0 (white) is is mapped to the color set by SetBkColor().
// Only then is the raster operation performed.
COLORREF clrSaveDstText = hdcSrc.SetTextColor(RGB(255,255,255));
hdcSrc.SetBkColor(RGB(0,0,0));
hdcSrc.BitBlt(0,0,bm.bmWidth, bm.bmHeight, &hdcDst,0,0,SRCAND);
// Clean up by deselecting any objects, and delete the
// DC's.
hdcDst.SetTextColor(clrSaveDstText);
hdcSrc.SetBkColor(clrSaveBk);
hdcSrc.SelectObject(hbmSrcT);
hdcDst.SelectObject(hbmDstT);
hdcSrc.DeleteDC();
hdcDst.DeleteDC();
}
// DrawTransparentBitmap
//
// "Drawing Transparent Bitmap with ease with on the fly masks in MFC"
// By Raja Segar
//
void CBitmapSlider::DrawTransparentBitmap(
CDC *pDC, int xStart, int yStart, int wWidth, int wHeight,
CDC *pTmpDC, int xSource, int ySource, CBitmap *bmMask )
{
// We are going to paint the two DDB's in sequence to the destination.
// 1st the monochrome bitmap will be blitted using an AND operation to
// cut a hole in the destination. The color image will then be ORed
// with the destination, filling it into the hole, but leaving the
// surrounding area untouched.
CDC hdcMem;
hdcMem.CreateCompatibleDC(NULL);
CBitmap* hbmT = hdcMem.SelectObject(bmMask);
pDC->BitBlt( xStart, yStart, wWidth, wHeight, &hdcMem,
xSource, ySource, SRCAND);
// Also note the use of SRCPAINT rather than SRCCOPY.
pDC->BitBlt(xStart, yStart, wWidth, wHeight, pTmpDC,
xSource, ySource,SRCPAINT);
// Now, clean up.
hdcMem.SelectObject(hbmT);
hdcMem.DeleteDC();
}
// To get keyboard input
//
UINT CBitmapSlider::OnGetDlgCode()
{
if( GetKeyState(VK_TAB) >= 0 ) {
return DLGC_WANTALLKEYS;
}
return CStatic::OnGetDlgCode();
}
// Handling keyboard input
//
void CBitmapSlider::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (!m_bEnable || !m_bEnableEx)
return;
switch( nChar ) {
// Left & up
case VK_LEFT :
case VK_UP :
SetPos( m_nPos-1 );
break;
// Right & down
case VK_RIGHT :
case VK_DOWN :
SetPos( m_nPos+1 );
break;
// Home
case VK_HOME :
SetPos( m_nMin );
break;
// End
case VK_END :
SetPos( m_nMax );
break;
// Page up
case VK_PRIOR :
SetPos( m_nPos - m_nPage );
break;
// Page down
case VK_NEXT :
SetPos( m_nPos + m_nPage );
break;
default :
CStatic::OnKeyDown(nChar, nRepCnt, nFlags);
return;
}
::PostMessage(
GetParent()->GetSafeHwnd(), WM_BITMAPSLIDER_MOVED,
GetDlgCtrlID(), m_nPos );
CStatic::OnKeyDown(nChar, nRepCnt, nFlags);
}
// Control looses its focus
//
void CBitmapSlider::OnKillFocus(CWnd* pNewWnd)
{
CStatic::OnKillFocus(pNewWnd);
m_bFocus = FALSE;
Invalidate();
}
// This control gains its focus
//
void CBitmapSlider::OnSetFocus(CWnd* pOldWnd)
{
CStatic::OnSetFocus(pOldWnd);
m_bFocus = TRUE;
Invalidate();
}
// Release resources
//
void CBitmapSlider::OnDestroy()
{
CStatic::OnDestroy();
m_bmThumb.DeleteObject();
m_bmThumbMask.DeleteObject();
m_bmThumbActive.DeleteObject();
m_bmThumbActiveMask.DeleteObject();
m_bmThumbBg.DeleteObject();
m_bmChannel.DeleteObject();
m_bmChannelMask.DeleteObject();
m_bmChannelActive.DeleteObject();
m_bmChannelActiveMask.DeleteObject();
}
有点一点需要注意:
如果窗口是滑动显示 ,需要做一些特殊处理:
::AnimateWindow(wnd_.GetSafeHwnd(), 500, AW_ACTIVATE | AW_HOR_POSITIVE);
在滑动之后 调用一下
slider_.ShowWindow(SW_HIDE);slider_.ShowWindow(SW_SHOW);