1.前言
最近发现读者对我的mfc美化的专栏比较感兴趣,因此在这里进行续写,这里我会计划写几个连续的篇章,包括对MFC按钮的美化,菜单栏的美化,标题栏的美化,list列表的美化,直到最后形成一个完整的成品效果。
2.最终效果展示
3.思路分析
1.编写mfc的list的派生类对 列表进行重绘
2.list和其他的空间有些区别,要分别对标题栏,和内容栏进行重绘。
4.实现的过程
1.在mfc界面,增加空间list
2.修改list的属性
边框:false
静态边缘:false
视图:Reporte
无滚动:true
3.声明list的变量
cpp
public:
CListCtrlComboEx m_list;
4.OnInitDialog 里面的核心代码
cpp
BOOL CCustomListDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 将"关于..."菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
//LIST
CRect rect;
m_list.GetClientRect(&rect);
DWORD dwStyle = m_list.GetExtendedStyle();
//dwStyle = (dwStyle | LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER);
dwStyle |= dwStyle | LVS_REPORT & ~LVS_EX_GRIDLINES | LVS_EX_FULLROWSELECT | LVS_SHOWSELALWAYS | LVS_EX_HEADERDRAGDROP;
m_list.SetExtendedStyle(dwStyle);
//m_list.SetBo
m_list.SetItemHeight(25);
m_list.SetFontSize(17);
m_list.InsertColumn(0, _T("编号"), LVCFMT_CENTER, (rect.Width() / 3) + 30, 0);
m_list.InsertColumn(1, _T("菜谱"), LVCFMT_CENTER, (rect.Width() - (rect.Width() / 3) - 30), 1);
m_list.InsertColumn(2, _T(""), LVCFMT_CENTER, 1000, 2);
m_list.InsertItem(0, _T("1"));
m_list.InsertItem(1, _T("2"));
m_list.InsertItem(2, _T("3"));
m_list.InsertItem(3, _T("4"));
m_list.InsertItem(4, _T("5"));
m_list.InsertItem(5, _T("6"));
m_list.InsertItem(6, _T("7"));
m_list.InsertItem(7, _T("8"));
m_list.InsertItem(8, _T("9"));
m_list.InsertItem(9, _T(""));
m_list.InsertItem(10, _T(""));
m_list.InsertItem(11, _T(""));
// TODO: 在此添加额外的初始化代码
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
5.list重写的对应封装代码
BitMark.h
cpp
#pragma once
#define BITMARK_MAX (2500)
#define BITMARK_ROWS_DEF (100)
#define BITMARK_COLS_DEF (20)
class BitMark
{
public:
BitMark(void);
virtual ~BitMark(void);
virtual BOOL Seek(DWORD uRows, DWORD uCols);
virtual void Set(DWORD uRow, DWORD uCol, BOOL bValid);
virtual BOOL IsValid(DWORD uRow, DWORD uCol);
virtual void Clear();
protected:
DWORD m_uRows, m_uCols;
BYTE m_aBit[BITMARK_MAX];
};
BitMark.cpp
cpp
#include "pch.h"
#include "BitMark.h"
#ifdef _AFX
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static const char THIS_FILE[] = __FILE__;
#endif
#endif
BitMark::BitMark(void)
{
ZeroMemory(m_aBit, BITMARK_MAX);
}
BitMark::~BitMark(void)
{
}
BOOL BitMark::Seek(DWORD uRows, DWORD uCols)
{
if((uRows*uCols) > BITMARK_MAX)
return FALSE;
m_uRows = uRows;
m_uCols = uCols;
return TRUE;
}
void BitMark::Set(DWORD uRow, DWORD uCol, BOOL bValid)
{
if((uRow*m_uCols + uCol) >= BITMARK_MAX)
return;
m_aBit[uRow*m_uCols+ uCol] = ( bValid ? 1 : 0 );
}
BOOL BitMark::IsValid(DWORD uRow, DWORD uCol)
{
BOOL bValid =FALSE;
if((uRow*m_uCols + uCol) >= BITMARK_MAX)
return FALSE;
if(0 != m_aBit[uRow*m_uCols + uCol])
bValid = TRUE;
return bValid;
}
void BitMark::Clear()
{
ZeroMemory(m_aBit, BITMARK_MAX);
}
HeaderCtrlEx.h
cpp
#pragma once
#include <afxcmn.h>
class HeaderCtrlEx :
public CHeaderCtrl
{
DECLARE_DYNAMIC(HeaderCtrlEx)
protected:
DECLARE_MESSAGE_MAP()
void OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult);
LRESULT OnLayout(WPARAM wParam, LPARAM lParam);
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
};
HeaderCtrlEx.cpp
cpp
#include "pch.h"
#include "HeaderCtrlEx.h"
IMPLEMENT_DYNAMIC(HeaderCtrlEx, CHeaderCtrl)
BEGIN_MESSAGE_MAP(HeaderCtrlEx, CHeaderCtrl)
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &HeaderCtrlEx::OnNMCustomdraw)
ON_MESSAGE(HDM_LAYOUT, &HeaderCtrlEx::OnLayout)
ON_WM_ERASEBKGND()
END_MESSAGE_MAP()
void HeaderCtrlEx::OnNMCustomdraw(NMHDR* pNMHDR, LRESULT* pResult)
{
// ref: https://stackoverflow.com/questions/28766659/changing-mfc-list-control-header-color
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, RGB(215, 235, 226));
pDC->FillSolidRect(&rect, RGB(30, 34, 39));
*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(RGB(0, 0, 0));
pDC->SetTextColor(RGB(255, 255, 255));
//pDC->SetBkColor(RGB(215, 235, 226));
pDC->SetBkColor(RGB(30, 34, 39));
//CFont m_pFont;
//m_pFont.CreateFont(ConvertWithDPIRatio(31),
// 0, 0, 0, FW_MEDIUM,
// FALSE, FALSE,
// 0,
// ANSI_CHARSET, // nCharSet
// OUT_DEFAULT_PRECIS, // nOutPrecision
// CLIP_DEFAULT_PRECIS, // nClipPrecision
// DEFAULT_QUALITY, // nQuality
// DEFAULT_PITCH | FF_SWISS, _T("Arial"));
//pDC->SelectObject(m_pFont);
CString str(buffer);
CRect rect = pNMCD->rc;
rect.OffsetRect(6, 0);
pDC->DrawText(str, CRect(rect), DT_SINGLELINE | DT_VCENTER);
*pResult = CDRF_SKIPDEFAULT;
}
}
/*
* Describe: Change the height of table header
* Author : Canliang Wu
* Date : 2021/12/15
*/
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;
}
BOOL HeaderCtrlEx::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
//return CListCtrl::OnEraseBkgnd(pDC);
return FALSE;
}
ListControlDefine.h
cpp
#pragma once
#define ListCtrlMask_Rows (500)
#define ListCtrlMask_Cols (20)
#define ListCtrlMask_Max (ListCtrlMask_Rows * ListCtrlMask_Cols)
typedef struct ListCtrlMask {
BYTE Bit[ListCtrlMask_Max];
} ListCtrlMask;
ListControlDefine.cpp
cpp
#include "pch.h"
#include "ListControlDefine.h"
ListCtrlComboEx.h
cpp
#if !defined(AFX_LISTCTRLCOMBOEX_H__CF78F101_D071_46A3_BCA8_CB30861448F1__INCLUDED_)
#define AFX_LISTCTRLCOMBOEX_H__CF78F101_D071_46A3_BCA8_CB30861448F1__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// ListCtrlComboEx.h : header file
#include "ListControlDefine.h"
#include "BitMark.h"
#include "HeaderCtrlEx.h"
#include <afxcmn.h>
#define cgCComboBox CComboBox //you can use yourself defined combobox
/
// CListCtrlComboEx window
#include <vector>
using namespace std;
struct stEditAble
{
int nRow;
int nCol;
};
struct stComboAble
{
int nRow;
int nCol;
cgCComboBox *pCombo;
};
#define IDCB_ONLISTCONTROL 9001
#define CListCtrlComboEx_ColumnMax (200)
class CListCtrlComboEx : public CListCtrl
{
// Construction
public:
CListCtrlComboEx();
public:
UINT m_nMsgComboSelChange;
BitMark m_oBm;
int m_nRowDblClk;
int m_nColDblClk;
int InsertColumn(int nCol, LPCTSTR lpszColumnHeading,
int nFormat = LVCFMT_LEFT, int nWidth = -1, int nSubItem = -1);
void SetItemWarning(int nItem, int nSubItem, BOOL bValid);
int m_anFormat[CListCtrlComboEx_ColumnMax];
void CreateComboBox(UINT nMsgComboSelChange);
void CreateEditBox();
CComboBox* GetCombo();
protected:
CComboBox* m_pcbListCtrl;
HeaderCtrlEx m_HeaderCtrl;
protected:
vector<stEditAble> m_EditAbleArray;
vector<stComboAble> m_ComboAbleArray;
int m_iRow;
int m_iCol;
CEdit *m_pEdit;
int m_iHeight;
CFont m_oFont;
// Attributes
public:
void SetEditAble(int nRow,int nCol);
void SetComboAble(int nRow,int nCol,cgCComboBox *pCombo);
void SetItemHeight(int nHeight);
COLORREF GetTableItemColor(int nRow, int nCol, COLORREF clrDef);
void ClearAllAbles();
BOOL GetCellRect(int nRow, int nCol, CRect& rect);
void SetFontSize(int cHeight = 18);
BOOL m_bFontSeted;
// Operations
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CListCtrlComboEx)
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CListCtrlComboEx();
// Generated message map functions
protected:
BOOL IsEditAble(int nRow,int nCol);
BOOL IsComboAble(int nRow,int nCol);
virtual void PreSubclassWindow();
LPCTSTR MakeShortString(CDC *pDC,LPCTSTR lpszLong,int nColumnLen,int nOffset);
protected:
//{{AFX_MSG(CListCtrlComboEx)
// NOTE - the ClassWizard will add and remove member functions here.
virtual afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult);
virtual afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
virtual afx_msg BOOL OnHeaderEndResize(UINT, NMHDR* pNMHDR, LRESULT* pResult);
afx_msg void OnCbnKillfocusCombo();
afx_msg void OnCbnSelchangeCombo();
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
//}}AFX_MSG
DECLARE_DYNAMIC(CListCtrlComboEx)
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnPaint();
public:
afx_msg BOOL OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult);
};
/
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_LISTCTRLCOMBOEX_H__CF78F101_D071_46A3_BCA8_CB30861448F1__INCLUDED_)
ListCtrlComboEx.cpp
cpp
// ListCtrlComboEx.cpp : implementation file
//
#include "pch.h"
//#include "cgListComboTest.h"
#include "ListCtrlComboEx.h"
//#include "resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/
// CListCtrlComboEx
CListCtrlComboEx::CListCtrlComboEx()
{
m_pcbListCtrl = NULL;
m_nRowDblClk = 0;
m_nColDblClk = 0;
m_bFontSeted = FALSE;
m_EditAbleArray.clear();
m_ComboAbleArray.clear();
m_iRow = -1;
m_iCol = -1;
m_iHeight = 0;
m_pEdit = NULL;
m_nMsgComboSelChange = 0;
ZeroMemory(&m_anFormat, sizeof(m_anFormat));
//m_pListCtrlMask = NULL;
}
CListCtrlComboEx::~CListCtrlComboEx()
{
if(m_pcbListCtrl) {
m_pcbListCtrl->DestroyWindow();
delete m_pcbListCtrl;
m_pcbListCtrl = NULL;
}
}
int CListCtrlComboEx::InsertColumn(int nCol, LPCTSTR lpszColumnHeading,
int nFormat /*= LVCFMT_LEFT*/, int nWidth /*= -1*/, int nSubItem /*= -1*/)
{
if(nCol>=0)
m_anFormat[nCol] = nFormat;
return CListCtrl::InsertColumn(nCol, lpszColumnHeading, nFormat, nWidth, nSubItem);
}
void CListCtrlComboEx::SetItemWarning(int nItem, int nSubItem, BOOL bValid)
{
//return;
m_oBm.Set(nItem, nSubItem, bValid);
}
void CListCtrlComboEx::CreateComboBox(UINT nMsgComboSelChange)
{
m_nMsgComboSelChange = nMsgComboSelChange;
CFont* cf = GetFont();
CComboBox *pCombo;
pCombo = new CComboBox();
CRect rect;
GetCellRect(0,1,rect);
pCombo->Create(WS_CHILD/*|WS_VISIBLE*/|CBS_AUTOHSCROLL|CBS_DROPDOWNLIST,rect,(CWnd*)this, IDCB_ONLISTCONTROL);
pCombo->SetFont(cf);
m_pcbListCtrl = pCombo;
}
CComboBox* CListCtrlComboEx::GetCombo()
{
return m_pcbListCtrl;
}
COLORREF CListCtrlComboEx::GetTableItemColor(int nRow, int nCol, COLORREF clrDef)
{
COLORREF clr;
clr = clrDef; //RGB(0, 0, 0);
//if((nRow*nCol) >= ListCtrlMask_Max)
// return clr;
//if(!m_pListCtrlMask)
// return clr;
//if(m_pListCtrlMask->Bit[nRow*ListCtrlMask_Cols + nCol])
// clr = RGB(255, 0, 0);
if(m_oBm.IsValid(nRow, nCol))
clr = RGB(255, 0, 0);
//if(myutil::GetBit(m_oWarningBitMark.bit[nRow], nCol))
//{
// clr = RGB(255, 0, 0);
//}
//if(myutil::GetBit(theApp.m_pYmVoltTblRow[nRow].upper_warning_bit, nCol))
//{
// clr = RGB(255, 0, 0);
//}
//if(myutil::GetBit(theApp.m_pYmVoltTblRow[nRow].lower_warning_bit, nCol))
//{
// clr = RGB(255, 0, 0);
//}
//if(m_oVoltTbl.v_row[nRow].v[nCol] > m_nUpper)
//{
// clr = RGB(255, 0, 0);
//}
//if(m_oVoltTbl.v_row[nRow].v[nCol] < m_nLower)
//{
// clr = RGB(255, 0, 0);
//}
//if(theApp.m_pYmVoltTblRow[nRow].V.volt[nCol] < theApp.m_pYmVoltTblRow[nRow].Lower)
//{
// clr = RGB(255, 0, 0);
//}
return clr;
}
void CListCtrlComboEx::ClearAllAbles()
{
m_EditAbleArray.clear();
m_ComboAbleArray.clear();
m_iRow = -1;
m_iCol = -1;
m_pEdit = NULL;
}
IMPLEMENT_DYNAMIC(CListCtrlComboEx, CListCtrl)
BEGIN_MESSAGE_MAP(CListCtrlComboEx, CListCtrl)
//{{AFX_MSG_MAP(CListCtrlComboEx)
// NOTE - the ClassWizard will add and remove mapping macros here.
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
ON_NOTIFY_EX(HDN_ENDTRACKA, 0, OnHeaderEndResize)
ON_NOTIFY_EX(HDN_ENDTRACKW, 0, OnHeaderEndResize)
ON_WM_MEASUREITEM_REFLECT()
ON_WM_LBUTTONDOWN()
ON_WM_ERASEBKGND()
ON_CBN_KILLFOCUS(IDCB_ONLISTCONTROL, &CListCtrlComboEx::OnCbnKillfocusCombo)
ON_CBN_SELCHANGE(IDCB_ONLISTCONTROL, &CListCtrlComboEx::OnCbnSelchangeCombo)
//}}AFX_MSG_MAP
ON_WM_PAINT()
ON_NOTIFY_REFLECT_EX(NM_DBLCLK, &CListCtrlComboEx::OnNMDblclk)
END_MESSAGE_MAP()
/
// CListCtrlComboEx message handlers
void CListCtrlComboEx::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{
NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);
int nRow = (int)pLVCD->nmcd.dwItemSpec;
pResult = CDRF_DODEFAULT;
/* // Allow column-traits to perform their custom drawing
if (pLVCD->nmcd.dwDrawStage & CDDS_SUBITEM)
{
CComboBox* pCombo = GetCellColumnTrait(nRow, pLVCD->iSubItem);
if (pCombo != NULL)
return; // Everything is handled by the column-trait
}
// Always perform drawing of cell-focus rectangle
switch (pLVCD->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
*pResult |= CDRF_NOTIFYITEMDRAW;
break;
// Before painting a row
case CDDS_ITEMPREPAINT:
{
*pResult |= CDRF_NOTIFYPOSTPAINT; // Ensure row-traits gets called
*pResult |= CDRF_NOTIFYSUBITEMDRAW; // Ensure column-traits gets called
} break;
// After painting the entire row
case CDDS_ITEMPOSTPAINT:
{
;
} break;
}*/
}
BOOL CListCtrlComboEx::OnHeaderEndResize(UINT, NMHDR* pNMHDR, LRESULT* pResult)
{
int size = m_ComboAbleArray.size();
int i;
for(i=0;i<size;i++)
{
int nRow = m_ComboAbleArray[i].nRow;
int nCol = m_ComboAbleArray[i].nCol;
cgCComboBox *pCombo = m_ComboAbleArray[i].pCombo;
CRect rect;
GetCellRect(nRow,nCol,rect);
rect.bottom -= 2*::GetSystemMetrics(SM_CXEDGE);
pCombo->MoveWindow(rect);
pCombo->SetWindowPos(NULL, // not relative to any other windows
0, 0, // TopLeft corner doesn't change
rect.Width(), (pCombo->GetCount()+1)*rect.Height(), // existing width, new height
SWP_NOMOVE | SWP_NOZORDER // don't move box or change z-ordering.
);
pCombo->ShowWindow(TRUE);
}
Invalidate(FALSE);
return FALSE;
}
void CListCtrlComboEx::OnCbnKillfocusCombo()
{
int size = m_ComboAbleArray.size();
int i;
for(i=0;i<size;i++)
{
int nRow = m_ComboAbleArray[i].nRow;
int nCol = m_ComboAbleArray[i].nCol;
cgCComboBox *pCombo = m_ComboAbleArray[i].pCombo;
pCombo->ShowWindow(FALSE);
}
Invalidate(FALSE);
}
void CListCtrlComboEx::OnCbnSelchangeCombo()
{
CWnd* P = this->GetParent();
if(m_nMsgComboSelChange)
P->PostMessage(m_nMsgComboSelChange);
int size = m_ComboAbleArray.size();
int i;
for(i=0;i<size;i++)
{
int nRow = m_ComboAbleArray[i].nRow;
int nCol = m_ComboAbleArray[i].nCol;
cgCComboBox *pCombo = m_ComboAbleArray[i].pCombo;
pCombo->ShowWindow(FALSE);
}
Invalidate(FALSE);
}
void CListCtrlComboEx::SetItemHeight(int nHeight)
{
m_iHeight = nHeight;
CRect rcWin;
GetWindowRect(&rcWin);
WINDOWPOS wp;
wp.hwnd = m_hWnd;
wp.cx = rcWin.Width();
wp.cy = rcWin.Height();
wp.flags = SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOZORDER;
SendMessage(WM_WINDOWPOSCHANGED,0,(LPARAM)&wp);
}
BOOL CListCtrlComboEx::GetCellRect(int nRow, int nCol,CRect& rect)
{
if (GetSubItemRect(nRow, nCol, LVIR_BOUNDS, rect)==FALSE)
return FALSE;
CRect colRect;
if (GetHeaderCtrl()->GetItemRect(nCol, colRect)==FALSE)
return FALSE;
if (nCol==0)
{
// Fix bug where LVIR_BOUNDS gives the entire row for nCol==0
CRect labelRect;
if (GetSubItemRect(nRow, nCol, LVIR_LABEL, labelRect)==FALSE)
return FALSE;
rect.right = labelRect.right;
rect.left = labelRect.right - colRect.Width();
}
else
{
// Fix bug when width is smaller than subitem image width
rect.right = rect.left + colRect.Width();
}
return TRUE;
}
void CListCtrlComboEx::SetFontSize(int cHeight)
{
if(m_bFontSeted)
return;
m_bFontSeted = TRUE;
m_oFont.CreateFont(
cHeight, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
_T("Arial")); // lpszFacename
SetFont(&m_oFont, TRUE);
}
BOOL CListCtrlComboEx::IsEditAble(int nRow,int nCol)
{
int i;
int size = m_EditAbleArray.size();
if(size > 0)
{
for(i=0;i<size;i++)
{
if(m_EditAbleArray[i].nRow == nRow && m_EditAbleArray[i].nCol == nCol)
return TRUE;
}
}
return FALSE;
}
BOOL CListCtrlComboEx::IsComboAble(int nRow,int nCol)
{
int i;
int size = m_ComboAbleArray.size();
if(size > 0)
{
for(i=0;i<size;i++)
{
if(m_ComboAbleArray[i].nRow == nRow && m_ComboAbleArray[i].nCol == nCol)
return TRUE;
}
}
return FALSE;
}
void CListCtrlComboEx::SetEditAble(int nRow,int nCol)
{
stEditAble sam;
sam.nRow = nRow;
sam.nCol = nCol;
m_EditAbleArray.push_back(sam);
}
void CListCtrlComboEx::SetComboAble(int nRow,int nCol,cgCComboBox *pCombo)
{
stComboAble sam;
sam.nRow = nRow;
sam.nCol = nCol;
sam.pCombo = pCombo;
m_ComboAbleArray.push_back(sam);
CRect rect;
GetCellRect(nRow,nCol,rect);
rect.bottom -= 2*::GetSystemMetrics(SM_CXEDGE);
pCombo->SetWindowPos(NULL, // not relative to any other windows
0, 0, // TopLeft corner doesn't change
rect.Width(), (pCombo->GetCount()+1)*rect.Height(), // existing width, new height
SWP_NOMOVE | SWP_NOZORDER // don't move box or change z-ordering.
);
pCombo->ShowWindow(TRUE);
pCombo->SetFocus();
}
void CListCtrlComboEx::OnLButtonDown(UINT nFlags, CPoint point)
{
int nRow, nCol;
if(m_pEdit != NULL)
{
CString str;
m_pEdit->GetWindowText(str);
SetItemText(m_iRow,m_iCol,str);
m_iRow = -1;
m_iCol = -1;
delete m_pEdit;
// m_pEdit->PostMessage(WM_CLOSE);
m_pEdit = NULL;
}
LVHITTESTINFO lvhti = {0};
lvhti.pt = point;
nRow = ListView_SubItemHitTest(m_hWnd, &lvhti); // SubItemHitTest is non-const
nCol = lvhti.iSubItem;
if (!(lvhti.flags & LVHT_ONITEM))
nRow = -1;
if(nRow == -1 || nCol == -1)
{
CListCtrl::OnLButtonDown(nFlags, point);
return;
}
if(IsEditAble(nRow,nCol))
{
m_iRow = nRow;
m_iCol = nCol;
CRect rect;
GetCellRect(nRow,nCol,rect);
m_pEdit = new CEdit();
m_pEdit->Create(WS_CHILD|ES_LEFT|ES_AUTOHSCROLL,rect,this,0);
CString str;
str = GetItemText(nRow,nCol);
m_pEdit->SetWindowText(str);
m_pEdit->ShowWindow(SW_SHOW);
m_pEdit->SetFocus();
return;
}
CListCtrl::OnLButtonDown(nFlags,point);
}
void CListCtrlComboEx::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
if(m_iHeight>0)
{
lpMeasureItemStruct->itemHeight = m_iHeight;
}
}
void CListCtrlComboEx::PreSubclassWindow()
{
ModifyStyle(0,LVS_OWNERDRAWFIXED);
//CListCtrl::PreSubclassWindow();
CHeaderCtrl* pHeader = GetHeaderCtrl();
if (pHeader != NULL) { VERIFY(m_HeaderCtrl.SubclassWindow(pHeader->m_hWnd)); }
CListCtrl::PreSubclassWindow();
}
void CListCtrlComboEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
int nItem = lpDrawItemStruct->itemID;
if(nItem == -1)
return;
CRect rcCol = lpDrawItemStruct->rcItem;
CString sText;
CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
int nOldDCMode = pDC->SaveDC();
LVITEM item;
item.iItem = nItem;
item.iSubItem = 0;
item.mask = LVIF_IMAGE|LVIF_STATE;
item.stateMask = 0xFFFF;
GetItem(&item);
BOOL bSelected = item.state & LVIS_SELECTED;
COLORREF color = RGB(30, 34, 39);
if(bSelected)
{
pDC->SetBkColor(RGB(30, 34, 39));
pDC->SetTextColor(RGB(255,255,255)/*::GetSysColor(COLOR_HIGHLIGHTTEXT)*//*GetTableItemColor(nItem, item.iSubItem)*/);
color = RGB(30, 34, 39);
}
else
{
pDC->SetBkColor(RGB(30, 34, 39));
pDC->SetTextColor(RGB(255,255,255)/*::GetSysColor(COLOR_WINDOWTEXT)*//*GetTableItemColor(nItem, item.iSubItem)*/);
}
LV_COLUMN lvc;
lvc.mask = LVCF_FMT|LVCF_WIDTH;
rcCol.right = rcCol.left;
for(int nCol=0;GetColumn(nCol,&lvc);nCol++)
{
rcCol.left = rcCol.right;
rcCol.right = rcCol.left + GetColumnWidth(nCol);
HPEN hOldPen = (HPEN)::SelectObject(lpDrawItemStruct->hDC,::CreatePen(PS_SOLID,1,color));
HBRUSH hOldBrush = (HBRUSH)::SelectObject(lpDrawItemStruct->hDC,::CreateSolidBrush(color));
::Rectangle(lpDrawItemStruct->hDC,rcCol.left-1,rcCol.top-1,rcCol.right,rcCol.bottom);
::DeleteObject(SelectObject(lpDrawItemStruct->hDC,hOldBrush));
::DeleteObject(SelectObject(lpDrawItemStruct->hDC,hOldPen));
sText = MakeShortString(pDC,GetItemText(nItem,nCol),rcCol.Width(),3);
if(bSelected)
{
pDC->SetBkColor(RGB(30, 34, 39));
//pDC->SetTextColor(GetTableItemColor(nItem, nCol, ::GetSysColor(COLOR_HIGHLIGHTTEXT)));
pDC->SetTextColor(GetTableItemColor(nItem, nCol, RGB(255, 255, 255)));
color = RGB(30, 34, 39);
}
else
{
pDC->SetBkColor(RGB(30, 34, 39));
pDC->SetTextColor(GetTableItemColor(nItem, nCol, RGB(255, 255, 255)));
}
//在这里进行测试
//在这里进行测试
UINT format = DT_CENTER;
switch(/*lvc.fmt*/m_anFormat[nCol] & (LVCFMT_LEFT | LVCFMT_CENTER | LVCFMT_RIGHT))
{
case LVCFMT_LEFT:
format = DT_LEFT;
break;
case LVCFMT_CENTER:
format = DT_CENTER;
break;
case LVCFMT_RIGHT:
format = DT_RIGHT;
break;
default:
break;
}
pDC->DrawText(sText,CRect::CRect(rcCol.left+3,rcCol.top,rcCol.right,rcCol.bottom), format/*DT_CENTER*//*format*//*DT_LEFT*/|DT_VCENTER|DT_SINGLELINE );
}
pDC->RestoreDC(nOldDCMode);
}
LPCTSTR CListCtrlComboEx::MakeShortString(CDC *pDC,LPCTSTR lpszLong,int nColumnLen,int nOffset)
{
static const _TCHAR szThreeDots[] = _T("...");
int nStringLen = lstrlen(lpszLong);
if(nStringLen == 0 ||
(pDC->GetTextExtent(lpszLong,nStringLen).cx+nOffset) <= nColumnLen)
{
return(lpszLong);
}
static _TCHAR szShort[MAX_PATH];
lstrcpy(szShort,lpszLong);
int nAddLen = pDC->GetTextExtent(szThreeDots,sizeof(szThreeDots)).cx;
for(int i=nStringLen-1; i>0; i--)
{
szShort[i] = 0;
if((pDC->GetTextExtent(szShort,i).cx+nAddLen+nOffset) <= nColumnLen)
{
break;
}
}
lstrcat(szShort,szThreeDots);
return(szShort);
}
void CListCtrlComboEx::OnPaint()
{
//CPaintDC dc(this); // device context for painting
TODO: 在此处添加消息处理程序代码
不为绘图消息调用 CListCtrl::OnPaint()
//
//CPaintDC dc(this); // device context for painting
//const MSG *msg = GetCurrentMessage();
//DefWindowProc( msg->message, msg->wParam, msg->lParam ); //这两句不能省,否则程序会因消息循环出现异常
Draw the lines only for LVS_REPORT mode
//if( (GetStyle() & LVS_TYPEMASK) == LVS_REPORT )
//{
// // Get the number of columns
// CClientDC dc(this );
// CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
// int nColumnCount = pHeader->GetItemCount();
// // The bottom of the header corresponds to the top of the line
// RECT rect;
// pHeader->GetClientRect( &rect );
// int top = rect.bottom;
// // Now get the client rect so we know the line length and
// // when to stop
// GetClientRect( &rect );
// // The border of the column is offset by the horz scroll
// int borderx = 0 - GetScrollPos( SB_HORZ );
// CPen listSepPen(PS_SOLID, 1, RGB(201, 213, 240)); //定制你的分割线的颜色
// //CPen listSepPen(PS_SOLID, 1, RGB(30, 34, 39));
// CPen *pOldPen = dc.SelectObject(&listSepPen);
// for( int i = 0; i < nColumnCount; i++ )
// {
// // Get the next border
// borderx += GetColumnWidth( i );
// // if next border is outside client area, break out
// if( borderx >= rect.right ) break;
// // Draw the line.
// dc.MoveTo( borderx, top);
// dc.LineTo( borderx, rect.bottom );
// }
// // Draw the horizontal grid lines
// // First get the height
// if( !GetItemRect( 0, &rect, LVIR_BOUNDS ))
// return;
// int height = rect.bottom - rect.top;
// GetClientRect( &rect );
// int width = rect.right;
// for(int i = 1; i <= GetCountPerPage(); i++ )
// {
// dc.MoveTo( 0, top + height*i);
// dc.LineTo( width, top + height*i );
// }
// dc.SelectObject(pOldPen);
//
//}
//-------------------------------替换
const MSG* msg = GetCurrentMessage();
DefWindowProc(msg->message, msg->wParam, msg->lParam);
CClientDC dc(this);
CRect rect;
GetClientRect(&rect);
CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
int nColumnCount = pHeader->GetItemCount();
CRect rectHead;
pHeader->GetClientRect(&rectHead);
// 画边框
//CPen penBorder(PS_SOLID, 1, RGB(0, 66, 66));
//CPen* pOldPen = dc->SelectObject(&penBorder);
//dc.MoveTo(rect.left, rect.top );
//dc.LineTo(rect.left, rect.bottom);
//dc.MoveTo(rect.right - 1, rect.top );
//dc.LineTo(rect.right - 1, rect.bottom)
if ((GetStyle() & LVS_TYPEMASK) == LVS_REPORT)
{
CPen penGrid;
//penGrid.CreatePen(PS_SOLID, 1, RGB(0, 66, 66));//颜色
penGrid.CreatePen(PS_SOLID, 1, RGB(48, 48, 48));//颜色
CPen* oldPen = dc.SelectObject(&penGrid);
int borderx = 0 - GetScrollPos(SB_HORZ);
//画边框
//dc.MoveTo(rect.right, rect.top);
//dc.LineTo(rect.left, rect.top);
//dc.MoveTo(rect.right, rect.bottom);
//dc.LineTo(rect.left, rect.bottom);
//dc.MoveTo(rect.left, rect.top);
//dc.LineTo(rect.left, rect.bottom);
//dc.MoveTo(rect.right, rect.top);
//dc.LineTo(rect.right, rect.bottom);
//取客户区域
CRect item;
int nHightPerLine = 18;
if (GetItemRect(0, &item, LVIR_BOUNDS))
{
nHightPerLine = item.bottom - item.top;
}
//画纵向线
for (int i = 0; i < nColumnCount; i++)
{
borderx += GetColumnWidth(i);
if (borderx > rect.right)
{
break;
}
dc.MoveTo(borderx, rectHead.bottom);
dc.LineTo(borderx, rect.bottom);
}
//画横向线
for (int i = 0; i <= GetCountPerPage(); i++)
{
dc.MoveTo(rect.left, rectHead.bottom + nHightPerLine * i + 1);
dc.LineTo(borderx, rectHead.bottom + nHightPerLine * i + 1);
}
dc.SelectObject(penGrid);
penGrid.DeleteObject();
}
}
BOOL CListCtrlComboEx::OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult)
{
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
NM_LISTVIEW* pNMListView=(NM_LISTVIEW*)pNMHDR;
m_nRowDblClk=pNMListView->iItem;//m_row为被选中行的行序号(int类型成员变量)
m_nColDblClk=pNMListView->iSubItem;//m_column为被选中行的列序号(int类型成员变量)
return FALSE;
}
BOOL CListCtrlComboEx::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
//return CListCtrl::OnEraseBkgnd(pDC);
return FALSE;
}