4.VC按钮显示图片

1. 简单加载BITMAP显示,缺点是:图片固定大小,不会自动拉伸

//资源文件里导入一张BITMAP,如 IDC_BITMAP1
//设置Button的Bitmap 属性为 TRUE


//.cpp
CBitmap PpBitmap = new CBitmap(); //创建图片对象
pBitmap->LoadBitmapA(IDB_BITMAP1); //从资源中加载图片

HBITMAP hBitmap = (HBITMAP)pBitmap->Detach();
m_btn1.SetBitmap(hBitmap); //按钮显示图片

效果如图:

 

 

简单加载 ICON文件,显示在Button上:

//资源文件 添加一个 ICON,ID为 IDI_ICON1,并设置Icon属性为TRUE

.h定义一个 HICON m_hIcon1;

.cpp

m_hIcon1 = AfxGetApp()->LoadIcon(IDI_ICON1);

m_btn1.SetIcon(m_hIcon1);

 

2.点击按钮后出现边框的效果。 (用处不大)

//将Button的 Owner Draw属性设置为TRUE
//在父窗口重载 虚函数 ON_WM_DRAWITEM -> OnDrawItem

void xxxDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    if (nIDCtl == IDC_BUTTON2)
    {
        //绘制按钮框架
        UINT uStyle = DFCS_BUTTONPUSH;
        //是否按下去了
        if (lpDrawItemStruct->itemState & ODS_SELECTED )
        {
            uStyle |= DFCS_PUSHED;
        }

        CDC dc;
        dc.Attach(lpDrawItemStruct->hDC);
        dc.DrawFrameControl(&lpDrawItemStruct->rcItem, DFC_BUTTON, uStyle);
        //输出文字
        dc.SelectObject(&m_font);
        dc.SetTextColor(RGB(0,0, 255));

        CString strText;
        strText = _T("Sylar Test");
        dc.TextOut(lpDrawItemStruct->rcItem.left + 40, lpDrawItemStruct->rcItem.top + 25, strText);
        //是否得到焦点
        if (lpDrawItemStruct->itemState & ODS_FOCUS)
        {
            //画虚框
            CRect rcFocus = lpDrawItemStruct->rcItem;
            rcFocus.DeflateRect(3, 3);
            dc.DrawFocusRect(&rcFocus);
        }
        return;
    }

    CDialogEx::OnDrawItem(nIDCtl, lpDrawItemStruct);
}

//字体设置
CFont m_font;
m_font.CreatePointFont(100, _T("宋体"), NULL);

效果如图:

 

 

3.实现 Normal, 鼠标移入, 鼠标点击 时按钮的3种不同状态(ICON还是同一个ICON,只是背景色不同的特效).

//资源 修改 Button 的 Owner Draw 为 True

//.h 新建类,继承自 CButton
//3种状态背景色, Normal、鼠标移入、鼠标按下
COLORREF m_normalClr;
COLORREF m_activeClr;
COLORREF m_pressedClr;
void SetNormalBkColor(COLORREF clr);
void SetActiveBkColor(COLORREF clr);
void SetPressedBkColor(COLORREF clr);
//字体颜色
COLORREF m_txtClr;
void SetTextColor(COLORREF clr);

//图像列表 用来保存 Icon
CImageList * m_pImageList;
void SetImageList(CImageList * pImage);
int m_nImageIndex; //图标索引
void SetImageIndex(int index);

//鼠标是否移入按钮中
BOOL m_bActive; //初始化为FALSE

//重新实现 DrawItem ,重载 OnMouseMove函数
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); //注意这里是DrawItem,不要用类向导添加 WM_DRAWITEM,否则程序会崩溃。

afx_msg void OnMouseMove(UINT nFlags, CPoint point);

