后附源码!
运行效果:
第一步:在窗口中拖拽一个CComboBox控件,设置如下属性:
- 类型,设置为:下拉列表
- 包含字符串,设置为:True
- 所有者描述,设置为:Variable
注意:
- 包含字符串,不设置为True,则使用GetLBText等函数无法获取到Item的text;
- 所有者描述,设置为No,不执行DrawItem、MeasureItem;
- 所有者描述,设置为Fixed,执行DrawItem,不执行MeasureItem;
- 所有者描述,设置为Variable,执行DrawItem、measureItem;
- DrawItem中绘制下拉列表;
- MeasureItem中设置下拉列表中向的高度。
第二步:选中CComboBox控件的下拉箭头,弹出下拉框,拖住拉大到至少能显示5个item的大小
注意:如果不拉大下拉框大于5个item的大小,则运行时下拉框不会显示出来。
第三步:选中CComboBox鼠标右键为其添加变量
第四步:定义CMyComboBox类,并使用CMyComboBox类名替换刚才生成的CComboBox类型的变量的类型
第五步:CComboBox 控件无法通过拖拽增加其Height,可以通过如下消息进行设置:
SendMessage(CB_SETITEMHEIGHT, -1, 37); // 37即为想要设置的Height
附代码:
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)
{
if (ODT_COMBOBOX != lpDrawItemStruct->CtlType) {
return CComboBox::DrawItem(lpDrawItemStruct);
}
CString text;
if (-1 != lpDrawItemStruct->itemID) {
GetLBText(lpDrawItemStruct->itemID, text);
}
else {
return CComboBox::DrawItem(lpDrawItemStruct);
}
CDC dc;
dc.Attach(lpDrawItemStruct->hDC);
// Save these value to restore them when done drawing.
COLORREF crOldTextColor = dc.GetTextColor();
COLORREF crOldBkColor = dc.GetBkColor();
CFont font;
font.CreateFont(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());
dc.SelectObject(&font);
dc.SetTextColor(m_text_color);
dc.SetBkColor(m_back_color);
dc.FillSolidRect(&lpDrawItemStruct->rcItem, m_back_color);
// Draw the text.
dc.DrawText(
text,
(int)_tcslen(text),
&lpDrawItemStruct->rcItem,
DT_SINGLELINE);
// Reset the background color and the text color back to their
// original values.
dc.SetTextColor(crOldTextColor);
dc.SetBkColor(crOldBkColor);
dc.Detach();
}
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();
}