MFC list ctrl 修改表头和表格字体、双击编辑一步搞定(源码)

目录

一、效果图

 二、HeaderCtrlEx 实现修改表头字体、背景颜色

三、CListEdit 实现双击编辑

四、HeaderCtrlEx、CListEdit应用到List Ctrl中

五、实战



一、效果图

MFC list ctrl 修改表头和表格字体、双击编辑一步搞定(源码)_第1张图片

 二、HeaderCtrlEx 实现修改表头字体、背景颜色

HeaderCtrlEx.h

class HeaderCtrlEx : public CHeaderCtrl  
{
  friend class CListCtrlEx;
	DECLARE_DYNAMIC(HeaderCtrlEx)

public:
           HeaderCtrlEx();
  virtual ~HeaderCtrlEx();

private:
  COLORREF m_clrBK; //表头背景颜色
  COLORREF m_clrFont; //表头字体颜色
  CFont* m_pFont; //表头字体样式

protected:
	DECLARE_MESSAGE_MAP()
	void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult);
	LRESULT OnLayout(WPARAM wParam, LPARAM lParam);

private:
  void SetHeaderCtrlFont(CFont* pFont);
};

HeaderCtrlEx.cpp

#include "stdafx.h"
#include "HeaderCtrlEx.h"

IMPLEMENT_DYNAMIC(HeaderCtrlEx, CHeaderCtrl)

static BOOL s_bDeleteFont = TRUE;

BEGIN_MESSAGE_MAP(HeaderCtrlEx, CHeaderCtrl)
    ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &HeaderCtrlEx::OnNMCustomdraw)
    ON_MESSAGE(HDM_LAYOUT, &HeaderCtrlEx::OnLayout)
END_MESSAGE_MAP()

HeaderCtrlEx::HeaderCtrlEx()
{
	m_pFont = new CFont;

	m_pFont->CreateFont(12, //以逻辑单位方式指定字体的高度
		0, //以逻辑单位方式指定字体中字符的平均宽度
		0, //指定偏离垂线和X轴在显示面上的夹角(单位:0.1度)
		0, //指定字符串基线和X轴之间的夹角(单位:0.1度)
		FW_NORMAL, //指定字体磅数
    FALSE, //是不是斜体
		FALSE, //加不加下划线
		0, //指定是否是字体字符突出
		ANSI_CHARSET, //指定字体的字符集
		OUT_DEFAULT_PRECIS, //指定所需的输出精度
		CLIP_DEFAULT_PRECIS, //指定所需的剪贴精度
		DEFAULT_QUALITY, //指示字体的输出质量
		DEFAULT_PITCH | FF_SWISS, //指定字体的间距和家族
		_T("宋体") //指定字体的字样名称
	);

  m_clrBK = RGB(255, 255, 255); 
  m_clrFont = RGB(0, 0, 0);
}

HeaderCtrlEx::~HeaderCtrlEx()
{
  if (m_pFont && s_bDeleteFont)
  {
    m_pFont->DeleteObject();
    delete m_pFont;
    m_pFont = NULL;
  }
}

