自绘 MFC 控件 CComboBox

第一步:在窗口中拖拽一个CComboBox控件,设置如下属性:

  •  类型,设置为:下拉列表
  • 包含字符串,设置为:True
  • 所有者描述,设置为:Variable

  注意:

  1. 包含字符串,不设置为True,则使用GetLBText等函数无法获取到Item的text;
  2. 所有者描述,设置为No,不执行DrawItem、MeasureItem;
  3. 所有者描述,设置为Fixed,执行DrawItem,不执行MeasureItem;
  4. 所有者描述,设置为Variable,执行DrawItem、measureItem;
  5. DrawItem中绘制下拉列表;
  6. MeasureItem中设置下拉列表中向的高度。

第二步:选中CComboBox控件的下拉箭头,弹出下拉框,拖住拉大到至少能显示5个item的大小

        注意:如果不拉大下拉框大于5个item的大小,则运行时下拉框不会显示出来。

第三步:选中CComboBox鼠标右键为其添加变量

第四步:定义CMyComboBox类,并使用CMyComboBox类名替换刚才生成的CComboBox类型的变量的类型

CMyComboBox.h 

#pragma once
#include 
#include 

class CMyComboBox : public CComboBox
{
public:
    CMyComboBox();
    
    void SetItem(std::vector 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 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();
}

你可能感兴趣的:(mfc,c++,开发语言,CComboBox)