MFC的自定义控件之控件封装
2018-02-26 本文已影响99人
JasonChen8888
MFC实现CListBox的继承实现自定义效果
目标 - 实现有背景颜色项的列表
思路
- 需要知道CListBox的每个item的绘制方法
- 需要知道CListBox的item的测量方法
查看源码找到关键的量重写的方法:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
开始实现
- 自定义控件的操作步骤
参考https://www.jianshu.com/p/e2fe069cfe35这边MFC的定义控件步骤
再创建控件类的时候,父类要选择CListBox
有个不一样的是在界面上的控件,可以是CListBox,也可以是Custom Control,只需要在控件属性的class
写成我们自定义的类名。
代码
控件的头文件
class CColorListBox : public CListBox
{
DECLARE_DYNAMIC(CColorListBox)
public:
CColorListBox();
virtual ~CColorListBox();
BOOL InitControl(CWnd* pWnd); //用来做初始化控件的方法
public:
virtual BOOL PreCreateWindow(CREATESTRUCT &cs);
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct); //一定要复写的方法
virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct); //一定要复写的方法
BOOL RegisterWindowClass(HINSTANCE hInstance = NULL);
protected:
DECLARE_MESSAGE_MAP()
};
控件的源文件
// ColorListBox.cpp : 实现文件
#include "stdafx.h"
#include "ColorListBox.h"
#include "CustomUIApp.h"
// CColorListBox
IMPLEMENT_DYNAMIC(CColorListBox, CListBox)
CColorListBox::CColorListBox()
{
RegisterWindowClass(); //控件注册类
}
CColorListBox::~CColorListBox()
{
}
BEGIN_MESSAGE_MAP(CColorListBox, CListBox)
END_MESSAGE_MAP()
BOOL CColorListBox::RegisterWindowClass(HINSTANCE hInstance)
{
LPCWSTR className = L"CColorListBox"; // 控件类名,必须和属性的class一致
WNDCLASS windowclass;
if (hInstance)
hInstance = AfxGetInstanceHandle();
if (!(::GetClassInfo(hInstance, className, &windowclass)))
{
windowclass.style = CS_DBLCLKS;
windowclass.lpfnWndProc = ::DefWindowProc;
windowclass.cbClsExtra = windowclass.cbWndExtra = 0;
windowclass.hInstance = hInstance;
windowclass.hIcon = NULL;
windowclass.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
windowclass.hbrBackground = ::GetSysColorBrush(COLOR_WINDOW);
windowclass.lpszMenuName = NULL;
windowclass.lpszClassName = className;
}
return AfxRegisterClass(&windowclass);
}
//初始化控件,设置对应的控件属性, 列表控件才能显示数据,该方法必须调用,才可以正常显示数据
BOOL CColorListBox::InitControl(CWnd* pWnd)
{
if (pWnd == NULL) return false;
CRect rect;
GetWindowRect(&rect);
pWnd->ScreenToClient(&rect);
UINT id = GetDlgCtrlID();
BOOL ret = DestroyWindow();
if (ret == FALSE) return false;
//设置控件的属性
ret = Create(WS_CHILD | WS_VISIBLE | WS_TABSTOP | LBS_OWNERDRAWVARIABLE | LBS_HASSTRINGS | LBS_NOTIFY, rect, pWnd, id);
return ret;
}
BOOL CColorListBox::PreCreateWindow(CREATESTRUCT &cs)
{
if (!CListBox::PreCreateWindow(cs))
return FALSE;
cs.style &= ~(LBS_SORT | LBS_OWNERDRAWVARIABLE);
cs.style |= LBS_OWNERDRAWFIXED;
return TRUE;
}
void CColorListBox::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
ASSERT(lpDIS->CtlType == ODT_LISTBOX);
LPCTSTR lpszText = (LPCTSTR)lpDIS->itemData;
CDC dc;
dc.Attach(lpDIS->hDC);
COLORREF crOldTextColor = dc.GetTextColor();
COLORREF crOldBkColor = dc.GetBkColor();
// If this item is selected, set the background color
// and the text color to appropriate values. Also, erase
// rect by filling it with the background color.
if ((lpDIS->itemAction | ODA_SELECT) &&
(lpDIS->itemState & ODS_SELECTED))
{
dc.SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
dc.SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
dc.FillSolidRect(&lpDIS->rcItem,
::GetSysColor(COLOR_HIGHLIGHT));
}
else
{
if (lpDIS->itemID % 2)
dc.FillSolidRect(&lpDIS->rcItem, RGB(128, 128, 128));
else
dc.FillSolidRect(&lpDIS->rcItem, RGB(255, 128, 255));
}
// If this item has the focus, draw a red frame around the
// item's rect.
if ((lpDIS->itemAction | ODA_FOCUS) &&
(lpDIS->itemState & ODS_FOCUS))
{
CBrush br(RGB(0, 0, 128));
dc.FrameRect(&lpDIS->rcItem, &br);
}
lpDIS->rcItem.left += 5;
// Draw the text.
CString sText;
GetText(lpDIS->itemID, sText);
CRect rect = lpDIS->rcItem;
// Setup the text format.
UINT nFormat = DT_LEFT | DT_SINGLELINE | DT_VCENTER;
if (GetStyle() & LBS_USETABSTOPS)
nFormat |= DT_EXPANDTABS;
dc.DrawText(
sText, -1, &rect, nFormat | DT_CALCRECT); //这边是计算
dc.DrawText(
sText, -1, &rect, nFormat); //这边是绘制文字
//设置字体颜色和背景颜色
dc.SetTextColor(crOldTextColor);
dc.SetBkColor(crOldBkColor);
dc.Detach();
}
void CColorListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMIS)
{
lpMIS->itemHeight = ::GetSystemMetrics(SM_CYMENUCHECK);
}
在对话框的调用:
BOOL CSecondDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
BOOL ret = m_colorlb.InitControl(this);
// TODO: 在此添加额外的初始化
return TRUE; // return TRUE unless you set the focus to a control
// 异常: OCX 属性页应返回 FALSE
}
void CSecondDlg::OnBnClickedAddData()
{
m_colorlb.AddString(L"11111111");
m_colorlb.AddString(L"22222222");
}