目录
四、HeaderCtrlEx、CListEdit应用到List Ctrl中
一、效果图
二、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<LPNMCUSTOMDRAW>(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 <afxcmn.h>
typedef std::function<void()> 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<NMLVCUSTOMDRAW*>(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<LPNMITEMACTIVATE>(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
}