void HeaderCtrlEx::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult)
{
    LPNMCUSTOMDRAW pNMCD = reinterpret_cast(pNMHDR);
    // TODO: Add your control notification handler code here
    *pResult = CDRF_DODEFAULT;

    if (pNMCD->dwDrawStage == CDDS_PREPAINT)
    {
        CDC* pDC = CDC::FromHandle(pNMCD->hdc);
        CRect rect(0, 0, 0, 0);
        GetClientRect(&rect);
        pDC->FillSolidRect(&rect, m_clrBK);

        *pResult = CDRF_NOTIFYITEMDRAW;
    }
    else if (pNMCD->dwDrawStage == CDDS_ITEMPREPAINT)
    {
        HDITEM hditem;
        TCHAR buffer[MAX_PATH] = { 0 };
        SecureZeroMemory(&hditem, sizeof(HDITEM));
        hditem.mask = HDI_TEXT;
        hditem.pszText = buffer;
        hditem.cchTextMax = MAX_PATH;
        GetItem(pNMCD->dwItemSpec, &hditem);

        CDC* pDC = CDC::FromHandle(pNMCD->hdc);
        pDC->SetTextColor(m_clrFont);
				pDC->SetBkColor(RGB(255, 255, 255));
        pDC->SetBkMode(TRANSPARENT);
        CFont* pOldFont = pDC->SelectObject(m_pFont);
        CString str(buffer);
        CRect rect = pNMCD->rc;

        CPen pen;
				pen.CreatePen(PS_SOLID, 1, RGB(240, 240, 240));
				CPen* pOldPen = pDC->SelectObject(&pen);
        pDC->Rectangle(&rect);
        pDC->SelectObject(pOldPen);
        pen.DeleteObject();

        //rect.OffsetRect(6, 0);
        pDC->DrawText(str, CRect(rect), DT_SINGLELINE | DT_CENTER | DT_VCENTER);
        pDC->SelectObject(pOldFont);
        pDC->Detach();
        *pResult = CDRF_SKIPDEFAULT;
    }
}


LRESULT HeaderCtrlEx::OnLayout(WPARAM wParam, LPARAM lParam)
{
    LRESULT lResult = CHeaderCtrl::DefWindowProc(HDM_LAYOUT, 0, lParam);
    HD_LAYOUT& hdl = *(HD_LAYOUT*)lParam;

    RECT* prc = hdl.prc;            // The table list rectangle
    WINDOWPOS* pwpos = hdl.pwpos;   // The table header rectangle

    int nHeight = (int)(pwpos->cy * 1.3);
    
    pwpos->cy = nHeight;            // New table header height
    //pwpos->x += 3;

    prc->top = nHeight;             // Decreases the table list height on the table header height

    return lResult;
}

void HeaderCtrlEx::SetHeaderCtrlFont(CFont* pFont)
{
  if (m_pFont && s_bDeleteFont)
	{
    m_pFont->DeleteObject();
    delete m_pFont;
    m_pFont = NULL;
  }
  m_pFont = pFont;

	s_bDeleteFont = FALSE;
}



三、CListEdit 实现双击编辑

CListEdit.h

#pragma once
#include 

typedef std::function CallBackFunc;

class CListEdit : public CEdit
{
	friend class CListCtrlEx;

	DECLARE_DYNAMIC(CListEdit)

public:
	CListEdit();
	virtual ~CListEdit();

	void SetCallBackFunc(const CallBackFunc& func) { m_updataListfunc = func; }

protected:
	DECLARE_MESSAGE_MAP()
	afx_msg void OnKillFocus(CWnd* pNewWnd);
	virtual BOOL PreTranslateMessage(MSG* pMsg);
private:
	CFont* m_pFont; //if NULL, same as list
	CallBackFunc m_updataListfunc;

	void SetListEditCtrlFont(CFont* pFont);
};

CListEdit.cpp

#include "stdafx.h"
#include "CListEdit.h"

//static BOOL s_bDeleteFont = TRUE;
static BOOL s_bUpdataList = TRUE;

IMPLEMENT_DYNAMIC(CListEdit, CEdit)

BEGIN_MESSAGE_MAP(CListEdit, CEdit)
	ON_WM_KILLFOCUS()
END_MESSAGE_MAP()

CListEdit::CListEdit()
{
	m_pFont = NULL;
}

CListEdit::~CListEdit()
{
}

void CListEdit::OnKillFocus(CWnd* pNewWnd)
{
	this->ShowWindow(SW_HIDE);
	if(s_bUpdataList) m_updataListfunc();
	s_bUpdataList = TRUE;
}

