⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vxskinbutton.cpp

📁 Windows ce 6.0 下实现各种按钮自画贴图
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// VxSkinButton.cpp : implementation file
//

#include "stdafx.h"
#include "VxSkinButton.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif 

/////////////////////////////////////////////////////////////////////////////
// CVxSkinButton
CVxSkinButton::CVxSkinButton()
{
    m_DrawMode = 1; // normal drawing mode
    m_FocusRectMargin = 0; // disable focus dotted rect
    hClipRgn = NULL; // no clipping region
    m_TextColor = GetSysColor(COLOR_BTNTEXT); // default button text color
    m_button_down = m_tracking = m_Checked = false;
    m_bMask = FALSE;
}

CVxSkinButton::~CVxSkinButton()
{
    if (hClipRgn)
        DeleteObject(hClipRgn);
    // free clip region
}

BEGIN_MESSAGE_MAP(CVxSkinButton, CButton)
//{{AFX_MSG_MAP(CVxSkinButton)
    ON_WM_ERASEBKGND()
    ON_WM_LBUTTONDOWN()
    ON_WM_LBUTTONUP()
    ON_WM_MOUSEMOVE()
    ON_WM_LBUTTONDBLCLK()
    ON_WM_KILLFOCUS()
    ON_WM_KEYDOWN()
//}}AFX_MSG_MAP
    //ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
    ON_MESSAGE(WM_CXSHADE_RADIO, OnRadioInfo)
    ON_MESSAGE(BM_SETCHECK, OnBMSetCheck)
    ON_MESSAGE(BM_GETCHECK, OnBMGetCheck)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CVxSkinButton message handlers
void CVxSkinButton::PreSubclassWindow()
{
    m_Style = GetButtonStyle(); // get specific BS_ styles
    if ((m_Style & BS_AUTOCHECKBOX) == BS_AUTOCHECKBOX)
    //||((m_Style & BS_CHECKBOX) == BS_CHECKBOX))
    {
        m_Style = BS_CHECKBOX;
    }
    else if ((m_Style & BS_AUTORADIOBUTTON) == BS_AUTORADIOBUTTON)
    //||((m_Style & BS_RADIOBUTTON) == BS_RADIOBUTTON))
    {
        m_Style = BS_RADIOBUTTON;
    }
    else
    {
        m_Style = BS_PUSHBUTTON;
    }

    CButton::PreSubclassWindow();
    ModifyStyle(0, BS_OWNERDRAW);
}

/////////////////////////////////////////////////////////////////////////////
// doesn't erase the button background
BOOL CVxSkinButton::OnEraseBkgnd(CDC *pDC)
{
    return 1;
}