//.cpp 具体实现
void xxx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
      CString text;
    CDC dc ;
    dc.Attach(lpDrawItemStruct->hDC);
    CRect clinetRect;
    GetClientRect(clinetRect);    
    dc.SetTextColor(RGB(0, 0, 255)); //设置文字颜色,蓝色
    CBrush brush;
    if (!m_bActive) //鼠标不在按钮内
    { //Normal 形态
        brush.CreateSolidBrush(m_normalBkColor);
        dc.FillRect(&clinetRect, &brush);    
    }
    else
    {
        if (lpDrawItemStruct->itemState & ODS_SELECTED) //按钮按下
        {
            brush.CreateSolidBrush(m_pressedBkColor); //Pressed 形态
        }
        else
        {
            brush.CreateSolidBrush(m_activeBkColor); //鼠标移入按钮内 形态
        }
        dc.FillRect(&clinetRect, &brush);

        CBrush brush1; //按钮边框颜色
        brush1.CreateSolidBrush(RGB(0, 0, 255)); //蓝色        
        dc.FrameRect(&clinetRect, &brush1); //用指定画刷画边框

    }
    if (m_pImagelist)
    {    
        //获取图像列中图像大小
        IMAGEINFO imageinfo;
        m_pImagelist->GetImageInfo(m_ImageIndex,&imageinfo);
        CSize imagesize;
        imagesize.cx = imageinfo.rcImage.right - imageinfo.rcImage.left;
        imagesize.cy = imageinfo.rcImage.bottom - imageinfo.rcImage.top;
        //在按钮垂直方向居中显示位图
        CPoint point;
        point.x = 2;
        point.y = (clinetRect.Height() - imagesize.cy)/2;
        m_pImagelist->Draw(&dc, m_ImageIndex, point, ILD_NORMAL | ILD_TRANSPARENT);
        //绘制按钮文本
        GetWindowText(text);
        clinetRect.DeflateRect(point.x + imagesize.cx + 2, 0, 0, 0); //通过朝CRect的中心移动边以缩小CRect;此处缩小了CRect的左边
        dc.SetBkMode(TRANSPARENT);
        dc.DrawText(text,clinetRect,DT_LEFT | DT_SINGLELINE | DT_VCENTER);    
    }
    else
    {
        GetWindowText(text);
        dc.SetBkMode(TRANSPARENT);
        dc.DrawText(text,clinetRect,DT_CENTER | DT_SINGLELINE | DT_VCENTER);    
    }
}

void xxx::OnMouseMove(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    CButton::OnMouseMove(nFlags, point);
    ClientToScreen(&point);
    HWND hwnd = ::WindowFromPoint(point);
    if (hwnd == this->m_hWnd)
    {    
        SetCapture(); //设置鼠标捕获。包括onmousedown、onmouseup、onclick、ondblclick、onmouseover和onmouseout
        if (!m_bActive) //不在按钮内
            Invalidate();
        m_bActive = TRUE;
    }
    else
    {
        ReleaseCapture(); //取消鼠标捕获
        m_bActive = FALSE;
        Invalidate();
    }
}

在对话框Dlg中:

//xxxDlg.h
CImageList m_images; //加载Icon图标的List

//xxxDlg.cpp
m_images.Create(32, 32, ILC_COLOR32 | ILC_MASK, 1, 0);
m_images.Add(AfxGetApp()->LoadIcon(IDI_ICON1)); //加载图标
m_images.Add(AfxGetApp()->LoadIcon(IDI_ICON2));

//设置图像列表
m_btn3.SetImageList(&m_images);                
m_btn4.SetImageList(&m_images);

//设置显示图像的索引
m_btn3.SetImageIndex(0);
m_btn4.SetImageIndex(1);

//设置按钮背景色
m_btn3.SetNormalBkColor(RGB(0xd2, 0xd2, 0xe3));
m_btn3.SetActiveBkColor(RGB(0xd8, 0xf6, 0xfc));
m_btn3.SetPressedBkColor(RGB(0xbb, 0xec, 0xf9));

m_btn4.SetNormalBkColor(RGB(0xd2, 0xd2, 0xe3));
m_btn4.SetActiveBkColor(RGB(0xd8, 0xf6, 0xfc));
m_btn4.SetPressedBkColor(RGB(0xbb, 0xec, 0xf9));

工程名:ImageButton; 效果图如下:

  Normal 普通模式

 Active 鼠标移入按钮(多了个边框)

 Pressed 按下(底色深了些)

 

4.实现 鼠标移入, 移出 时显示不同 Icon 的特效。

//资源 Button的 Owner Draw 设置为TRUE
//添加2张ICON图,分别为鼠标移入和移出的图标

//.h

#pragma pack(1)
typedef struct _STRUCT_ICONS
{
    HICON        hIcon;            // Handle to icon
    DWORD        dwWidth;        // Width of icon
    DWORD        dwHeight;        // Height of icon
} STRUCT_ICONS;
#pragma pack()

STRUCT_ICONS m_csIcons[2];

BOOL SetIcon(int nIconIn, int nIconOut = NULL); //传入2个ID,设置鼠标移入/移出 的ICON图
BOOL SetIcon(HICON hIconIn, HICON hIconOut);
void FreeResources(); //清空 m_csIcons 数组内容

virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);

BOOL m_bMouseOnButton; //鼠标是否在按钮内;初始化为FALSE
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);

//.cpp

