CBitmapSlider擴展

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:  [email protected]
// 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);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章