/////////////////////////////////////////////////////////////////////////////
void CVxSkinButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    ASSERT(lpDrawItemStruct);
    //TRACE("* Captured: %08X\n", ::GetCapture());

    // Check if the button state in not in inconsistent mode...
    POINT mouse_position;

    if ((m_button_down) && (::GetCapture() == m_hWnd) && (::GetCursorPos
        (&mouse_position)))
    {
        if (::WindowFromPoint(mouse_position) == m_hWnd)
        {
            if ((GetState() &BST_PUSHED) != BST_PUSHED)
            {
                //TRACE("* Inconsistency up detected! Fixing.\n");
                SetState(TRUE);
                return;
            }
        }
        else
        {
            if ((GetState() & BST_PUSHED) == BST_PUSHED)
            {
                //TRACE("* Inconsistency up detected! Fixing.\n");
                SetState(FALSE);
                return;
            }
        }
    }

    //TRACE("* Drawing: %08x\n", lpDrawItemStruct->itemState);
    CString sCaption;
    CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC); // get device context
    RECT r = lpDrawItemStruct->rcItem; // context rectangle
    int cx = r.right - r.left; // get width
    int cy = r.bottom - r.top; // get height
    // get text box position
    RECT tr = 
    {
        r.left + m_FocusRectMargin + 2, r.top, r.right - m_FocusRectMargin - 2,
            r.bottom
    };

    GetWindowText(sCaption); // get button text
    pDC->SetBkMode(TRANSPARENT);

    // Select the correct skin 
    if (lpDrawItemStruct->itemState & ODS_DISABLED)
    {
        // DISABLED BUTTON
        DrawBitmap(pDC, 3, r, m_DrawMode);
        // if needed, draw the standard 3D rectangular border
        if (m_Border)
            pDC->DrawEdge(&r, EDGE_RAISED, BF_RECT);
        // paint the etched button text
        pDC->SetTextColor(GetSysColor(COLOR_3DHILIGHT));
        pDC->DrawText(sCaption, &tr, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
        pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
        OffsetRect(&tr, -1, -1);
        pDC->DrawText(sCaption, &tr, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
    }
    else
    {
        // SELECTED (DOWN) BUTTON
        if ((lpDrawItemStruct->itemState &ODS_SELECTED) || m_Checked)
        {
            DrawBitmap(pDC, 2, r, m_DrawMode);
            OffsetRect(&tr, 2, 1); // shift text
            // if needed, draw the standard 3D rectangular border
            if (m_Border)
                pDC->DrawEdge(&r, EDGE_SUNKEN, BF_RECT);
        }
        else
        {
            // DEFAULT BUTTON
            if (m_tracking)
            {
                DrawBitmap(pDC, 1, r, m_DrawMode);
            }
            else
            {
                if ((lpDrawItemStruct->itemState &ODS_FOCUS))
                {
                    DrawBitmap(pDC, 0, r, m_DrawMode);
                }
                else
                {
                    DrawBitmap(pDC, 0, r, m_DrawMode);
                }
            }
            // if needed, draw the standard 3D rectangular border
            if (m_Border)
            {
                pDC->DrawEdge(&r, EDGE_RAISED, BF_RECT);
            }
        }
        // paint the focus rect
        if ((lpDrawItemStruct->itemState & ODS_FOCUS) && (m_FocusRectMargin > 0))
        {
            r.left += m_FocusRectMargin;
            r.top += m_FocusRectMargin;
            r.right -= m_FocusRectMargin;
            r.bottom -= m_FocusRectMargin;
            DrawFocusRect(lpDrawItemStruct->hDC, &r);
        }
        // paint the enabled button text
        pDC->SetTextColor(m_TextColor);
        pDC->DrawText(sCaption, &tr, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
    }
}

/////////////////////////////////////////////////////////////////////////////
int CVxSkinButton::GetBitmapWidth(HBITMAP hBitmap)
{
    BITMAP bm;

    GetObject(hBitmap, sizeof(BITMAP), (PSTR)&bm);

    return bm.bmWidth;
}

/////////////////////////////////////////////////////////////////////////////
int CVxSkinButton::GetBitmapHeight(HBITMAP hBitmap)
{
    BITMAP bm;

    GetObject(hBitmap, sizeof(BITMAP), (PSTR)&bm);

    return bm.bmHeight;
}

/////////////////////////////////////////////////////////////////////////////
void CVxSkinButton::DrawBitmap(CDC *dc, int nState, RECT r, int DrawMode)
{
    int cx = r.right - r.left;
    int cy = r.bottom - r.top;

    cx = m_ButtonSize.cx;
    cy = m_ButtonSize.cy;

    if (m_bMask)
    {
        CDC dcBmp;
        dcBmp.CreateCompatibleDC(dc);
        dcBmp.SelectObject(m_bImage);
        CDC hdcMem;
        hdcMem.CreateCompatibleDC(dc);
        CBitmap hBitmap;
        hBitmap.CreateCompatibleBitmap(dc, cx, cy);
        hdcMem.SelectObject(hBitmap);

        hdcMem.BitBlt(r.left, r.top, cx, cy, dc, 0, 0, SRCCOPY);
        if (!DrawMode)
        {
            hdcMem.BitBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx
                *nState, 0, SRCINVERT);
            hdcMem.BitBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx *4, 0,
                SRCAND);
            hdcMem.BitBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx
                *nState, 0, SRCINVERT);
        }
        else
        {
            hdcMem.StretchBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx
                *nState, 0, m_ButtonSize.cx, m_ButtonSize.cy, SRCINVERT);
            hdcMem.StretchBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx *4,
                0, m_ButtonSize.cx, m_ButtonSize.cy, SRCAND);
            hdcMem.StretchBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx
                *nState, 0, m_ButtonSize.cx, m_ButtonSize.cy, SRCINVERT);
        }
        dc->BitBlt(r.left, r.top, cx, cy, &hdcMem, 0, 0, SRCCOPY);

        hdcMem.DeleteDC();
        hBitmap.DeleteObject();
    }
    else
    {
        CDC dcBmp;
        dcBmp.CreateCompatibleDC(dc);
        dcBmp.SelectObject(m_bImage);

        if (!DrawMode)
        {
            dc->BitBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx *nState,
                0, SRCCOPY);
        }
        else
        {
            dc->StretchBlt(r.left, r.top, cx, cy, &dcBmp, m_ButtonSize.cx
                *nState, 0, m_ButtonSize.cx, m_ButtonSize.cy, SRCCOPY);
        }
        DeleteDC(dcBmp);
    }
}

