MFC界面美化第四篇----自绘list列表(重绘列表)

news2024/11/26 2:25:57

1.前言

最近发现读者对我的mfc美化的专栏比较感兴趣,因此在这里进行续写,这里我会计划写几个连续的篇章,包括对MFC按钮的美化,菜单栏的美化,标题栏的美化,list列表的美化,直到最后形成一个完整的成品效果。

2.最终效果展示

3.思路分析

1.编写mfc的list的派生类对 列表进行重绘

2.list和其他的空间有些区别,要分别对标题栏,和内容栏进行重绘。

4.实现的过程

1.在mfc界面,增加空间list

2.修改list的属性

边框:false
静态边缘:false
视图:Reporte
无滚动:true
 

3.声明list的变量

public:
	CListCtrlComboEx  m_list;

4.OnInitDialog 里面的核心代码

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

#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

#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

#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

#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

#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

#include "pch.h"
#include "ListControlDefine.h"

ListCtrlComboEx.h

#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

// 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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1531075.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python】反编译PyInstaller打包的exe

查看exe基本信息 需要反编译的exe 查看exe文件的打包工具&#xff0c;查看exe信息的软件叫Detect It Easy(查壳工具) 由图我们可以看出当前选中的exe文件是由名叫PyInstaller的打包工具打包好的exe 反编译 exe反编译工具&#xff1a;pyinstxtractor.py 使用方法 python py…

VMWare虚拟机使用openmediavault搭建NAS服务器完整步聚

下载: gopenmediavault - The open network attached storage solution 下载好openmediavault的ISO镜像后,打开虚拟机并安装 系统类型选择Debian 启动虚拟机并安装openmediavault 选择中文 地区选中国 键盘配置选汉语 开始安装 配置网络信息 配置root密码 确认密码 系统安装中…

spark基本原理UI界面解读

这里是引用 1 八股文 1.1 基本原理 driver节点是整个应用程序的指挥所 指挥官是sparkcontext 环境&#xff1a;构建一个集群 应用程序提交 确定主节点&#xff0c;确定指挥所driver&#xff0c;确定指挥官sparkcontext sparkcontext会向资源管理器申请资源 会将作业分…

英伟达出品:全球最强大芯片Blackwell来了!采用4nm制程,2080 亿个晶体管组,支持10万亿参数模型

更多精彩内容在 美国加利福尼亚州圣何塞 —— 2024 年 3 月 18 日 —— NVIDIA 于今日宣布推出 NVIDIA Blackwell 平台以赋能计算新时代。该平台可使世界各地的机构都能够在万亿参数的大语言模型&#xff08;LLM&#xff09;上构建和运行实时生成式 AI&#xff0c;其成本和能耗…

机器视觉系统选型-精度计算

eg&#xff1a;1.康耐视500w相机拍照&#xff0c;视野为50mm40mm&#xff0c;所使用的视觉工具精度为个像素&#xff0c;求测量精度&#xff1f;&#xff08;500w相机分辨率为25921944&#xff09; 相机精度:(即像素分辨率) 相机精度50mm/25920.0193mm 测量精度&#xff1a;测量…

Source Insight使用-添加新的文件类型

目录 遇到的问题解决方法结果 遇到的问题 在Source Insight中我们通常查看.c和.h文件&#xff0c;当使用其查看.java 或者.hal等类型文件时&#xff0c;发现找不到 解决方法 以添加.hal文件为例: 选择Options 下面的File Type Options… 选项。 点击左侧的 “C/C Source F…

mysql索引实现

什么是索引失效 在MySQL中&#xff0c;索引失效指的是查询语句无法有效地使用索引&#xff0c;而必须进行全表扫描。索引失效可能会导致查询性能下降&#xff0c;特别是在处理大量数据时。 索引失效的原因 1.索引列进行了运算或函数操作 如果对索引列进行了运算或使用了函数…

Linux命令进程管理工具top、ps、jps和tar以及守护进程nohup

进程管理工具top ps 概述 top 和 ps 是 Linux 系统中两个非常重要的用于管理和监控进程的命令工具。以下是它们的主要功能和区别&#xff1a; top&#xff1a; 动态视图&#xff1a;top 提供了一个实时动态更新的视图&#xff0c;能够持续显示系统中当前正在运行的进程信息及其…

软考 网工 每日学习打卡 2024/3/19