BOOL xxx::SetIcon(int nIconIn, int nIconOut)
{
    HICON        hIconIn            = NULL;
    HICON        hIconOut        = NULL;
    HINSTANCE    hInstResource    = NULL;

    // Find correct resource handle
    hInstResource = AfxFindResourceHandle(MAKEINTRESOURCE(nIconIn), RT_GROUP_ICON);

    // Set icon when the mouse is IN the button
    hIconIn = (HICON)::LoadImage(hInstResource, MAKEINTRESOURCE(nIconIn), IMAGE_ICON, 0, 0, 0);

    // Set icon when the mouse is OUT the button
    if (nIconOut)
    {
        hIconOut = (HICON)::LoadImage(hInstResource, MAKEINTRESOURCE(nIconOut), IMAGE_ICON, 0, 0, 0);
    }

    return SetIcon(hIconIn, hIconOut);
}

BOOL xxx::SetIcon(HICON hIconIn, HICON hIconOut)
{
    BOOL bRet;
    ICONINFO ii;

    // Free any loaded resource
    FreeResources();

    if (hIconIn)
    {
        // Icon when mouse over button?
        m_csIcons[0].hIcon = hIconIn;
        // Get icon dimension
        ::ZeroMemory(&ii, sizeof(ICONINFO));
        bRet = ::GetIconInfo(hIconIn, &ii);
        if (bRet == FALSE)
        {
            FreeResources();
            return FALSE;
        } // if

        m_csIcons[0].dwWidth = (DWORD)(ii.xHotspot * 2);
        m_csIcons[0].dwHeight = (DWORD)(ii.yHotspot * 2);
        ::DeleteObject(ii.hbmMask);
        ::DeleteObject(ii.hbmColor);

        // Icon when mouse outside button?
        if (hIconOut)
        {
            m_csIcons[1].hIcon = hIconOut;
            // Get icon dimension
            ::ZeroMemory(&ii, sizeof(ICONINFO));
            bRet = ::GetIconInfo(hIconOut, &ii);
            if (bRet == FALSE)
            {
                FreeResources();
                return FALSE;
            } // if

            m_csIcons[1].dwWidth    = (DWORD)(ii.xHotspot * 2);
            m_csIcons[1].dwHeight    = (DWORD)(ii.yHotspot * 2);
            ::DeleteObject(ii.hbmMask);
            ::DeleteObject(ii.hbmColor);
        } // if
    } // if

    Invalidate();

    return TRUE;
} // End of SetIcon


void xxx::FreeResources()
{
    if (m_csIcons[0].hIcon)
    {
        ::DestroyIcon(m_csIcons[0].hIcon);
    }
    if (m_csIcons[1].hIcon)    
    {
        ::DestroyIcon(m_csIcons[1].hIcon);
    }

    ::ZeroMemory(&m_csIcons, sizeof(m_csIcons));
} // End of FreeResources


void xxx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    CDC * pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    CRect captionRect = lpDrawItemStruct->rcItem;

    CRect clinetRect;
    GetClientRect(clinetRect);  

    // Draw the icon
    if (m_csIcons[0].hIcon)
    {
        BYTE byIndex = 0;
        // Select the icon to use
        if (m_bMouseOnButton) //鼠标在按钮上
        {
       byIndex = 0; //显示图标0
}
else //鼠标不在按钮上
{
byIndex = (m_csIcons[1].hIcon == NULL ? 0 : 1); //存在则显示图标1
} CRect rImage; rImage
= lpDrawItemStruct->rcItem; pDC->DrawState( rImage.TopLeft(), rImage.Size(), m_csIcons[byIndex].hIcon, DSS_NORMAL, (CBrush*)NULL); } // if CString sTitle; GetWindowText(sTitle); // Button 有文字则输出 if (sTitle.IsEmpty() == FALSE) { pDC->SetBkMode(TRANSPARENT); pDC->DrawText(sTitle,clinetRect,DT_CENTER | DT_SINGLELINE | DT_VCENTER); } // if } void xxx::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CButton::OnMouseMove(nFlags, point); ClientToScreen(&point); HWND hwnd = ::WindowFromPoint(point); if (hwnd == this->m_hWnd) { SetCapture(); //设置鼠标捕获。包括onmousedown、onmouseup、onclick、ondblclick、onmouseover和onmouseout if (!m_bMouseOnButton) //不在按钮内 Invalidate(); m_bMouseOnButton = TRUE; } else { ReleaseCapture(); //取消鼠标捕获 m_bMouseOnButton = FALSE; Invalidate(); } }
//xxxDlg.cpp
m_btn1.SetIcon(IDI_ICON2, IDI_ICON1); //ICON1 无眼睛, ICON2 有眼睛

工程名:ImageButton2; 效果图如下:

鼠标未移入:

鼠标移入:

(同理实现鼠标点击,再次点击时2个图标的切换。)

 

5.一张彩色Icon,鼠标不在按钮上时为灰色/暗色, 鼠标移入则变成彩色。(原理跟4差不多,简单的方法是用PS将第一张彩色ICON P成灰色色即可。这里是代码里调成灰色/暗色)

//在上面4的基础上做得修改

//资源去掉 Button 的 Owner Draw 属性,设为 FALSE

//.h
#define BT_AUTO_GRAY (HICON)(0xffffffff - 1L) //灰色
#define BT_AUTO_DARKER (HICON)(0xffffffff - 2L) //暗色

//重载虚函数 PreSubWindow,这样就可以不用设置Owner Draw属性
virtual void PreSubWindow();
BOOL m_nTyleStyle; //按钮Style

//将一张彩色图片变成 灰色
HICON CreateGrayscaleIcon(HICON hIcon);
//彩色ICON 变暗色
COLORREF DarkenColor(COLORREF crColor, double dFactor);
HICON CreateDarkerIcon(HICON hIcon);

//.cpp的代码到时回家再补上,现在只说修改的地方
void xxx::PreSubclassWindow()
{
  UINT nBS;
  nBS = GetButtonStyle();

  m_nTypeStyle = nBS & BS_TYPEMASK;

  if (m_nTypeStyle == BS_DEFPUSHBUTTON)
  {
    m_nTypeStyle = BS_PUSHBUTTON;
  }
  ASSERT(m_nTypeStyle != BS_OWNERDRAW);

  ModifyStyle(BS_TYPEMASK, BS_OWNERDRAW, SWP_FRAMECHANGED);

  CButton::PreSubclassWindow();
}