/////////////////////////////////////////////////////////////////////////////
void CVxSkinButton::FillWithBitmap(CDC *dc, HBITMAP hbmp, RECT r)
{
    if (!hbmp)
        return;
    CDC memdc;

    memdc.CreateCompatibleDC(dc);
    memdc.SelectObject(hbmp);

    int w = r.right - r.left;
    int h = r.bottom - r.top;
    int x, y, z;
    int bx = GetBitmapWidth(hbmp);
    int by = GetBitmapHeight(hbmp);

    for (y = r.top; y < h; y += by)
    {
        if ((y + by) > h)
        {
            by = h - y;
        }

        z = bx;

        for (x = r.left; x < w; x += z)
        {
            if ((x + z) > w)
            {
                z = w - x;
            }

            dc->BitBlt(x, y, z, by, &memdc, 0, 0, SRCCOPY);
        }
    }
    DeleteDC(memdc);
}

/////////////////////////////////////////////////////////////////////////////
void CVxSkinButton::SetSkin(UINT nBitmap, short drawmode, short border, short
    margin, BOOL bMask)
{
    m_bImage.DeleteObject(); // free previous allocated bitmap
    m_bImage.LoadBitmap(nBitmap);
    m_DrawMode = max(0, min(drawmode, 2));
    m_Border = border;
    m_FocusRectMargin = max(0, margin);
    m_bMask = bMask;

    if (!m_bMask)
    {
        m_ButtonSize.cx = GetBitmapWidth(m_bImage) / 4;
        //m_ButtonSize.cx = GetBitmapWidth(m_bImage);
        m_ButtonSize.cy = GetBitmapHeight(m_bImage);
    }
    else
    {
        m_ButtonSize.cx = GetBitmapWidth(m_bImage) / 5;
        m_ButtonSize.cy = GetBitmapHeight(m_bImage);
    }
    SetWindowPos(&wndTop, 0, 0, m_ButtonSize.cx, m_ButtonSize.cy, SWP_NOMOVE |
        SWP_NOZORDER);
}