BOOL CListEdit::PreTranslateMessage(MSG* pMsg)
{
	if (pMsg->message == WM_KEYDOWN && (pMsg->wParam == VK_ESCAPE || pMsg->wParam == VK_RETURN))
	{
		if (pMsg->wParam == VK_ESCAPE)
		{
			s_bUpdataList = FALSE;
			this->ShowWindow(SW_HIDE);
		}
		else if (pMsg->wParam == VK_RETURN)
		{
			this->ShowWindow(SW_HIDE);
			m_updataListfunc();
		}
		return TRUE;
	}
	return CEdit::PreTranslateMessage(pMsg);
}


void CListEdit::SetListEditCtrlFont(CFont* pFont)
{
	m_pFont = pFont;
}

四、HeaderCtrlEx、CListEdit应用到List Ctrl中

CListCtrlEx.h

#pragma once

class HeaderCtrlEx;
class CListEdit;
class CListCtrlEx : public CListCtrl  
{
	DECLARE_DYNAMIC(CListCtrlEx)

public:
           CListCtrlEx();
  virtual ~CListCtrlEx();

public:
	//设置 list ctrl 选中时的颜色
  void SetSelectedColor(COLORREF clrSelected);

	//设置双击编辑框字体
  void SetListEditFont(CFont* pFont);

	//设置表头字体
  void SetHeaderFont(CFont* pFont);

	//设置表头背景颜色
  void SetHeaderBKColor(COLORREF clrBK);

	//设置表头字体颜色
  void SetHeaderFontColor(COLORREF clrFont);

	//设置是否可双击编辑
	void SetListEdit(BOOL bListEdit = TRUE); 

protected:
	DECLARE_MESSAGE_MAP()
	afx_msg void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult);
	afx_msg BOOL OnNMDBClick(NMHDR* pNMHDR, LRESULT* pResult);
	virtual void PreSubclassWindow();

private:
	HeaderCtrlEx* m_pHeaderCtrl;
	CListEdit* m_pListEditCtrl;
	int m_nRow;
	int m_nCol;
	BOOL m_bListEdit;

private:
	void RegisterHeaderCtrl();
	void UpdataListCallBackFunc();
};

CListCtrlEx.cpp

#include "stdafx.h"
#include "CListCtrlEx.h"
#include "HeaderCtrlEx.h"
#include "CListEdit.h"

IMPLEMENT_DYNAMIC(CListCtrlEx, CListCtrl)

static COLORREF s_clrSelected = RGB(0, 120, 215); //如果用成员变量, OnNMCustomdraw会把成员变量的颜色变成0

BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CListCtrlEx::OnNMCustomdraw)
	ON_NOTIFY_REFLECT_EX(NM_DBLCLK, &CListCtrlEx::OnNMDBClick)
/*
注意:
ON_NOTIFY_REFLECT 控制自己处理消息
ON_NOTIFY_REFLECT_EX 如果控件消息响应函数 OnNMDBClick 返回 FALSE,消息由父窗口继续处理

*/
END_MESSAGE_MAP()

//CustomDraw to change selected item color
void CListCtrlEx::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult)
{
	NMLVCUSTOMDRAW* pLVCD = reinterpret_cast(pNMHDR);
	
	*pResult = CDRF_DODEFAULT;
	
	switch (pLVCD->nmcd.dwDrawStage)
	{
		case CDDS_PREPAINT:
			*pResult = CDRF_NOTIFYITEMDRAW;
			break;
		case CDDS_ITEMPREPAINT:
			*pResult = CDRF_NOTIFYSUBITEMDRAW;
			break;
		case CDDS_SUBITEM | CDDS_ITEMPREPAINT:
		{
			if ((GetItemState(pLVCD->nmcd.dwItemSpec, LVIS_SELECTED) & LVIS_SELECTED))
			{
				pLVCD->nmcd.uItemState = CDIS_DEFAULT;

				pLVCD->clrTextBk = s_clrSelected;
				pLVCD->clrText = GetSysColor(COLOR_HIGHLIGHTTEXT);
				*pResult = CDRF_NEWFONT;
			}
			break;
		}

		default:
			break;
	}
}

