• 不规则按钮,支持普通Button,Radio Button, Check Button


    使用白色作为透明色Mask创建不规则region

    发几张图片(程序以bmp做例子,但是论坛不能传bmp)上来做个具体例子:

    normal

    down

    focus

    diable

    mask

     1 //Header File
     2 
     3 #pragma once
     4 
     5 
     6 // CRgnButton
     7 
     8 #define WM_CXSHADE_RADIO    WM_USER+0x100
     9 #define ALLOC_UNIT  100
    10 
    11 class CRgnButton : public CButton
    12 {
    13     DECLARE_DYNAMIC(CRgnButton)
    14 
    15 public:
    16     CRgnButton();
    17     virtual ~CRgnButton();
    18 
    19     enum DRAW_MODE { DRAW_NORMAL, DRAW_STRETCH, DRAW_TILED };
    20 public:
    21     void SetToolTipText(const CString &strTip);
    22     COLORREF SetTextColor(COLORREF colorNew);
    23     void SetSkin(UINT normal, UINT down, UINT over=0, UINT disabled=0, UINT focus=0,UINT mask=0,
    24         DRAW_MODE drawmode=DRAW_NORMAL,short border=0,short margin=0);
    25 public:
    26     virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
    27 protected:
    28     virtual void PreSubclassWindow();
    29 
    30     afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    31     afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    32     afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    33     afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    34     afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
    35     afx_msg void OnKillFocus(CWnd* pNewWnd);
    36     afx_msg BOOL OnBnClicked();
    37     afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
    38 
    39     afx_msg HRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);
    40     afx_msg HRESULT OnRadioInfo(WPARAM wParam, LPARAM lParam);
    41     afx_msg HRESULT OnBMSetCheck(WPARAM wParam, LPARAM lParam);
    42     afx_msg HRESULT OnBMGetCheck(WPARAM wParam, LPARAM lParam);
    43     DECLARE_MESSAGE_MAP()
    44 
    45 protected:
    46     HRGN    CreateRgnFromBitmap(CBitmap &bmp, COLORREF cTransColor);
    47     void    FillWithBitmap(CDC* dc, CBitmap &bmp, RECT rc);
    48     void    DrawBitmap(CDC* dc, CBitmap &bmp, RECT rc, DRAW_MODE DrawMode);
    49     int        GetBitmapWidth (CBitmap *bmp);
    50     int        GetBitmapHeight (CBitmap *bmp);
    51     void    RelayEvent(UINT message, WPARAM wParam, LPARAM lParam);
    52 private:
    53     bool            m_bCheck;
    54     DWORD        m_Style;
    55     bool            m_bTrack;
    56     bool            m_bBtnDown;
    57     CToolTipCtrl    m_Tooltip;
    58     CBitmap        m_bNormal, m_bDown, m_bDisable, m_bMask, m_bOver, m_bFocus;
    59     short            m_nFocusRectMargin;
    60     COLORREF    m_cTextColor;
    61     HRGN            m_hClipRgn;
    62     bool            m_bHasBorder;
    63     DRAW_MODE    m_DrawMode;
    64 
    65     BYTE MinByte(BYTE a, BYTE b) { return (0xff < (a + b) )? 0xff : (a + b); }
    66 };
      1 //Source Code
      2 // RgnButton.cpp : 实现文件
      3 //
      4 
      5 #include "stdafx.h"
      6 #include "RegionWnd.h"
      7 #include "RgnButton.h"
      8 
      9 
     10 // CRgnButton
     11 
     12 IMPLEMENT_DYNAMIC(CRgnButton, CButton)
     13 
     14 CRgnButton::CRgnButton()
     15 : m_bCheck(false), m_bBtnDown(false), m_bTrack(false)
     16 , m_DrawMode(DRAW_STRETCH)
     17 , m_hClipRgn(NULL), m_nFocusRectMargin(0)
     18 {
     19     m_cTextColor = GetSysColor(COLOR_BTNTEXT);
     20 }
     21 
     22 CRgnButton::~CRgnButton()
     23 {
     24     if(m_hClipRgn)
     25         DeleteObject(m_hClipRgn);
     26 }
     27 
     28 
     29 BEGIN_MESSAGE_MAP(CRgnButton, CButton)
     30     ON_WM_ERASEBKGND()
     31     ON_WM_LBUTTONDOWN()
     32     ON_WM_LBUTTONUP()
     33     ON_WM_MOUSEMOVE()
     34     ON_WM_LBUTTONDBLCLK()
     35     ON_WM_KILLFOCUS()
     36 //    ON_CONTROL_REFLECT_EX(BN_CLICKED, &CRgnButton::OnBnClicked)
     37     ON_WM_KEYDOWN()
     38 
     39     ON_MESSAGE(WM_MOUSELEAVE,  OnMouseLeave)
     40     ON_MESSAGE(WM_CXSHADE_RADIO,  OnRadioInfo)
     41     ON_MESSAGE(BM_SETCHECK,  OnBMSetCheck)
     42     ON_MESSAGE(BM_GETCHECK,  OnBMGetCheck)
     43 END_MESSAGE_MAP()
     44 
     45 
     46 
     47 // CRgnButton 消息处理程序
     48 
     49 
     50 
     51 void CRgnButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
     52 {
     53     ASSERT(lpDrawItemStruct);
     54 
     55     //Check if the button state is not in inconsistent mode...
     56     POINT mouse_position;
     57     if ( (m_bBtnDown) && (::GetCapture() == m_hWnd) && (::GetCursorPos(&mouse_position))) {
     58         if (::WindowFromPoint(mouse_position) == m_hWnd){
     59             if ((GetState() & BST_PUSHED) != BST_PUSHED) {
     60                 SetState(TRUE);
     61                 return;
     62             }
     63         } else {
     64             if ((GetState() & BST_PUSHED) == BST_PUSHED) {
     65                 SetState(FALSE);
     66                 return;
     67             }
     68         }
     69     }
     70 
     71     CString strCaption;
     72     CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
     73     CRect rc=lpDrawItemStruct->rcItem;
     74     int cx = rc.Width();
     75     int cy = rc.Height();
     76     // get text box position
     77     RECT tr={ rc.left + m_nFocusRectMargin +2, rc.top, rc.right - m_nFocusRectMargin -2, rc.bottom };
     78 
     79     GetWindowText(strCaption);                            // get button text
     80     pDC->SetBkMode(TRANSPARENT);
     81 
     82     // Select the correct skin 
     83     if (lpDrawItemStruct->itemState & ODS_DISABLED){    // DISABLED BUTTON
     84         if(m_bDisable.m_hObject == NULL)
     85             // no skin selected for disabled state -> standard button
     86             pDC->FillSolidRect(&rc, GetSysColor(COLOR_BTNFACE));
     87         else // paint the skin
     88             DrawBitmap(pDC, m_bDisable, rc, m_DrawMode);
     89         // if needed, draw the standard 3D rectangular border
     90         if (m_bHasBorder) 
     91             pDC->DrawEdge(&rc, EDGE_RAISED, BF_RECT);
     92         // paint the etched button text
     93         pDC->SetTextColor(GetSysColor(COLOR_3DHILIGHT));
     94         pDC->DrawText(strCaption, &tr, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
     95         pDC->SetTextColor(GetSysColor(COLOR_GRAYTEXT));
     96         OffsetRect(&tr, -1, -1);
     97         pDC->DrawText(strCaption, &tr, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
     98     } else {                                        // SELECTED (DOWN) BUTTON
     99         if ( (lpDrawItemStruct->itemState & ODS_SELECTED) || m_bCheck ) {
    100             if(m_bDown.m_hObject==NULL) // no skin selected for selected state -> standard button
    101                 pDC->FillSolidRect(&rc, GetSysColor(COLOR_BTNFACE));
    102             else { // paint the skin
    103                 DrawBitmap(pDC, m_bDown, rc, m_DrawMode);
    104             }
    105             OffsetRect(&tr, 1, 1);  //shift text
    106             // if needed, draw the standard 3D rectangular border
    107             if (m_bHasBorder) 
    108                 pDC->DrawEdge(&rc, EDGE_SUNKEN, BF_RECT);
    109         } else {                                            // DEFAULT BUTTON
    110             if(m_bNormal.m_hObject==NULL) // no skin selected for normal state -> standard button                
    111             {
    112                 CString strRect;
    113                 strRect.Format(L"Rect: %d, %d, %d, %d\n", rc.left, rc.top, rc.right, rc.bottom);
    114                 OutputDebugString(strRect);
    115                 pDC->FillSolidRect(&rc, GetSysColor(COLOR_BTNFACE));
    116             }
    117             else if ( (m_bTrack) && (m_bOver.m_hObject != NULL)) { // paint the skin
    118                     DrawBitmap(pDC, m_bOver, rc, m_DrawMode);
    119             } else {
    120                 if ((lpDrawItemStruct->itemState & ODS_FOCUS)&&(m_bFocus.m_hObject != NULL)) {
    121                     DrawBitmap(pDC, m_bFocus, rc, m_DrawMode);
    122                 } else {
    123                     DrawBitmap(pDC, m_bNormal, rc, m_DrawMode);
    124                 }
    125             }
    126             // if needed, draw the standard 3D rectangular border
    127             if (m_bHasBorder) 
    128                 pDC->DrawEdge(&rc, EDGE_RAISED,BF_RECT);
    129         }
    130         // paint the focus rect
    131         if ((lpDrawItemStruct->itemState & ODS_FOCUS) && (m_nFocusRectMargin > 0)){
    132             rc.left   += m_nFocusRectMargin ;
    133             rc.top    += m_nFocusRectMargin ;
    134             rc.right  -= m_nFocusRectMargin ;
    135             rc.bottom -= m_nFocusRectMargin ;
    136             DrawFocusRect (lpDrawItemStruct->hDC, &rc) ;
    137         }
    138         // paint the enabled button text
    139         pDC->SetTextColor(m_cTextColor);
    140         pDC->DrawText(strCaption,&tr,DT_SINGLELINE|DT_VCENTER|DT_CENTER);
    141     }
    142 }
    143 
    144 int CRgnButton::GetBitmapWidth(CBitmap *bmp)
    145 {
    146     if(!bmp)
    147         return -1;
    148 
    149     BITMAP bm;
    150     bmp->GetBitmap(&bm);
    151 
    152     return bm.bmWidth;
    153 }
    154 
    155 int CRgnButton::GetBitmapHeight(CBitmap *bmp)
    156 {
    157     if(!bmp)
    158         return -1;
    159 
    160     BITMAP bm;
    161     bmp->GetBitmap(&bm);
    162 
    163     return bm.bmHeight;
    164 }
    165 
    166 void CRgnButton::DrawBitmap(CDC* dc, CBitmap &bmp, RECT rc, DRAW_MODE DrawMode)
    167 {
    168     if(DrawMode == DRAW_TILED){
    169         FillWithBitmap(dc, bmp, rc);
    170         return;
    171     }
    172     if(!bmp.GetSafeHandle()) 
    173         return;    //safe check
    174 
    175     CRect cr = rc;
    176     int cx=cr.Width();
    177     int cy=cr.Height();
    178     CDC dcBmp,dcMask;
    179     dcBmp.CreateCompatibleDC(dc);
    180     dcBmp.SelectObject(bmp);
    181 
    182     if (m_bMask.m_hObject!=NULL){
    183         dcMask.CreateCompatibleDC(dc);
    184         dcMask.SelectObject(m_bMask);
    185 
    186         CDC dcMem;
    187         dcMem.CreateCompatibleDC(dc);
    188         CBitmap bmpMem;
    189         bmpMem.CreateCompatibleBitmap(dc,cx,cy);
    190         CBitmap *oldBmp = dcMem.SelectObject(&bmpMem);
    191 
    192         dcMem.BitBlt(cr.left, cr.top, cx, cy, dc, 0, 0, SRCCOPY);
    193         if(DrawMode == DRAW_NORMAL){
    194             dcMem.BitBlt(cr.left, cr.top, cx, cy, &dcBmp, 0, 0, SRCINVERT);
    195             dcMem.BitBlt(cr.left, cr.top, cx, cy, &dcMask, 0, 0, SRCAND);
    196             dcMem.BitBlt(cr.left, cr.top, cx, cy, &dcBmp, 0, 0, SRCINVERT);
    197         } else {
    198             int bx=GetBitmapWidth(&bmp);
    199             int by=GetBitmapHeight(&bmp);
    200             dcMem.StretchBlt(cr.left, cr.top, cx, cy, &dcBmp, 0, 0, bx, by, SRCINVERT);
    201             dcMem.StretchBlt(cr.left, cr.top, cx, cy, &dcMask, 0, 0, bx, by, SRCAND);
    202             dcMem.StretchBlt(cr.left, cr.top, cx, cy, &dcBmp, 0, 0, bx, by, SRCINVERT);
    203         }
    204         dc->BitBlt(cr.left, cr.top, cx, cy, &dcMem, 0, 0, SRCCOPY);
    205 
    206         dcMem.SelectObject(oldBmp);
    207         dcMem.DeleteDC();
    208         bmpMem.DeleteObject();
    209 
    210         DeleteDC(dcMask);
    211     } else {
    212         if( DrawMode == DRAW_NORMAL){
    213             dc->BitBlt(cr.left, cr.top, cx, cy, &dcBmp, 0, 0, SRCCOPY);
    214         } else {
    215             int bx=GetBitmapWidth(&bmp);
    216             int by=GetBitmapHeight(&bmp);
    217             dc->StretchBlt(cr.left, cr.top, cx, cy, &dcBmp, 0, 0, bx, by, SRCCOPY);
    218         }
    219     }
    220     dcBmp.DeleteDC();
    221 }
    222 
    223 void CRgnButton::FillWithBitmap(CDC* dc, CBitmap &bmp, RECT rc)
    224 {
    225     if(!bmp.GetSafeHandle()) 
    226         return;
    227 
    228     CDC dcMem;
    229     dcMem.CreateCompatibleDC(dc);
    230     CBitmap *oldBmp = dcMem.SelectObject(&bmp);
    231 
    232     int w = rc.right - rc.left;
    233     int    h = rc.bottom - rc.top;
    234     int x, y, z;
    235     int    bx=GetBitmapWidth(&bmp);
    236     int    by=GetBitmapHeight(&bmp);
    237 
    238     for (y = rc.top ; y < h ; y += by){
    239         if ( (y + by) > h) 
    240             by = h - y;
    241         z=bx;
    242         for (x = rc.left ; x < w ; x += z){
    243             if ( (x + z) > w) 
    244                 z = w - x;
    245             dc->BitBlt(x, y, z, by, &dcMem, 0, 0, SRCCOPY);
    246         }
    247     }
    248 
    249     dcMem.SelectObject(oldBmp);
    250     dcMem.DeleteDC();
    251 }
    252 
    253 void CRgnButton::PreSubclassWindow()
    254 {
    255     m_Style=GetButtonStyle();    ///get specific BS_ styles
    256     if ( (m_Style & BS_AUTOCHECKBOX) == BS_AUTOCHECKBOX)
    257         m_Style=BS_CHECKBOX;
    258     else if ((m_Style & BS_AUTORADIOBUTTON)==BS_AUTORADIOBUTTON)
    259         m_Style=BS_RADIOBUTTON;
    260     else { m_Style=BS_PUSHBUTTON; }
    261 
    262     CButton::PreSubclassWindow();
    263     ModifyStyle(0, BS_OWNERDRAW);
    264 }
    265 
    266 BOOL CRgnButton::OnEraseBkgnd(CDC* pDC)
    267 {
    268     return TRUE;
    269 
    270 //    return CButton::OnEraseBkgnd(pDC);
    271 }
    272 
    273 void CRgnButton::OnLButtonDown(UINT nFlags, CPoint point)
    274 {
    275     RelayEvent(WM_LBUTTONDOWN, (WPARAM)nFlags, MAKELPARAM(LOWORD(point.x), LOWORD(point.y)));
    276 
    277     //If we are tracking this button, cancel it
    278     if (m_bTrack) {
    279         TRACKMOUSEEVENT t = {
    280             sizeof(TRACKMOUSEEVENT),
    281             TME_CANCEL | TME_LEAVE,
    282             m_hWnd,
    283             0 
    284         };
    285         if (::_TrackMouseEvent(&t)) {
    286             m_bTrack = false;
    287         }
    288     }
    289 
    290     CButton::OnLButtonDown(nFlags, point);
    291     m_bBtnDown = true;
    292 }
    293 
    294 void CRgnButton::OnLButtonUp(UINT nFlags, CPoint point)
    295 {
    296     if (m_Style){ //track mouse for radio & check buttons
    297         POINT p2 = point;
    298         ::ClientToScreen(m_hWnd, &p2);
    299         HWND mouse_wnd = ::WindowFromPoint(p2);
    300         if (mouse_wnd == m_hWnd){ // mouse is in button
    301             if (m_Style==BS_CHECKBOX) 
    302                 SetCheck(m_bCheck ? 0 : 1);
    303             if (m_Style==BS_RADIOBUTTON) 
    304                 SetCheck(1);
    305         }
    306     }
    307     //Pass this message to the ToolTip control
    308     RelayEvent(WM_LBUTTONUP,(WPARAM)nFlags,MAKELPARAM(LOWORD(point.x),LOWORD(point.y)));
    309 
    310     //Default-process the message
    311     m_bBtnDown = false;
    312     CButton::OnLButtonUp(nFlags, point);
    313 }
    314 
    315 void CRgnButton::OnMouseMove(UINT nFlags, CPoint point)
    316 {
    317     RelayEvent(WM_MOUSEMOVE,(WPARAM)nFlags,MAKELPARAM(LOWORD(point.x),LOWORD(point.y)));
    318 
    319     if ( (m_bBtnDown) && (::GetCapture() == m_hWnd)) {
    320         POINT p2 = point;
    321         ::ClientToScreen(m_hWnd, &p2);
    322         HWND mouse_wnd = ::WindowFromPoint(p2);
    323 
    324         bool bPressed = ((GetState() & BST_PUSHED) == BST_PUSHED);
    325         bool bNeedPressed = (mouse_wnd == m_hWnd);
    326         if (bPressed != bNeedPressed) {
    327             SetState(bNeedPressed ? TRUE : FALSE);
    328             Invalidate();
    329         }
    330     } else {
    331         if (!m_bTrack) {
    332             TRACKMOUSEEVENT t = {
    333                 sizeof(TRACKMOUSEEVENT),
    334                 TME_LEAVE,
    335                 m_hWnd,
    336                 0
    337             };
    338             if (::_TrackMouseEvent(&t)) {
    339                 m_bTrack = true;
    340                 Invalidate();
    341             }
    342         }
    343     }
    344 
    345     CButton::OnMouseMove(nFlags, point);
    346 }
    347 
    348 void CRgnButton::OnLButtonDblClk(UINT nFlags, CPoint point)
    349 {
    350     SendMessage(WM_LBUTTONDOWN, nFlags, MAKELPARAM(point.x, point.y));
    351 
    352 //    CButton::OnLButtonDblClk(nFlags, point);
    353 }
    354 
    355 void CRgnButton::OnKillFocus(CWnd* pNewWnd)
    356 {
    357     if (::GetCapture() == m_hWnd) {
    358         ::ReleaseCapture();
    359         ASSERT (!m_bTrack);
    360         m_bBtnDown = false;
    361     }
    362 
    363     CButton::OnKillFocus(pNewWnd);
    364 }
    365 
    366 BOOL CRgnButton::OnBnClicked()
    367 {
    368     if (::GetCapture() == m_hWnd) {
    369         ::ReleaseCapture();
    370         ASSERT (!m_bTrack);
    371     }
    372 
    373     m_bBtnDown = false;
    374     return FALSE;
    375 }
    376 
    377 void CRgnButton::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
    378 {
    379     if ( (m_Style) && (nChar==' ') ){ //needed stuff for check & radio buttons
    380         if (m_Style == BS_CHECKBOX) 
    381             SetCheck(m_bCheck ? 0 : 1);
    382         if (m_Style == BS_RADIOBUTTON) 
    383             SetCheck(1);
    384     }
    385 
    386     CButton::OnKeyDown(nChar, nRepCnt, nFlags);
    387 }
    388 
    389 HRESULT CRgnButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)
    390 {
    391     ASSERT(m_bTrack);
    392 
    393     m_bTrack = false;
    394     Invalidate();
    395 
    396     return 0;
    397 }
    398 
    399 HRESULT CRgnButton::OnRadioInfo(WPARAM wParam, LPARAM lParam)
    400 {
    401     if (m_bCheck){    //only checked buttons need to be unchecked
    402         m_bCheck = false;
    403         Invalidate();
    404     }
    405     return 0;
    406 }
    407 
    408 HRESULT CRgnButton::OnBMSetCheck(WPARAM wParam, LPARAM lParam)
    409 {
    410     m_bCheck = (wParam != 0);
    411 
    412     switch (m_Style)
    413     {
    414     case BS_RADIOBUTTON:
    415         if (m_bCheck) { //uncheck the other radio buttons (in the same group)
    416             HWND hthis,hwnd2,hpwnd;
    417             hpwnd=GetParent()->GetSafeHwnd();    //get button parent handle
    418             hwnd2=hthis=GetSafeHwnd();            //get this button handle
    419             if (hthis && hpwnd){                //consistency check
    420                 for( ; ; ){    //scan the buttons within the group
    421                     hwnd2=::GetNextDlgGroupItem(hpwnd, hwnd2, 0);
    422                     //until we reach again this button
    423                     if ( (hwnd2 == hthis) || (hwnd2 == NULL) ) 
    424                         break;
    425                     //post the uncheck message
    426                     ::PostMessage(hwnd2, WM_CXSHADE_RADIO, 0, 0);
    427                 }
    428             }
    429         }
    430         break;
    431     case BS_PUSHBUTTON:
    432         m_bCheck=false;
    433         ASSERT(false); // Must be a Check or Radio button to use this function
    434     }
    435 
    436     Invalidate();
    437     return 0;
    438 }
    439 
    440 HRESULT CRgnButton::OnBMGetCheck(WPARAM wParam, LPARAM lParam)
    441 {
    442     return m_bCheck;
    443 }
    444 
    445 void CRgnButton::SetSkin(UINT normal, UINT down, UINT over/* =0 */, 
    446              UINT disabled/* =0 */, UINT focus/* =0 */,UINT mask/* =0 */, 
    447              DRAW_MODE drawmode/* =1 */,short border/* =1 */,short margin/* =4 */)
    448 {
    449     m_bNormal.DeleteObject();    //free previous allocated bitmap
    450     m_bDown.DeleteObject();
    451     m_bOver.DeleteObject();
    452     m_bDisable.DeleteObject();
    453     m_bMask.DeleteObject();
    454     m_bFocus.DeleteObject();
    455 
    456     if (normal>0) m_bNormal.LoadBitmap(normal);
    457     if (down>0)      m_bDown.LoadBitmap(down);
    458     if (over>0)      m_bOver.LoadBitmap(over);
    459     if (focus>0)  m_bFocus.LoadBitmap(focus);
    460 
    461     if (disabled>0) 
    462         m_bDisable.LoadBitmap(disabled);
    463     else if (normal>0) 
    464         m_bDisable.LoadBitmap(normal);
    465 
    466     m_DrawMode = (DRAW_MODE)max(0,min(drawmode, DRAW_TILED));
    467     m_bHasBorder = (border > 0);
    468     m_nFocusRectMargin = max(0, margin);
    469 
    470     if (mask>0){
    471         m_bMask.LoadBitmap(mask);
    472         if (m_hClipRgn) 
    473             DeleteObject(m_hClipRgn);
    474         m_hClipRgn = CreateRgnFromBitmap(m_bMask, RGB(255,255,255));
    475         if (m_hClipRgn){
    476             SetWindowRgn(m_hClipRgn, TRUE);
    477             GetDC()->SelectClipRgn(CRgn::FromHandle(m_hClipRgn));
    478         }
    479         if (m_DrawMode == 0){
    480             SetWindowPos(NULL, 0, 0, GetBitmapWidth(&m_bMask),
    481                 GetBitmapHeight(&m_bMask), SWP_NOZORDER|SWP_NOMOVE);
    482         }
    483     }
    484 }
    485 
    486 HRGN CRgnButton::CreateRgnFromBitmap(CBitmap &bmp, COLORREF cTransColor)
    487 {
    488     HRGN hRgn = NULL;
    489     COLORREF cTolerance = RGB(0, 0, 0);
    490     BITMAP bm;
    491 
    492     bmp.GetBitmap(&bm);
    493     CDC dcMem;
    494     dcMem.CreateCompatibleDC(NULL);
    495 
    496     BITMAPINFOHEADER bInfoHead;
    497     bInfoHead.biSize = sizeof(BITMAPINFOHEADER);
    498     bInfoHead.biWidth = bm.bmWidth;
    499     bInfoHead.biHeight = bm.bmHeight; 
    500     bInfoHead.biPlanes = 1; 
    501     bInfoHead.biBitCount = 32; 
    502     bInfoHead.biCompression = BI_RGB; 
    503     bInfoHead.biSizeImage = 0; 
    504     bInfoHead.biXPelsPerMeter = 0; 
    505     bInfoHead.biYPelsPerMeter = 0; 
    506     bInfoHead.biClrUsed = 0; 
    507     bInfoHead.biClrImportant = 0; 
    508 
    509     void *pBit32 = NULL;
    510     HBITMAP hBmp32 = CreateDIBSection(dcMem.GetSafeHdc(), (BITMAPINFO *)&bInfoHead, DIB_RGB_COLORS, &pBit32, NULL, 0);
    511     if(hBmp32) {
    512         CBitmap *pBmp32 = CBitmap::FromHandle(hBmp32);
    513         BITMAP bm32;
    514         pBmp32->GetBitmap(&bm32);
    515         while(bm32.bmWidthBytes % 4)    //round to even
    516             bm32.bmWidthBytes++;
    517 
    518         CBitmap *oldBmp1 = dcMem.SelectObject(pBmp32);
    519         CDC dcTmp;
    520         dcTmp.CreateCompatibleDC(&dcMem);
    521         CBitmap *oldBmp2 = dcTmp.SelectObject(&bmp);
    522 
    523         dcMem.BitBlt(0, 0, bm.bmWidth, bm.bmHeight, &dcTmp, 0, 0, SRCCOPY);
    524 
    525         DWORD maxRects = ALLOC_UNIT;  
    526         HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects));  
    527         RGNDATA *pData = (RGNDATA *)GlobalLock(hData);  
    528         pData->rdh.dwSize = sizeof(RGNDATAHEADER);  
    529         pData->rdh.iType = RDH_RECTANGLES;  
    530         pData->rdh.nCount = pData->rdh.nRgnSize = 0;  
    531         SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
    532 
    533         BYTE lr = GetRValue(cTransColor);
    534         BYTE lg = GetGValue(cTransColor);
    535         BYTE lb = GetBValue(cTransColor);
    536         BYTE hr = MinByte(lr, GetRValue(cTolerance));
    537         BYTE hg = MinByte(lg, GetGValue(cTolerance));
    538         BYTE hb = MinByte(lb, GetBValue(cTolerance));
    539 
    540         BYTE *p32 = (BYTE *)bm32.bmBits + (bm32.bmHeight - 1) * bm32.bmWidthBytes;  
    541         for (int y = 0; y < bm.bmHeight; y++)  
    542         {  
    543             // Scan each bitmap pixel from left to right  
    544             for (int x = 0; x < bm.bmWidth; x++)  
    545             {  
    546                 // Search for a continuous range of "non transparent pixels"  
    547                 int x0 = x;  
    548                 LONG *p = (LONG *)p32 + x;  
    549                 while (x < bm.bmWidth)  
    550                 {  
    551                     BYTE b = GetRValue(*p);  
    552                     if (b >= lr && b <= hr)  
    553                     {  
    554                         b = GetGValue(*p);  
    555                         if (b >= lg && b <= hg)  
    556                         {  
    557                             b = GetBValue(*p);  
    558                             if (b >= lb && b <= hb)  
    559                                 // This pixel is "transparent"  
    560                                 break;  
    561                         }  
    562                     }  
    563                     p++;  
    564                     x++;  
    565                 }  
    566 
    567                 if (x > x0)  
    568                 {
    569                     // Add the pixels (x0, y) to (x, y+1) as a new rectangle in the region  
    570                     if (pData->rdh.nCount >= maxRects)  
    571                     {  
    572                         GlobalUnlock(hData);  
    573                         maxRects += ALLOC_UNIT;  
    574                         hData = GlobalReAlloc(hData, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), GMEM_MOVEABLE);  
    575                         pData = (RGNDATA *)GlobalLock(hData);  
    576                     }  
    577                     RECT *pr = (RECT *)&pData->Buffer;  
    578                     SetRect(&pr[pData->rdh.nCount], x0, y, x, y+1);  
    579                     if (x0 < pData->rdh.rcBound.left)  
    580                         pData->rdh.rcBound.left = x0;  
    581                     if (y < pData->rdh.rcBound.top)  
    582                         pData->rdh.rcBound.top = y;  
    583                     if (x > pData->rdh.rcBound.right)  
    584                         pData->rdh.rcBound.right = x;  
    585                     if (y+1 > pData->rdh.rcBound.bottom)  
    586                         pData->rdh.rcBound.bottom = y+1;  
    587                     pData->rdh.nCount++;  
    588 
    589                     // On Windows98, ExtCreateRegion() may fail if the number of rectangles is too  
    590                     // large (ie: > 4000). Therefore, we have to create the region by multiple steps.  
    591                     if (pData->rdh.nCount == 2000)  
    592                     {  
    593                         HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);  
    594                         if (hRgn)  
    595                         {  
    596                             CombineRgn(hRgn, hRgn, h, RGN_OR);  
    597                             DeleteObject(h);  
    598                         }  
    599                         else 
    600                             hRgn = h;  
    601                         pData->rdh.nCount = 0;  
    602                         SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);  
    603                     }  
    604                 }  
    605             }  
    606 
    607             // Go to next row (remember, the bitmap is inverted vertically)  
    608             p32 -= bm32.bmWidthBytes;  
    609         }  
    610 
    611         HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);  
    612         if (hRgn)  
    613         {  
    614             CombineRgn(hRgn, hRgn, h, RGN_OR);  
    615             DeleteObject(h);  
    616         }  
    617         else 
    618             hRgn = h;  
    619 
    620         // Clean up  
    621         GlobalFree(hData);
    622         dcMem.SelectObject(oldBmp1);
    623         DeleteObject(hBmp32);
    624         dcTmp.SelectObject(oldBmp2);
    625         dcTmp.DeleteDC();
    626     }
    627     dcMem.DeleteDC();
    628 
    629     return hRgn;
    630 }
    631 
    632 COLORREF CRgnButton::SetTextColor(COLORREF colorNew)
    633 {
    634     COLORREF colorTmp = m_cTextColor;
    635     m_cTextColor = colorNew;
    636 
    637     return colorTmp;
    638 }
    639 
    640 void CRgnButton::SetToolTipText(const CString &strTip)
    641 {
    642     if(m_Tooltip.m_hWnd==NULL){
    643         if(m_Tooltip.Create(this))    //first assignment
    644             if(m_Tooltip.AddTool(this, strTip))
    645                 m_Tooltip.Activate(1);
    646     } else {
    647         m_Tooltip.UpdateTipText(strTip,this);
    648     }
    649 }
    650 
    651 void CRgnButton::RelayEvent(UINT message, WPARAM wParam, LPARAM lParam)
    652 {
    653     if(NULL != m_Tooltip.m_hWnd){
    654         MSG msg;
    655         msg.hwnd = m_hWnd;
    656         msg.message = message;
    657         msg.wParam = wParam;
    658         msg.lParam = lParam;
    659         msg.time = 0;
    660         msg.pt.x = LOWORD(lParam);
    661         msg.pt.y = HIWORD(lParam);
    662 
    663         m_Tooltip.RelayEvent(&msg);
    664     }
    665 }
  • 相关阅读:
    cento7快速修改主机名和修改root密码
    [goolegke]nginxingress建立测试
    filebeat安装读取nginx json日志
    MySQL索引背后的数据结构及算法原理
    Lua脚本在redis分布式锁场景的运用
    Sentinel实现限流
    java架构技术流程图
    mybatis数据加解密处理方案
    vue 自定义代码片段
    node项目vue 自动化部署之pm2
  • 原文地址:https://www.cnblogs.com/jojodru/p/2652856.html
Copyright © 2020-2023  润新知