自绘 MFC 控件 CComboBox
第一步:在窗口中拖拽一个CComboBox控件,设置如下属性:
注意:
- 包含字符串,不设置为True,则使用GetLBText等函数无法获取到Item的text;
- 所有者描述,设置为No,不执行DrawItem、MeasureItem;
- 所有者描述,设置为Fixed,执行DrawItem,不执行MeasureItem;
- 所有者描述,设置为Variable,执行DrawItem、measureItem;
- DrawItem中绘制下拉列表;
- MeasureItem中设置下拉列表中向的高度。
第二步:选中CComboBox控件的下拉箭头,弹出下拉框,拖住拉大到至少能显示5个item的大小
注意:如果不拉大下拉框大于5个item的大小,则运行时下拉框不会显示出来。
第三步:选中CComboBox鼠标右键为其添加变量
第四步:定义CMyComboBox类,并使用CMyComboBox类名替换刚才生成的CComboBox类型的变量的类型
CMyComboBox.h
#pragma once
#include <afxwin.h>
#include <vector>class CMyComboBox : public CComboBox
{
public:CMyComboBox();void SetItem(std::vector<CString> text);void SetTextColor(COLORREF rgb);void SetFont(const std::string& name, int size, bool bold = false);void SetBkColor(COLORREF color);virtual void PreSubclassWindow() override;virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);virtual int CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct);protected:afx_msg void OnPaint();DECLARE_MESSAGE_MAP();private:CString m_text;COLORREF m_text_color;std::string m_font;int m_font_size;bool m_bold;COLORREF m_bk_color;
};
CMyComboBox.cpp
#include "pch.h"
#include "CMyComboBox.h"CMyComboBox::CMyComboBox(): m_text(_T("请选择")), m_text_color(RGB(0,0,0), m_font("Microsoft YaHei UI"), m_bold(false), m_font_size(14), m_bk_color(TRANSPARENT)
{}BEGIN_MESSAGE_MAP(CMyComboBox, CComboBox)ON_WM_PAINT()
END_MESSAGE_MAP()void CMyComboBox::SetItemText(std::vector<CString> text)
{InsertString(GetCount(), m_text);for (auto item : text) {InsertString(GetCount(), item);}SetCurSel(0);
}void CMyComboBox::SetTextColor(COLORREF rgb)
{m_text_color = rgb;
}void CMyComboBox::SetFontName(const std::string& font, bool bold/* = false*/)
{m_font_name = font;m_bold = bold;
}void CMyComboBox::SetFontSize(int size)
{m_font_size = size;
}void CMyComboBox::SetBkColor(COLORREF color)
{m_bk_color= color;SendMessage(CB_SETITEMHEIGHT, -1, 37);
}void CMyComboBox::PreSubclassWindow()
{ModifyStyle(0, BS_OWNERDRAW); CComboBox::PreSubclassWindow();
}void CMyComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{CString text;if (-1 != lpDrawItemStruct->itemID) {GetLBText(lpDrawItemStruct->itemID, text);}else {return;}TEXTMETRIC text_metric;CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);if (pDC) {CFont font;font.CreateFontW(m_font_size - 5, 0, 0, 0, (m_bold ? FW_BOLD : FW_NORMAL), FALSE, FALSE, FALSE, ANSI_CHARSET,OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS,to_wstring(m_font_name).c_str());pDC->SelectObject(&font);pDC->GetTextMetrics(&text_metric);CRect rc;GetClientRect(&rc);if ((lpDrawItemStruct->itemState & ODS_SELECTED) &&(lpDrawItemStruct->itemAction & (ODA_DRAWENTIRE | ODA_SELECT))) {pDC->FillSolidRect(&lpDrawItemStruct->rcItem, m_bk_color);pDC->SetBkColor(m_bk_color);pDC->SetTextColor(m_text_color);pDC->TextOutW(lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.top, text);}else if (lpDrawItemStruct->itemAction & (ODA_SELECT | ODA_DRAWENTIRE)) {pDC->FillSolidRect(&lpDrawItemStruct->rcItem, m_bk_color);pDC->SetBkColor(m_bk_color);pDC->SetTextColor(m_text_color);pDC->TextOutW(lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.top, text);}ReleaseDC(pDC);font.DeleteObject();}
}void CMyComboBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{CRect rc;GetClientRect(&rc);lpMeasureItemStruct->itemHeight = 20;
}int CMyComboBox::CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct)
{return 1;
}void CMyComboBox::OnPaint()
{CRect rect;GetClientRect(&rect);CPaintDC pDC(this);pDC.SetBkMode(TRANSPARENT);pDC.SelectStockObject(NULL_BRUSH);CPen pen;pen.CreatePen(PS_SOLID, 1, m_bk_color);pDC.SelectObject(&pen);CFont font;font.CreateFontW(m_font_size - 5, 0, 0, 0, (m_bold ? FW_BOLD : FW_NORMAL), FALSE, FALSE, FALSE, ANSI_CHARSET,OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS,to_wstring(m_font_name).c_str());pDC.SelectObject(&font);CBrush brush;CBrush brush_flag;CBrush brush_angle;CRgn rgn;if (m_back_color != TRANSPARENT) {brush.CreateSolidBrush(m_bk_color);pDC.SelectObject(&brush);pDC.Rectangle(&rect);CRect rc(rect);rc.left = rect.right - 20;brush_flag.CreateSolidBrush(m_bk_color);pDC.SelectObject(&brush_flag);pDC.Rectangle(rc);int angleSideWidth = 10;CPoint ptAngle[3];ptAngle[0].x = rc.left + rc.Width() / 2 - angleSideWidth / 2;ptAngle[0].y = rc.top + rc.Height() / 2 - 2;ptAngle[1].x = ptAngle[0].x + angleSideWidth;ptAngle[1].y = ptAngle[0].y;ptAngle[2].x = rc.left + rc.Width() / 2;ptAngle[2].y = ptAngle[0].y + 5;rgn.CreatePolygonRgn(ptAngle, 3, ALTERNATE);brush_angle.CreateSolidBrush(RGB(123,123,123));pDC.FillRgn(&rgn, &brush_angle);}CString text;GetWindowTextW(text);if (0 == text.GetLength()) {text = m_text;}int len = text.GetLength();if (0 < len) {TEXTMETRIC text_metric;pDC.GetTextMetrics(&text_metric);int offset_move = ((text_metric.tmPitchAndFamily & 0x0F) * (len - 1) + text_metric.tmAveCharWidth * len);if (0 < offset_move) {pDC.MoveTo((len <= 6 ? offset_move + text_metric.tmAveCharWidth : offset_move), 0);}rect.top += (rect.Height() - text_metric.tmHeight) / 2;pDC.SetTextColor(m_text_color);pDC.DrawText(text.GetBuffer(), &rect, DT_CENTER | DT_SINGLELINE);}pen.DeleteObject();font.DeleteObject();if (m_back_color != TRANSPARENT) {brush.DeleteObject();brush_flag.DeleteObject();brush_angle.DeleteObject();rgn.DeleteObject();}ReleaseDC(&pDC);CComboBox::OnPaint();
}