BOOL CListCtrlEx::OnNMDBClick(NMHDR* pNMHDR, LRESULT* pResult)
{
	if (!m_bListEdit) return FALSE;
	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast(pNMHDR);
	// TODO: 在此添加控件通知处理程序代码
	NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
	CRect rect;

	m_nRow = pNMListView->iItem;//获得选中的行
	m_nCol = pNMListView->iSubItem;//获得选中列
	if (m_nRow != -1 && m_nCol != -1 && m_pListEditCtrl)
	{
		if (pNMListView->iSubItem != 0) 
		{
		
			this->GetSubItemRect(m_nRow, m_nCol, LVIR_LABEL, rect);
			BOOL bCreat = TRUE;
			if (!IsWindow(m_pListEditCtrl->m_hWnd))
			{
				bCreat = m_pListEditCtrl->Create(WS_BORDER | WS_CHILD | WS_VISIBLE, rect, this, 1);
			}
			if (bCreat)
			{
				m_pListEditCtrl->SetParent(this);
				m_pListEditCtrl->MoveWindow(&rect);
				CFont* pFont = NULL;
				if (!m_pListEditCtrl->m_pFont)
				{
					pFont = this->GetFont(); //if not set, same as list
				}
				else
				{
					pFont = m_pListEditCtrl->m_pFont;
				}
				if(pFont) m_pListEditCtrl->SetFont(pFont);
				m_pListEditCtrl->SetWindowText(this->GetItemText(m_nRow, m_nCol));
				m_pListEditCtrl->ShowWindow(SW_SHOW);//显示Edit控件;
				m_pListEditCtrl->SetFocus();//设置Edit焦点
				m_pListEditCtrl->ShowCaret();//显示光标
				m_pListEditCtrl->SetSel(0, -1);//将光标移动到最后
			}
		}
	}
	*pResult = 0;
	return TRUE;
}

void CListCtrlEx::PreSubclassWindow()
{
	CHeaderCtrl* pHeader = GetHeaderCtrl();
	if (pHeader && m_pHeaderCtrl) { VERIFY(m_pHeaderCtrl->SubclassWindow(pHeader->m_hWnd)); }

	CListCtrl::PreSubclassWindow();
}

CListCtrlEx::CListCtrlEx()
{
	m_pHeaderCtrl = new HeaderCtrlEx;
	m_pListEditCtrl = new CListEdit;
	CallBackFunc func = std::bind(&CListCtrlEx::UpdataListCallBackFunc, this);
	m_pListEditCtrl->SetCallBackFunc(func);
	m_bListEdit = FALSE;
}

CListCtrlEx::~CListCtrlEx()
{
	if (m_pHeaderCtrl)
	{
		delete m_pHeaderCtrl;
		m_pHeaderCtrl = NULL;
	}

	if (m_pListEditCtrl)
	{
		delete m_pListEditCtrl;
		m_pListEditCtrl = NULL;
	}
}

void CListCtrlEx::SetSelectedColor(COLORREF clrSelected)
{
	s_clrSelected = clrSelected;
}

void CListCtrlEx::SetListEditFont(CFont* pFont)
{
	if (m_pListEditCtrl) m_pListEditCtrl->SetListEditCtrlFont(pFont);
}

void CListCtrlEx::SetHeaderFont(CFont* pFont)
{
	if (m_pHeaderCtrl) m_pHeaderCtrl->SetHeaderCtrlFont(pFont);
}

void CListCtrlEx::SetHeaderBKColor(COLORREF clrBK)
{
	if (m_pHeaderCtrl) m_pHeaderCtrl->m_clrBK = clrBK;
}

void CListCtrlEx::SetHeaderFontColor(COLORREF clrFont)
{
	if (m_pHeaderCtrl) m_pHeaderCtrl->m_clrFont = clrFont;
}

void CListCtrlEx::SetListEdit(BOOL bListEdit)
{
	m_bListEdit = bListEdit;
}

void CListCtrlEx::UpdataListCallBackFunc()
{
	CString str;
	if (m_pListEditCtrl)
	{
		m_pListEditCtrl->GetWindowText(str);
	}
	if (m_pListEditCtrl)
	{
		this->SetItemText(m_nRow, m_nCol, str);
	}
}

void CListCtrlEx::RegisterHeaderCtrl()
{
	CHeaderCtrl* pHeader = GetHeaderCtrl();
	if (pHeader && m_pHeaderCtrl) { VERIFY(m_pHeaderCtrl->SubclassWindow(pHeader->m_hWnd)); }
}

五、实战

/***********************.h***********************/
class CMyDialog: public CDialog
{
	DECLARE_DYNAMIC(CMyDialog)

public:
	CMyDialog(CWnd* pParent = nullptr);   // 标准构造函数
	virtual ~CMyDialog();

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_DIALOG_SAFETYAPPOPTION_CHAPTER2LIST };
#endif

protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

	DECLARE_MESSAGE_MAP()

public:
	virtual BOOL OnInitDialog();
}

/***********************.cpp***********************/
void CMyDialog::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST, m_list);
}

BOOL CMyDialog::OnInitDialog()
{
	CDialog::OnInitDialog();

	LONG lStyle;
	lStyle = GetWindowLong(m_list.m_hWnd, GWL_STYLE);//获取当前窗口style
	lStyle &= ~LVS_TYPEMASK; //清除显示方式位
	lStyle |= LVS_REPORT; //设置style
	lStyle |= LVS_SHOWSELALWAYS; //设置style
	//lStyle |= LVS_NOCOLUMNHEADER;
	//lStyle |= LVS_SINGLESEL; //设置style
	SetWindowLong(m_list.m_hWnd, GWL_STYLE, lStyle);//设置style
	DWORD dwStyle = m_list.GetExtendedStyle();
	dwStyle |= LVS_EX_FULLROWSELECT;//选中某行使整行高亮(只适用与report风格的listctrl)
	dwStyle |= LVS_EX_GRIDLINES;//网格线(只适用与report风格的listctrl)
	dwStyle |= LVS_EX_CHECKBOXES;
	dwStyle |= LVS_EX_HEADERDRAGDROP;
	dwStyle |= LVS_EX_HEADERINALLVIEWS;
	m_list.SetExtendedStyle(dwStyle); //设置扩展风格

	m_pFont->CreateFont(12, //以逻辑单位方式指定字体的高度
		0, //以逻辑单位方式指定字体中字符的平均宽度
		0, //指定偏离垂线和X轴在显示面上的夹角(单位:0.1度)
		0, //指定字符串基线和X轴之间的夹角(单位:0.1度)
		FW_BOLD, //指定字体磅数
		FALSE, //是不是斜体
		FALSE, //加不加下划线
		0, //指定是否是字体字符突出
		ANSI_CHARSET, //指定字体的字符集
		OUT_DEFAULT_PRECIS, //指定所需的输出精度
		CLIP_DEFAULT_PRECIS, //指定所需的剪贴精度
		DEFAULT_QUALITY, //指示字体的输出质量
		DEFAULT_PITCH | FF_SWISS, //指定字体的间距和家族
		_T("宋体") //指定字体的字样名称
	);
	m_list.SetHeaderFont(m_pFont);
	m_list.SetListEdit();
    m_list.InsertColumn(0, TEXT("col1"), LVCFMT_CENTER, 60);
	m_list.InsertColumn(1, TEXT("col2"), LVCFMT_CENTER, rect.Width() - 60);
    m_list.SetItemText(0, 0, TEXT("row1 col1"));
	m_list.SetItemText(0, 1, TEXT("row1 col2"));


	return TRUE;  // return TRUE unless you set the focus to a control
								// 异常: OCX 属性页应返回 FALSE
}

你可能感兴趣的:(mfc,list,c++)