学习内容 第8章 网络安全 本章主要讲解网络安全方面的基础知识和应用技术。针对考试应该掌握诸如数据加密、报文认 证、数字签名等基本理论&#xff0c;在此基础上深入理解网络安全协议的工作原理&#xff0c;并能够针对具体的 网络系统设计和实现简单的安全解决方案。 本章共有…

C++ —— 类和对象(终)

目录 1. 日期类的实现 1.1 前置 和 后置 重载 1.2 >> 和 << 的重载 2. const 成员 3. 取地址及const取地址操作符重载 4. 再谈构造函数 4.1 构造函数体赋值 4.2 初始化列表 4.3 隐式类型转换 4.4 explict 关键字 5. static 成员 5.1 概念 5.2 特性 …

Java 的强引用、弱引用、软引用、虚引用

1、强引用&#xff08;StrongReference&#xff09; 强引用是使用最普遍的引用。如果一个对象具有强引用&#xff0c;那垃圾回收器绝不会回收它。如下&#xff1a; Object onew Object(); // 强引用 当内存空间不足&#xff0c;Java虚拟机宁愿抛出OutOfMemoryError错误&am…

Java多线程实战-CompletableFuture异步编程优化查询接口响应速度

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️本系列源码仓库&#xff1a;多线程并发编程学习的多个代码片段(github) &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正…

Spring 6.0和SpringBoot 3.0有什么新特性?

Spring在2022年相继推出了Spring Framework 6.0和SpringBoot 3.0&#xff0c;Spring把这次升级称之为新一代框架的开始&#xff0c;下一个10年的新开端 一、问题解析 主要更新内容是以下几个&#xff1a; ● A Java 17 baseline ● Support for Jakarta EE 10 with an EE 9 ba…

永磁同步电机无位置传感器系列(1)——非线性磁链观测器的仿真复现过程

无位置传感器控制&#xff0c;这个方向也是电机控制里面的大热门了。最近在看PLL&#xff0c;中国电机有一篇ESO-PLL获得了23年的高影响力论文&#xff0c;标题如下。因为这篇ESO-PLL需要用到下面这篇英文文献的转子位置观测器&#xff0c;想着就先把这个观测器的文章给复现了。…

【工具】vscode终端打不开

问题 1The terminal process failed to launch: A native exception occurred during launch (forkpty(3) failed.). 参考方案 下面参考链接是针对windows系统上vscode 出现的相同问题的解答 参考链接&#xff1a;https://blog.csdn.net/weixin_40921421/article/details/122…

农业四情监测设备—全面、准确地收集农田环境数据

型号推荐&#xff1a;云境天合TH-Q3】农业四情监测设备是一种高科技的农田监测工具&#xff0c;旨在实时监测和管理农田中的土壤墒情、作物生长、病虫害以及气象条件。这些设备综合运用了传感器、摄像头、气象站等技术手段&#xff0c;能够全面、准确地收集农田环境数据&#x…

机器学习之客户违约预测模型搭建之原理篇

前言 这一章主要介绍机器学习在金融领域一个重要应用&#xff1a;客户违约预测模型的搭建&#xff0c;其所用到原理为机器学习中的决策树模型。通过本章的学习&#xff0c;您能了解在信息时代下金融风险控制的新手段&#xff0c;并对机器学习有一个初步的了解。 1. 机器学习在…

【JavaScript】JavaScript 运算符 ⑤ ( 运算符优先级 )

文章目录 一、JavaScript 运算符优先级1、运算符优先级 概念2、运算符优先级 列举3、运算符示例 一、JavaScript 运算符优先级 1、运算符优先级 概念 JavaScript 的 运算符 是有 " 优先级 " 的 , " 运算符优先级 " 决定 一个表达式中 多个 运算符的 执行顺…

【每日一题】好子数组的最大分数

Tag 【单调栈】【暴力枚举】【数组】【2024-03-19】 题目来源 1793. 好子数组的最大分数 解题思路 本题和 84. 柱状图中最大的矩形 一样&#xff0c;计算的都是最大矩形的面积。只不过多了一个约束&#xff1a;矩形必须包含下标 k。 以下的方法一和方法二是 84. 柱状图中最…

你还在花钱看短剧吗?这些人做短剧推广已经通过短剧赚钱了

短剧分销&#xff0c;简单来说&#xff0c;就是你在抖音、快手、小红书等短视频平台浏览时看到的一半时&#xff0c;指引你去其他平台观看完整版的操作。 而使用“蜂小推”做短剧推广&#xff0c;你也能利用短剧快速致富~ 想要进行短剧分销&#xff0c;你需要经过一系列步骤&a…