/////////////////////////////////////////////////////////////////////////////
HRGN CVxSkinButton::CreateRgnFromBitmap(HBITMAP hBmp, COLORREF color)
{
    if (!hBmp)
        return NULL;

    BITMAP bm;
    GetObject(hBmp, sizeof(BITMAP), &bm); // get bitmap attributes

    CDC dcBmp;
    dcBmp.CreateCompatibleDC(GetDC()); 
    // Creates a memory device context for the bitmap
    dcBmp.SelectObject(hBmp); // selects the bitmap in the device context

    const DWORD RDHDR = sizeof(RGNDATAHEADER);
    const DWORD MAXBUF = 40; // size of one block in RECTs
    // (i.e. MAXBUF * sizeof(RECT) in bytes)
    LPRECT pRects;
    DWORD cBlocks = 0; // number of allocated blocks

    INT i, j; // current position in mask image
    INT first = 0; // left position of current scan line
    // where mask was found
    bool wasfirst = false; // set when if mask was found in current scan line
    bool ismask; // set when current color is mask color

    // allocate memory for region data
    RGNDATAHEADER *pRgnData = (RGNDATAHEADER*)new BYTE[RDHDR + ++cBlocks
        *MAXBUF * sizeof(RECT)];
    memset(pRgnData, 0, RDHDR + cBlocks * MAXBUF * sizeof(RECT));
    // fill it by default
    pRgnData->dwSize = RDHDR;
    pRgnData->iType = RDH_RECTANGLES;
    pRgnData->nCount = 0;
    for (i = 0; i < bm.bmHeight; i++)
    {
        for (j = 0; j < bm.bmWidth; j++)
        {
            // get color
            ismask = (dcBmp.GetPixel(j, bm.bmHeight - i - 1) != color);
            // place part of scan line as RECT region if transparent color found after mask color or
            // mask color found at the end of mask image
            if (wasfirst && ((ismask && (j == (bm.bmWidth - 1))) || (ismask ^ 
                (j < bm.bmWidth))))
            {
                // get offset to RECT array if RGNDATA buffer
                pRects = (LPRECT)((LPBYTE)pRgnData + RDHDR);
                // save current RECT
                pRects[pRgnData->nCount++] = CRect(first, bm.bmHeight - i - 1,
                    j + (j == (bm.bmWidth - 1)), bm.bmHeight - i);
                // if buffer full reallocate it
                if (pRgnData->nCount >= cBlocks *MAXBUF)
                {
                    LPBYTE pRgnDataNew = new BYTE[RDHDR + ++cBlocks *MAXBUF *
                        sizeof(RECT)];
                    memcpy(pRgnDataNew, pRgnData, RDHDR + (cBlocks - 1) *MAXBUF
                        * sizeof(RECT));
                    delete pRgnData;
                    pRgnData = (RGNDATAHEADER*)pRgnDataNew;
                }
                wasfirst = false;
            }
            else if (!wasfirst && ismask)
            // set wasfirst when mask is found
            {
                first = j;
                wasfirst = true;
            }
        }
    }
    dcBmp.DeleteDC(); //release the bitmap
    // create region
    /* Under WinNT the ExtCreateRegion returns NULL (by Fable@aramszu.net) */
    //HRGN hRgn = ExtCreateRegion(NULL, RDHDR + pRgnData->nCount * sizeof(RECT), (LPRGNDATA)pRgnData);
    /* ExtCreateRegion replacement { */
    HRGN hRgn = CreateRectRgn(0, 0, 0, 0);
    ASSERT(hRgn != NULL);
    pRects = (LPRECT)((LPBYTE)pRgnData + RDHDR);
    for (i = 0; i < (int)pRgnData->nCount; i++)
    {
        HRGN hr = CreateRectRgn(pRects[i].left, pRects[i].top, pRects[i].right,
            pRects[i].bottom);
        VERIFY(CombineRgn(hRgn, hRgn, hr, RGN_OR) != ERROR);
        if (hr)
            DeleteObject(hr);
    }
    ASSERT(hRgn != NULL);
    /* } ExtCreateRegion replacement */

    delete pRgnData;
    return hRgn;
}

/////////////////////////////////////////////////////////////////////////////
COLORREF CVxSkinButton::SetTextColor(COLORREF new_color)
{
    COLORREF tmp_color = m_TextColor;

    m_TextColor = new_color;

    return tmp_color; //returns the previous color
}

/////////////////////////////////////////////////////////////////////////////
/*void CVxSkinButton::SetToolTipText(CString s)
{
    if (m_tooltip.m_hWnd == NULL) 
    {
        if (m_tooltip.Create(this))     // first assignment
        {
            if (m_tooltip.AddTool(this, (LPCTSTR)s))
            {
                m_tooltip.Activate(1);
            }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -