• 自绘按钮


    ━━━━━━━━━━━━━━━━━━━━━━━━
        突然心血来潮,想写一个自绘按钮的类。以前做这事会觉得很辛苦,但现在随着自己知识和经验的增长,一切都变得简单很多了。刚刚做好,现与诸位分享。若有不正确之处,还望各位海涵并给于斧正。阿弥陀佛!^-^
    ━━━━━━━━━━━━━━━━━━━━━━━━

    一、如何使用:
        1.把MyButton.cpp 和 MyButton.h 添加到你的工程里。
        2.包含头文件 #include "MyButton.h"
        3.在OnInitDialog()中添加以代码。(一切搞掂,是不是很方便呢)
        BOOL CDemoDlg::OnInitDialog()
        {
            //子类化单个按钮。
            //button close 时在 PostNcDestroy() 会调用delete this清除对象
            CMyButton*p1 =new CMyButton(m_hWnd,IDC_BUTTON1);
            CMyButton*p2 =new CMyButton(m_hWnd,IDC_BUTTON2);

        return TRUE;
        }

        4.需要子类化所有button时,按如下调用:
        BOOL CDemoDlg::OnInitDialog()
        {
            //子类化所有按钮
            CMyButton::SubclassAllButton(m_hWnd);

        return TRUE;
        }

    ━━━━━━━━━━━━━━━━━━━━━━━━
    二、几个重点:
        1.要设置button为自绘。如下代码“ModifyStyle(0, BS_OWNERDRAW);”
        2、要手动添加鼠标离开窗口的消息(若不懂,请看捕获鼠标离开窗口的消息)
            http://hi.baidu.com/qiujiejia/blog/item/f22d012488c7880f4c088def.html
        3.成员函数DrawGradientV是画一个颜色渐变的矩形,你可以把它直接移植出来应用在你的工程里
        4.DrawMyItem函数分成三个步骤。
        (1)画渐变背景
        (2)画空的矩形框作为按钮的边框
        (3)画文字(如果鼠标按下,则偏移文字)

    ━━━━━━━━━━━━━━━━━━━━━━━━

    三、把自绘按钮封装成一个dll

    你只需要把ButtonSkin.dll放在工程目录下,并且在对话框初始化时添加以下代码即可使所有button都换上皮肤,很方便。
      
    //加载按钮皮肤
        HINSTANCE hInst1;
        if (hInst1=LoadLibrary("ButtonSkin.dll"))
        {
            void (*SubclassButton)(HWND)=(void(*)(HWND))GetProcAddress(hInst1,"SubclassButton");
            if(SubclassButton)     SubclassButton(m_hWnd);
        }

    ButtonSkin.dll 下载:ButtonSkin.dll
    详细代码请参考源程序:ButtonSkin source code

    ━━━━━━━━━━━━━━━━━━━━━━━━

    四、部分重要代码

    CMyButton::CMyButton(HWND ParentWnd,UINT nID)
    {
       SubclassWindow(::GetDlgItem(ParentWnd,nID)); //子类化
    }

    void CMyButton::PreSubclassWindow()
    {
       m_IsInWindow=false;
       ModifyStyle(0, BS_OWNERDRAW);               //修改为自绘button
       ::GetClientRect(m_hWnd,&rect);               //获取button的矩形区域
       CButton::PreSubclassWindow();
    }

    /****************************************************************************
    //子类化所有按钮
    ****************************************************************************/
    void CMyButton::SubclassAllButton(HWND ParentWnd)
    {
       HWND hChild = ::GetWindow(ParentWnd, GW_CHILD);
       while(hChild != NULL)
       {
            TCHAR lpClassName[MAX_PATH];
            ::GetClassName(hChild,lpClassName,MAX_PATH); //获得窗口类名
            if (_tcscmp(lpClassName,_T("Button"))==0)
            {
                // 判断按钮类型, 确保不是单选或复选按钮
                DWORD dwStyle = GetWindowLong(hChild, GWL_STYLE);
                dwStyle = dwStyle & 0x0000000F;
                if(dwStyle == BS_PUSHBUTTON || dwStyle == BS_DEFPUSHBUTTON)
                {
                    //button close 时在 PostNcDestroy() 会调用delete this清除对象
                    CMyButton* p=new CMyButton();
                    p->SubclassWindow(hChild); //子类化
                }
            }
            hChild=::GetWindow(hChild, GW_HWNDNEXT);
       }
    }

    /****************************************************************************
    在鼠标第一次进入窗口时,绘制按钮的over效果
    ****************************************************************************/
    void CMyButton::OnMouseMove(UINT nFlags, CPoint point)
    {
       if (!m_IsInWindow)
       {
            m_IsInWindow = TRUE;
            TRACKMOUSEEVENT trackmouseevent;
            trackmouseevent.cbSize = sizeof(trackmouseevent);
            trackmouseevent.dwFlags = TME_LEAVE;
            trackmouseevent.hwndTrack = GetSafeHwnd();
            trackmouseevent.dwHoverTime = HOVER_DEFAULT;
            _TrackMouseEvent(&trackmouseevent);  

            //draw move over effect
            DrawMyItem(RGB(0,225,225),RGB(175,238,238));
       }  
       CButton::OnMouseMove(nFlags, point);
    }

    /****************************************************************************
    鼠标离开按钮,置m_IsInWindow为false,并刷新按钮
    ****************************************************************************/
    LRESULT CMyButton::OnMouseLeave(WPARAM wParam, LPARAM lParam)
    {  
       m_IsInWindow=false;      
       InvalidateRect(NULL);
       return 0;
    }  

    /****************************************************************************
    核心代码。
    COLORREF co1, COLORREF co2 组合成渐变色
    ****************************************************************************/
    void CMyButton::DrawMyItem(COLORREF co1, COLORREF co2)
    {
       HDC hdc=::GetDC(m_hWnd);

       //draw gradient effect
       DrawGradientV(hdc,co1,co2,rect);

       //draw a null rectangle as the button frame
       HBRUSH OldBrush=(HBRUSH)::SelectObject(hdc,(HBRUSH)GetStockObject(NULL_BRUSH));
       ::Rectangle(hdc,0,0,rect.right-rect.left,rect.bottom-rect.top);
       ::SelectObject (hdc,OldBrush) ;

       //draw button text
       TCHAR WindowText[100];
       ::GetWindowText(m_hWnd, WindowText, MAX_PATH);

       //设置文字透明
       int nMode=::SetBkMode(hdc,TRANSPARENT);  

       //鼠标按下时字体偏移
       if (GetKeyState(VK_LBUTTON)<0)
       {
            CRect TempRect=rect;
            TempRect.OffsetRect(1,1);
            ::DrawText (hdc,WindowText, -1,&TempRect,DT_SINGLELINE | DT_CENTER | DT_VCENTER |DT_VCENTER|DT_END_ELLIPSIS ) ;
       }  
       else
            ::DrawText (hdc,WindowText, -1,&rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER |DT_VCENTER|DT_END_ELLIPSIS ) ;

       ::SetBkMode(hdc,nMode);

       ::ReleaseDC(m_hWnd,hdc);
    }



    /****************************************************************************
    收到消息要求我们来绘制button
    ****************************************************************************/
    void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
    {
       if (lpDrawItemStruct->itemState & ODS_FOCUS )
       {
            if (lpDrawItemStruct->itemState & ODS_SELECTED ) //鼠标按下并且在窗口外
                DrawMyItem(RGB(0,255,0),RGB(0,255,200));
            else
                DrawMyItem(RGB(49,68,212),RGB(147,255,255)); //获得焦点的效果
       }
       else
            DrawMyItem(RGB(253,181,81),RGB(253,255,206)); //没有获得焦点的效果
    }




    /****************************************************************************
    绘制垂直颜色渐变区域
    DrawGradientV(   HDC hdc           //绘图刷子
                    COLORREF co1   //顶端颜色
                    COLORREF co2   //低端颜色
                    RECT& DrawRect)   //颜色渐变区域
    ****************************************************************************/

    //设置渐变参数,GRADLEVEL越小,颜色渐变越细腻,过度效果越好,但速度比较慢
    #define GRADLEVEL 1  

    void CMyButton::DrawGradientV( HDC hdc, COLORREF co1, COLORREF co2, RECT& DrawRect )
    {
       int r = GetRValue( co1 );
       int g = GetGValue( co1 );
       int b = GetBValue( co1 );
      
       int r2 = GetRValue( co2 );
       int g2 = GetGValue( co2 );
       int b2 = GetBValue( co2 );

       //计算宽,高
       int DrawRectWidth=DrawRect.right-DrawRect.left;
       int DrawRectHeight=DrawRect.bottom-DrawRect.top;

       if ( DrawRectWidth<=0)
            return;

       //初始化rect
       RECT rect={0,0,DrawRectWidth,GRADLEVEL};
      
       //准备GDI
       HDC hMemDC=CreateCompatibleDC(hdc);               //创建内存DC
       HBITMAP hBitmap=::CreateCompatibleBitmap(hdc,DrawRectWidth,DrawRectHeight);//创建位图
       ::SelectObject(hMemDC,hBitmap);       //把位图选进内存DC
       HBRUSH hbr;


       for(int i = DrawRectHeight; i > 0; i -= GRADLEVEL )
       {
            //创建刷子
            hbr = CreateSolidBrush( RGB( r, g, b ) );
            FillRect( hMemDC, &rect, hbr );
            DeleteObject( hbr );

            //改变小正方体的位置
            rect.top += GRADLEVEL;
            rect.bottom += GRADLEVEL;

            //判断小正方体是否超界
            if( rect.bottom > DrawRect.bottom )
                rect.bottom = DrawRect.bottom;
           
            //改变颜色
            r += ( r2 - r + i / 2 ) / i * GRADLEVEL;
            g += ( g2 - g + i / 2 ) / i * GRADLEVEL;
            b += ( b2 - b + i / 2 ) / i * GRADLEVEL;
       }

       //内存DC映射到屏幕DC
       BitBlt(hdc,DrawRect.left,DrawRect.top,DrawRectWidth,DrawRectHeight,hMemDC,0,0,SRCCOPY);  

       //删除
       ::DeleteDC(hMemDC) ;                      
       ::DeleteObject(hBitmap);  
    }




    void CMyButton::PostNcDestroy()
    {
       delete this;  
       CButton::PostNcDestroy();
    }

    ━━━━━━━━━━━━━━━━━━━━━━━━
  • 相关阅读:
    java微信扫码支付(模式二)
    Python学习08
    学习java第12天
    学习java第11天
    学习java第十天
    学习Java第九天
    学习Java第八天
    学习Java第六天
    学习Java第六天
    学习Java第五天
  • 原文地址:https://www.cnblogs.com/jinsedemaitian/p/5589155.html
Copyright © 2020-2023  润新知