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 时的同样效果。