HICON xxx::CreateGrayscaleIcon(HICON hIcon)
{
    HICON        hGrayIcon = NULL;
    HDC            hMainDC = NULL, hMemDC1 = NULL, hMemDC2 = NULL;
    BITMAP        bmp;
    HBITMAP        hOldBmp1 = NULL, hOldBmp2 = NULL;
    ICONINFO    csII, csGrayII;
    BOOL        bRetValue = FALSE;

    bRetValue = ::GetIconInfo(hIcon, &csII);
    if (bRetValue == FALSE)    return NULL;

    hMainDC = ::GetDC(NULL);
    hMemDC1 = ::CreateCompatibleDC(hMainDC);
    hMemDC2 = ::CreateCompatibleDC(hMainDC);
    if (hMainDC == NULL || hMemDC1 == NULL || hMemDC2 == NULL)    return NULL;

    if (::GetObject(csII.hbmColor, sizeof(BITMAP), &bmp))
    {
        DWORD    dwWidth = csII.xHotspot*2;
        DWORD    dwHeight = csII.yHotspot*2;

        csGrayII.hbmColor = ::CreateBitmap(dwWidth, dwHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
        if (csGrayII.hbmColor)
        {
            hOldBmp1 = (HBITMAP)::SelectObject(hMemDC1, csII.hbmColor);
            hOldBmp2 = (HBITMAP)::SelectObject(hMemDC2, csGrayII.hbmColor);

            //::BitBlt(hMemDC2, 0, 0, dwWidth, dwHeight, hMemDC1, 0, 0, SRCCOPY);

            DWORD        dwLoopY = 0, dwLoopX = 0;
            COLORREF    crPixel = 0;
            BYTE        byNewPixel = 0;

            for (dwLoopY = 0; dwLoopY < dwHeight; dwLoopY++)
            {
                for (dwLoopX = 0; dwLoopX < dwWidth; dwLoopX++)
                {
                    crPixel = ::GetPixel(hMemDC1, dwLoopX, dwLoopY);
                    byNewPixel = (BYTE)((GetRValue(crPixel) * 0.299) + (GetGValue(crPixel) * 0.587) + (GetBValue(crPixel) * 0.114));

                    if (crPixel)    
                        ::SetPixel(hMemDC2, dwLoopX, dwLoopY, RGB(byNewPixel, byNewPixel, byNewPixel));
                    else
                        ::SetPixel(hMemDC2, dwLoopX, dwLoopY, crPixel);
                } // for
            } // for

            ::SelectObject(hMemDC1, hOldBmp1);
            ::SelectObject(hMemDC2, hOldBmp2);

            csGrayII.hbmMask = csII.hbmMask;

            csGrayII.fIcon = TRUE;
            hGrayIcon = ::CreateIconIndirect(&csGrayII);
        } // if

        ::DeleteObject(csGrayII.hbmColor);
        //::DeleteObject(csGrayII.hbmMask);
    } // if

    ::DeleteObject(csII.hbmColor);
    ::DeleteObject(csII.hbmMask);
    ::DeleteDC(hMemDC1);
    ::DeleteDC(hMemDC2);
    ::ReleaseDC(NULL, hMainDC);

    return hGrayIcon;
} // End of CreateGrayscaleIcon

HICON xxx::CreateDarkerIcon(HICON hIcon)
{
    HICON        hGrayIcon = NULL;
    HDC            hMainDC = NULL, hMemDC1 = NULL, hMemDC2 = NULL;
    BITMAP        bmp;
    HBITMAP        hOldBmp1 = NULL, hOldBmp2 = NULL;
    ICONINFO    csII, csGrayII;
    BOOL        bRetValue = FALSE;

    bRetValue = ::GetIconInfo(hIcon, &csII);
    if (bRetValue == FALSE)    return NULL;

    hMainDC = ::GetDC(NULL);
    hMemDC1 = ::CreateCompatibleDC(hMainDC);
    hMemDC2 = ::CreateCompatibleDC(hMainDC);
    if (hMainDC == NULL || hMemDC1 == NULL || hMemDC2 == NULL)    return NULL;

    if (::GetObject(csII.hbmColor, sizeof(BITMAP), &bmp))
    {
        DWORD    dwWidth = csII.xHotspot*2;
        DWORD    dwHeight = csII.yHotspot*2;

        csGrayII.hbmColor = ::CreateBitmap(dwWidth, dwHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
        if (csGrayII.hbmColor)
        {
            hOldBmp1 = (HBITMAP)::SelectObject(hMemDC1, csII.hbmColor);
            hOldBmp2 = (HBITMAP)::SelectObject(hMemDC2, csGrayII.hbmColor);

            //::BitBlt(hMemDC2, 0, 0, dwWidth, dwHeight, hMemDC1, 0, 0, SRCCOPY);

            DWORD        dwLoopY = 0, dwLoopX = 0;
            COLORREF    crPixel = 0;

            for (dwLoopY = 0; dwLoopY < dwHeight; dwLoopY++)
            {
                for (dwLoopX = 0; dwLoopX < dwWidth; dwLoopX++)
                {
                    crPixel = ::GetPixel(hMemDC1, dwLoopX, dwLoopY);

                    if (crPixel)    
                        ::SetPixel(hMemDC2, dwLoopX, dwLoopY, DarkenColor(crPixel, 0.25));
                    else
                        ::SetPixel(hMemDC2, dwLoopX, dwLoopY, crPixel);
                } // for
            } // for

            ::SelectObject(hMemDC1, hOldBmp1);
            ::SelectObject(hMemDC2, hOldBmp2);

            csGrayII.hbmMask = csII.hbmMask;

            csGrayII.fIcon = TRUE;
            hGrayIcon = ::CreateIconIndirect(&csGrayII);
        } // if

        ::DeleteObject(csGrayII.hbmColor);
        //::DeleteObject(csGrayII.hbmMask);
    } // if

    ::DeleteObject(csII.hbmColor);
    ::DeleteObject(csII.hbmMask);
    ::DeleteDC(hMemDC1);
    ::DeleteDC(hMemDC2);
    ::ReleaseDC(NULL, hMainDC);

    return hGrayIcon;
} // End of CreateDarkerIcon

COLORREF xxx::DarkenColor(COLORREF crColor, double dFactor)
{
    if (dFactor > 0.0 && dFactor <= 1.0)
    {
        BYTE red,green,blue,lightred,lightgreen,lightblue;
        red = GetRValue(crColor);
        green = GetGValue(crColor);
        blue = GetBValue(crColor);
        lightred = (BYTE)(red-(dFactor * red));
        lightgreen = (BYTE)(green-(dFactor * green));
        lightblue = (BYTE)(blue-(dFactor * blue));
        crColor = RGB(lightred,lightgreen,lightblue);
    } // if

    return crColor;
} // End of DarkenColor

//DrawItem函数 OnMouseMove函数与5相同。
//.dlg
m_btn2.SetIcon(IDI_ICON3, (int)BTNST_AUTO_GRAY); //BTNST_AUTO_DARKER暗色; BTNST_AUTO_GRAY灰色

工程名: ImageButton2, 效果如图:

 鼠标不在按钮上

 鼠标移入按钮

 

6.绘制边框的问题。鼠标点击才改变图案。

7.实现 Bimap 替换Icon 时的同样效果。 

posted @ 2016-05-19 00:28  SylarLiang_VC  阅读(1985)  评论(0编辑  收藏  举报