示例图
一、公共文件
和这篇一样,就不写了(MFC-自绘控件(CButton篇))
二、CComBox头文件
#pragma once #include "Public.h" #include <vector> using std::vector; typedef struct tagITEMLIST { HICON hIcon; //图标 CString strUrl; //Url地址 COLORREF clrLeft; //左边文本的颜色 UINT iItem; //ID 号 }ItemList, *PItemList; #define DEF_FRAME_COLOR RGB(40,138,228) #define DEF_TEXT_COLOR RGB(0,0,0) #define DEF_BG_COLOR RGB(210,210,210) #define DEF_SELECT_COLOR RGB(250,250,250) //组合框类 class CPngComboBox : public CComboBox { public: //构造函数 CPngComboBox(); //析构函数 virtual ~CPngComboBox(); public: // 添加元素 void AddNewString(CString leftText,UINT icon = NULL,COLORREF leftColor = DEF_TEXT_COLOR); // 设置尾部图标 void SetEndIcon(UINT endIcon); // 设置颜色 void SetComboColor(COLORREF crFrame = DEF_FRAME_COLOR, COLORREF crBgTitle = DEF_BG_COLOR, COLORREF crBgSelected = DEF_SELECT_COLOR, COLORREF crBgNoSelected = DEF_BG_COLOR); //设置字体大小及类型 void SetFontType(int fontSize, CString fontType,BOOL bArtFont = FALSE,COLORREF crArtFont = DEF_FRAME_COLOR); //设置右侧点击按钮的图标 void SetRightButton(UINT norImg,UINT clickImg); protected: afx_msg void OnPaint(); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); afx_msg void OnCbnSelchange(); afx_msg BOOL OnEraseBkgnd(CDC * pDC); afx_msg LRESULT OnMouseLeave(WPARAM wparam, LPARAM lparam); DECLARE_MESSAGE_MAP() DECLARE_DYNAMIC(CPngComboBox) private: void UpdateRect(void); void OnNcPaint(CDC* pDC); void DrawContent(UINT iState, CRect rcClient, CDC* pDC, int itemID); Image* ImageFromResource(HINSTANCE hInstance, UINT uImgID, LPCTSTR lpType); void DrawTextString(CDC * pDC, LPCTSTR pszString, COLORREF crText, COLORREF crFrame, LPRECT lpRect); void DrawTextString(CDC * pDC, LPCTSTR pszString, COLORREF crText, COLORREF crFrame, int nXPos, int nYPos); public: virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct); virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam); protected: BOOL m_bOver; CBrush* m_pBrsh; CPen m_bgPen; BOOL m_bDown; CFont m_font; int m_selItem; //select item flags BOOL m_bFous; //over fous int m_preSelItem; //pre select item flags UINT m_endIcon; COLORREF m_crFrame; COLORREF m_crBgTitle; COLORREF m_crBgSelected; COLORREF m_crBgNoSelected; vector<ItemList*> m_vecItemList; BOOL m_bArtFont; COLORREF m_crArtFont; Image* m_norImg; Image* m_clickImg; };
#include "stdafx.h" #include "PngComboBox.h" #include "resource.h" IMPLEMENT_DYNAMIC(CPngComboBox, CComboBox) BEGIN_MESSAGE_MAP(CPngComboBox, CComboBox) ON_WM_PAINT() ON_WM_MOUSEMOVE() ON_WM_ERASEBKGND() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) ON_CONTROL_REFLECT(CBN_SELCHANGE, OnCbnSelchange) END_MESSAGE_MAP() ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// CPngComboBox::CPngComboBox() { m_bOver = FALSE; m_bArtFont = FALSE; m_pBrsh = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); m_bgPen.CreatePen(PS_SOLID, 1, RGB(160, 31, 208)); m_font.CreateFont(15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, _T("宋体")); m_bDown = FALSE; m_selItem = 666666666; m_preSelItem = 666666666; m_bFous = FALSE; m_endIcon = NULL; m_crFrame = DEF_FRAME_COLOR; m_crBgTitle = DEF_BG_COLOR; m_crBgSelected = DEF_SELECT_COLOR; m_crBgNoSelected = DEF_BG_COLOR; m_crArtFont = DEF_FRAME_COLOR; m_norImg = NULL; m_clickImg = NULL; } CPngComboBox::~CPngComboBox() { if (m_bgPen.m_hObject != NULL) m_bgPen.DeleteObject(); if (m_pBrsh->m_hObject != NULL) m_pBrsh->DeleteObject(); if (m_font.m_hObject != NULL) m_font.DeleteObject(); for (auto* e : m_vecItemList) { if (e != NULL) { delete e; } } } void CPngComboBox::AddNewString(CString leftText, UINT icon, COLORREF leftColor) { ItemList* pItem = new ItemList; pItem->clrLeft = leftColor; pItem->hIcon = icon ? AfxGetApp()->LoadIcon(icon) : NULL; pItem->strUrl = leftText; pItem->iItem = AddString(leftText); m_vecItemList.push_back(pItem); } void CPngComboBox::SetEndIcon(UINT endIcon) { m_endIcon = endIcon; } void CPngComboBox::SetRightButton(UINT norImg, UINT clickImg) { m_norImg = ImageFromResource(AfxGetInstanceHandle(), norImg,_T("PNG")); m_clickImg = ImageFromResource(AfxGetInstanceHandle(), clickImg, _T("PNG")); if (!m_norImg || !m_clickImg) { m_norImg = m_clickImg = NULL; } } Image *CPngComboBox::ImageFromResource(HINSTANCE hInstance, UINT uImgID, LPCTSTR lpType) { HRSRC hResInfo = ::FindResource(hInstance, MAKEINTRESOURCE(uImgID), lpType); if (hResInfo == NULL) return NULL; //fail DWORD dwSize; dwSize = SizeofResource(hInstance, hResInfo); //get resource size(bytes) HGLOBAL hResData; hResData = ::LoadResource(hInstance, hResInfo); if (hResData == NULL) return NULL; //fail HGLOBAL hMem; hMem = ::GlobalAlloc(GMEM_MOVEABLE, dwSize); if (hMem == NULL) { ::FreeResource(hResData); return NULL; } LPVOID lpResData, lpMem; lpResData = ::LockResource(hResData); lpMem = ::GlobalLock(hMem); ::CopyMemory(lpMem, lpResData, dwSize); //copy memory ::GlobalUnlock(hMem); ::FreeResource(hResData); //free memory IStream *pStream; HRESULT hr; hr = ::CreateStreamOnHGlobal(hMem, TRUE, &pStream);//create stream object Image *pImage = NULL; if (SUCCEEDED(hr)) { pImage = Image::FromStream(pStream);//get GDI+ pointer pStream->Release(); } ::GlobalFree(hMem); return pImage; } void CPngComboBox::SetComboColor(COLORREF crFrame, COLORREF crBgTitle, COLORREF crBgSelected, COLORREF crBgNoSelected) { m_crFrame = crFrame; m_crBgTitle = crBgTitle; m_crBgSelected = crBgSelected; m_crBgNoSelected = crBgNoSelected; } void CPngComboBox::SetFontType(int fontSize, CString fontType,BOOL bArtFont, COLORREF crArtFont) { m_font.Detach(); LOGFONT lf; memset(&lf, 0, sizeof(LOGFONT)); lf.lfHeight = fontSize; _tcsncpy_s(lf.lfFaceName, LF_FACESIZE, fontType, fontType.GetLength()); VERIFY(m_font.CreateFontIndirect(&lf)); m_bArtFont = bArtFont; m_crArtFont = crArtFont; } void CPngComboBox::OnNcPaint(CDC* pDC) { //绘制客户区 CDC dMemDC; dMemDC.CreateCompatibleDC(pDC); dMemDC.SetMapMode(pDC->GetMapMode()); //画动作 CBitmap mNewBmp; CRect rc; GetClientRect(&rc); mNewBmp.CreateCompatibleBitmap(pDC, rc.right - rc.left, rc.bottom - rc.top); CBitmap* pOldBmp = dMemDC.SelectObject(&mNewBmp); CPen* pOldPen = dMemDC.SelectObject(&m_bgPen); CBrush bgBs(m_crBgNoSelected); CBrush* pOldBrsh = dMemDC.SelectObject(&bgBs); dMemDC.Rectangle(&rc); dMemDC.SelectObject(pOldPen); dMemDC.SelectObject(&pOldBrsh); if ((GetCurSel() > 4) || (GetCurSel() < 0)) { return; } PItemList pItem = m_vecItemList[GetCurSel()]; CPen m_penLeft; CPen m_penRight; CRect rcLeft, rcMid, rcRight; rcLeft = rcMid = rcRight = rc; dMemDC.SetBkMode(TRANSPARENT); //画第一段图标 if (pItem->hIcon != NULL) { rcLeft.left = 5; rcLeft.right = rcLeft.left + 16; rcLeft.top += 4; ::DrawIconEx(dMemDC.m_hDC, rcLeft.left, rcLeft.top, pItem->hIcon, 16, 16, NULL, NULL, DI_NORMAL); } else { rcLeft.right = 0; } //画第二段文本 rcMid.left = rcLeft.right + 5; CFont* pOldFont = dMemDC.SelectObject(&m_font); DrawTextString(&dMemDC, pItem->strUrl, pItem->clrLeft,m_crArtFont, &rcMid); dMemDC.SelectObject(pOldFont); CRect rcEnd(rc); rcEnd.left = rc.right - 22; if (m_norImg == NULL) { if (m_bDown) { dMemDC.DrawFrameControl(&rcEnd, DFC_SCROLL, DFCS_SCROLLDOWN | DFCS_FLAT | DFCS_MONO | DFCS_PUSHED); } else { dMemDC.DrawFrameControl(&rcEnd, DFC_SCROLL, DFCS_SCROLLDOWN | DFCS_FLAT | DFCS_MONO); } } else { Graphics graphics(dMemDC.m_hDC); if (m_bDown) { graphics.DrawImage(m_norImg, rcEnd.left, rcEnd.top+1, 22, 22); } else { graphics.DrawImage(m_clickImg, rcEnd.left, rcEnd.top+1, 22, 22); } graphics.ReleaseHDC(dMemDC.m_hDC); } pDC->BitBlt(rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, &dMemDC, rc.left, rc.top, SRCCOPY); //恢复 dMemDC.SelectObject(pOldBmp); pOldBmp->DeleteObject(); dMemDC.DeleteDC(); } void CPngComboBox::OnPaint() { CPaintDC dc(this); // device context for painting OnNcPaint(&dc); } void CPngComboBox::DrawContent(UINT iState, CRect rcClient, CDC* pDC, int itemID) { PItemList pItem = m_vecItemList[itemID]; CPen m_penLeft; CPen m_penRight; CRect rcLeft, rcMid; rcLeft = rcMid = rcClient; pDC->SetBkMode(TRANSPARENT); if (iState & ODS_SELECTED) { //及时更新选择区域 UpdateRect(); } if (itemID == m_selItem) { CPen bgPen; bgPen.CreatePen(PS_SOLID, 1, RGB(141, 178, 227)); CPen* pOldPen = pDC->SelectObject(&bgPen); CBrush bgBs(m_crBgSelected); CBrush* pOldBrush = pDC->SelectObject(&bgBs); pDC->RoundRect(&rcClient, CPoint(5, 5)); pDC->SelectObject(pOldBrush); pDC->SelectObject(pOldPen); bgPen.DeleteObject(); } else { CBrush bgBs(m_crBgNoSelected); pDC->FillRect(&rcClient,&bgBs); } //画第一段图标 if (pItem->hIcon != NULL) { rcLeft.left = 5; rcLeft.right = rcLeft.left + 16; rcLeft.top += 4; ::DrawIconEx(pDC->m_hDC, rcLeft.left, rcLeft.top, pItem->hIcon, 16, 16, NULL, NULL, DI_NORMAL); }else{ rcLeft.right = 0; } //画第二段文本 rcMid.left = rcLeft.right + 5; if(m_endIcon != NULL) rcMid.right -= 22; pDC->SetTextColor(pItem->clrLeft); CFont* pOldFont = pDC->SelectObject(&m_font); DrawTextString(pDC, pItem->strUrl, pItem->clrLeft, m_crArtFont, &rcMid); pDC->SelectObject(pOldFont); CRect rcEnd(rcClient); rcEnd.left = rcEnd.right - 18; rcEnd.top += 3; if (itemID == m_selItem && m_endIcon != NULL) DrawIconEx(pDC->m_hDC, rcEnd.left, rcEnd.top, AfxGetApp()->LoadIcon(m_endIcon), 16, 16, NULL, NULL, DI_NORMAL); } //鼠标移动消息 void CPngComboBox::OnMouseMove(UINT nFlags, CPoint point) { if (m_bOver == FALSE) { m_bOver = TRUE; //更新当前区域 UpdateRect(); TRACKMOUSEEVENT tme; tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE; tme.dwHoverTime = 0; tme.hwndTrack = m_hWnd; _TrackMouseEvent(&tme); } CComboBox::OnMouseMove(nFlags, point); } //鼠标离开消息 LRESULT CPngComboBox::OnMouseLeave(WPARAM wparam, LPARAM lparam) { if (m_bOver) { m_bOver = FALSE; } UpdateRect(); return 1; } void CPngComboBox::UpdateRect(void) { CRect rcClient; GetWindowRect(&rcClient); rcClient.DeflateRect(-2, -2); GetParent()->ScreenToClient(&rcClient); GetParent()->InvalidateRect(&rcClient, FALSE); return; } //绘画背景 BOOL CPngComboBox::OnEraseBkgnd(CDC * pDC) { return TRUE; } void CPngComboBox::OnLButtonDown(UINT nFlags, CPoint point) { m_bDown = TRUE; UpdateRect(); CComboBox::OnLButtonDown(nFlags, point); } void CPngComboBox::OnLButtonUp(UINT nFlags, CPoint point) { m_bDown = FALSE; UpdateRect(); CComboBox::OnLButtonUp(nFlags, point); } void CPngComboBox::OnCbnSelchange() { UpdateRect(); } void CPngComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { if (lpDrawItemStruct->CtlType != ODT_COMBOBOX) { return; } UINT itemID = lpDrawItemStruct->itemID; CRect rcClient = lpDrawItemStruct->rcItem; UINT iState = lpDrawItemStruct->itemState; CBitmap MemBit; CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC); DrawContent(iState, rcClient, pDC, itemID); } void CPngComboBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) { lpMeasureItemStruct->itemHeight = 30; lpMeasureItemStruct->itemWidth = 400; } LRESULT CPngComboBox::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) { if (WM_CTLCOLORLISTBOX == message) { HWND hListBox = (HWND)lParam; CListBox* pListBox = (CListBox*)FromHandle(hListBox); ASSERT(pListBox); int nCount = pListBox->GetCount(); if (CB_ERR != nCount) { CPoint pt; GetCursorPos(&pt); pListBox->ScreenToClient(&pt); CRect rc; for (int i = 0; i < nCount; i++) { pListBox->GetItemRect(i, &rc); if (rc.PtInRect(pt)) { m_preSelItem = m_selItem; m_selItem = i; if (m_selItem != m_preSelItem) { CRect preRc; CRect rcFous(rc); rcFous.left = rcFous.right - 18; pListBox->GetItemRect(m_preSelItem, &preRc); pListBox->InvalidateRect(&preRc); if (rcFous.PtInRect(pt)) { m_bFous = TRUE; pListBox->InvalidateRect(&rc); } else { m_bFous = FALSE; pListBox->InvalidateRect(&rc); } } break; } } } } return CComboBox::WindowProc(message, wParam, lParam); } //艺术字体 void CPngComboBox::DrawTextString(CDC * pDC, LPCTSTR pszString, COLORREF crText, COLORREF crFrame, LPRECT lpRect) { //变量定义 int nStringLength = lstrlen(pszString); int nXExcursion[8] = { 1,1,1,0,-1,-1,-1,0 }; int nYExcursion[8] = { -1,0,1,1,1,0,-1,-1 }; //绘画边框 pDC->SetTextColor(crFrame); CRect rcDraw; for (int i = 0; i < sizeof(nXExcursion) / sizeof(nXExcursion[0]); ++i) { rcDraw.CopyRect(lpRect); rcDraw.OffsetRect(nXExcursion[i], nYExcursion[i]); pDC->DrawText(pszString, nStringLength, &rcDraw, DT_VCENTER | DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS); } //绘画字体 rcDraw.CopyRect(lpRect); pDC->SetTextColor(crText); pDC->DrawText(pszString, nStringLength, &rcDraw, DT_VCENTER | DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS); return; } //艺术字体 void CPngComboBox::DrawTextString(CDC * pDC, LPCTSTR pszString, COLORREF crText, COLORREF crFrame, int nXPos, int nYPos) { //变量定义 int nStringLength = lstrlen(pszString); int nXExcursion[8] = { 1,1,1,0,-1,-1,-1,0 }; int nYExcursion[8] = { -1,0,1,1,1,0,-1,-1 }; //绘画边框 pDC->SetTextColor(crFrame); for (int i = 0; i < sizeof(nXExcursion) / sizeof(nXExcursion[0]); i++) { pDC->TextOut(nXPos + nXExcursion[i], nYPos + nYExcursion[i], pszString, nStringLength); } //绘画字体 pDC->SetTextColor(crText); pDC->TextOut(nXPos, nYPos, pszString, nStringLength); return; }
1、控件属性必须为Owner Drawer : Variable,Has Strings : False;Type:Drop List;Sort:False;四个条件缺一不可
2、
CPngComboBox m_combo; //-------------- DDX_Control(pDX, IDC_COMBO1, m_combo); //-------------------- m_combo.AddNewString(_T("葵花宝典"),IDI_ICON12 ); m_combo.AddNewString(_T("吸星大法"),IDI_ICON2); m_combo.AddNewString(_T("六脉神剑"),IDI_ICON3); m_combo.SetFontType(20,_T("宋体"),TRUE,RGB(0,150,255)); m_combo.SetRightButton(IDB_PNG5, IDB_PNG4); m_combo.SetCurSel(0);