⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 reportctrl.cpp

📁 用户管理系统
💻 CPP
📖 第 1 页 / 共 3 页
字号:
#include "stdafx.h"
#include "ReportCtrl.h"
#include <afxtempl.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

///////////////////////////////////////////////////////////////////////////////
// ReportCtrl.cpp
//
// Written by Bin Liu (abinn32@163.com)
//
// Special notes: The sorting methods was inspired by Mark Jackson in his "Sort List
//                Control" article on http://www.codeproject.com 
//
// This file is the implementation of class "CReportCtrl", which is derived from MFC class
// "CListCtrl" and specialized in the "Report" style list control manipulation.
//
// A bunch of methods are implemented or overloaded in this class in order to provide
// fast, efficient and convenient access and operations. For example, it is no more
// necessary to convert all other data types into character strings before
// using "SetItemText", you can pass in whatever into "SetItemText" because
// this class overloaded "SetItemText" for all common data types.
//
// Moreover, using heap pointers as list item data has become more safer since
// the user defined CALLBACK function "BOOL (*) (DWORD)" will be called every time
// _before_ a list item is actually being deleted, therefore you can perform the
// cleanup period to the deletion of each item.
//
// This code may be used in compiled form in any way you desire. This file may be
// redistributed unmodified by any means PROVIDING it is not sold for profit without
// the authors written consent, and providing that this notice and the authors name 
// is included. If the source code in  this file is used in any commercial application 
// then acknowledgement must be made to the author of this file .
//
// This file is provided "as is" with no expressed or implied warranty.
//
// Special notes: The sorting methods was inspired by Mark Jackson in his "Sort List
//                Control" article on http://www.codeproject.com 
///////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////
// The item data class, stores item data and item text array for sorting
///////////////////////////////////////////////////////////////////////////
class ItemData
{
public:
	ItemData() : dwData(0) {} 
	CStringArray arrStr; // item texts
	DWORD dwData; // the actual item data
};


////////////////////////////////////////////////////////////////////////////
// CReportHeaderCtrl implementation
////////////////////////////////////////////////////////////////////////////
/*
CReportCtrl::CReportHeaderCtrl::CReportHeaderCtrl()
{
	m_iSortColumn = -1;
	m_bSortAscending = 0;
}

int CReportCtrl::CReportHeaderCtrl::GetSortedColumn() const
{
	return m_iSortColumn;
}

int CReportCtrl::CReportHeaderCtrl::IsSortAscending() const
{
	return m_bSortAscending;
}

void CReportCtrl::CReportHeaderCtrl::SetSortAscending(int  bAscending)
{
	m_bSortAscending = bAscending;
}

void CReportCtrl::CReportHeaderCtrl::SetSortedColumn(int nCol)
{
	m_iSortColumn = nCol;
}

////////////////////////////////////////////////////////////////////////////////
// Mark Jackson's code
////////////////////////////////////////////////////////////////////////////////
void CReportCtrl::CReportHeaderCtrl::UpdateSortArrow()
{
	// change the item to owner drawn.
	HD_ITEM hditem;

	hditem.mask = HDI_FORMAT;
	VERIFY(GetItem(m_iSortColumn, &hditem));
	hditem.fmt |= HDF_OWNERDRAW;
	VERIFY(SetItem(m_iSortColumn, &hditem));

	// invalidate the header control so it gets redrawn
	Invalidate();
}

////////////////////////////////////////////////////////////////////////////////
// Mark Jackson's code
////////////////////////////////////////////////////////////////////////////////
void CReportCtrl::CReportHeaderCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
	// attath to the device context.
	CDC dc;
	VERIFY(dc.Attach(lpDrawItemStruct->hDC));

	// save the device context.
	const int iSavedDC = dc.SaveDC();

	// get the column rect.
	CRect rc(lpDrawItemStruct->rcItem);

	// set the clipping region to limit drawing within the column.
	CRgn rgn;
	VERIFY(rgn.CreateRectRgnIndirect(&rc));
	(void)dc.SelectObject(&rgn);
	VERIFY(rgn.DeleteObject());

	// draw the background,
	CBrush brush(GetSysColor(COLOR_3DFACE));
//	CBrush brush(RGB(255,0,0));
	dc.FillRect(rc, &brush);

	// get the column text and format.
	TCHAR szText[ 256 ];
	HD_ITEM hditem;

	hditem.mask = HDI_TEXT | HDI_FORMAT;
	hditem.pszText = szText;
	hditem.cchTextMax = 255;

	VERIFY(GetItem(lpDrawItemStruct->itemID, &hditem));

	// determine the format for drawing the column label.
	UINT uFormat = DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER | DT_END_ELLIPSIS ;

	if(hditem.fmt & HDF_CENTER)
		uFormat |= DT_CENTER;
	else if(hditem.fmt & HDF_RIGHT)
		uFormat |= DT_RIGHT;
	else
		uFormat |= DT_LEFT;

	// adjust the rect if the mouse button is pressed on it.
	if(lpDrawItemStruct->itemState == ODS_SELECTED)
	{
		rc.left++;
		rc.top += 2;
		rc.right++;
	}

	CRect rcIcon(lpDrawItemStruct->rcItem);
	const int iOffset = (rcIcon.bottom - rcIcon.top) / 4;

	// adjust the rect further if the sort arrow is to be displayed.
	if(lpDrawItemStruct->itemID == (UINT)m_iSortColumn)
		rc.right -= 3 * iOffset;

	rc.left += iOffset;
	rc.right -= iOffset;

      dc.SetBkMode(TRANSPARENT);
	// draw the column label.
	if(rc.left < rc.right)
		(void)dc.DrawText(szText, -1, rc, uFormat);

	// draw the sort arrow.
	if(lpDrawItemStruct->itemID == (UINT)m_iSortColumn)
	{
		// set up the pens to use for drawing the arrow.
		CPen penLight(PS_SOLID, 1, GetSysColor(COLOR_3DHILIGHT));
		CPen penShadow(PS_SOLID, 1, GetSysColor(COLOR_3DSHADOW));
		CPen* pOldPen = dc.SelectObject(&penLight);

		if(m_bSortAscending > 0)
		{
			// draw the arrow pointing upwards.
			dc.MoveTo(rcIcon.right - 2 * iOffset, iOffset);
			dc.LineTo(rcIcon.right - iOffset, rcIcon.bottom - iOffset - 1);
			dc.LineTo(rcIcon.right - 3 * iOffset - 2, rcIcon.bottom - iOffset - 1);
			(void)dc.SelectObject(&penShadow);
			dc.MoveTo(rcIcon.right - 3 * iOffset - 1, rcIcon.bottom - iOffset - 1);
			dc.LineTo(rcIcon.right - 2 * iOffset, iOffset - 1);		
		}
		else if(m_bSortAscending < 0)
		{
			// draw the arrow pointing downwards.
			dc.MoveTo(rcIcon.right - iOffset - 1, iOffset);
			dc.LineTo(rcIcon.right - 2 * iOffset - 1, rcIcon.bottom - iOffset);
			(void)dc.SelectObject(&penShadow);
			dc.MoveTo(rcIcon.right - 2 * iOffset - 2, rcIcon.bottom - iOffset);
			dc.LineTo(rcIcon.right - 3 * iOffset - 1, iOffset);
			dc.LineTo(rcIcon.right - iOffset - 1, iOffset);		
		}

		// restore the pen.
		(void)dc.SelectObject(pOldPen);
	}
//exit01:
	// restore the previous device context.
	VERIFY(dc.RestoreDC(iSavedDC));

	// detach the device context before returning.
	(void)dc.Detach();
}
*/

////////////////////////////////////////////////////////////////////////////
// CReportCtrl implementation
////////////////////////////////////////////////////////////////////////////
CReportCtrl::CReportCtrl()
{
}

CReportCtrl::~CReportCtrl()
{
}

BEGIN_MESSAGE_MAP(CReportCtrl, CListCtrlBase)
	//{{AFX_MSG_MAP(CReportCtrl)
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnClick)
	ON_WM_DESTROY()
	ON_WM_VSCROLL()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CReportCtrl message handlers

void CReportCtrl::PreSubclassWindow()
{
	// the list control must have the report style.
	ASSERT(GetStyle() & LVS_REPORT);

	CListCtrlBase::PreSubclassWindow();
	VERIFY(m_wndHeader.SubclassWindow(GetHeaderCtrl()->GetSafeHwnd()));
	
	// I can't see any reason that a report list does not use LVS_EX_FULLROWSELECT style,
	// but of course, user can remove this style by "SetFullRowSelect(FALSE)" any time.
	SetFullRowSelect(TRUE);
}

BOOL CReportCtrl::_IsValidIndex(int nIndex) const
{
	return nIndex >= 0 && nIndex < CListCtrl::GetItemCount();
}

////////////////////////////////////////////////////////////////////////////////
// Mark Jackson's code
////////////////////////////////////////////////////////////////////////////////
BOOL CReportCtrl::SetHeadings(UINT uiStringID)
{
	CString strHeadings;
	VERIFY(strHeadings.LoadString(uiStringID));
	return SetHeadings(strHeadings);
}

////////////////////////////////////////////////////////////////////////////////
// Mark Jackson's code, modified by Bin Liu
////////////////////////////////////////////////////////////////////////////////
// the heading text is in the format column 1 text,column 1 width;column 2 text,column 3 width;etc.
BOOL CReportCtrl::SetHeadings(const CString& strHeadings)
{
	CString sPara;
	int nParaStart = 0;
	int nSemiColon = -1;
	BOOL bContinue = TRUE;
	while (nSemiColon < strHeadings.GetLength())
	{
		// determine the paragraph ("xxx,xxx,xxx;")
		nSemiColon = strHeadings.Find(_T(';'), nParaStart);
		if(nSemiColon == -1)
		{
			// reached the end of string
			nSemiColon = strHeadings.GetLength();
			bContinue = FALSE;
		}

		sPara = strHeadings.Mid(nParaStart, nSemiColon - nParaStart);
		nParaStart = nSemiColon + 1; // ready to move on to next paragraph
		
		int iStart = 0;
		int iComma = -1;

		// find the heading name string
		iComma = sPara.Find(_T(','), iStart);

		if(iComma == -1)
			break;

		const CString sColName = sPara.Mid(iStart, iComma - iStart);

		iStart = iComma + 1;

		// find the heading format string (0=LVCFMT_LEFT, 1=LVCFMT_CENTER, 2=LVCFMT_RIGHT)
		int nFmt = LVCFMT_LEFT;
		iComma = sPara.Find(_T(','), iStart);
		if (iComma == -1)
		{
			// user does not specify a format, so use LVCFMT_LEFT as default)
		}
		else
		{
			// there is a format string
			int n = _ttoi(sPara.Mid(iStart, iComma - iStart));

			if (n == 1)
				nFmt = LVCFMT_CENTER;
			else if (n == 2)
				nFmt = LVCFMT_RIGHT;
			else
				nFmt = LVCFMT_LEFT;
			
			iStart = iComma + 1;
		}

		// remained is the column width string
		int iWidth = _ttoi(sPara.Mid(iStart, sPara.GetLength() - iStart));
		if (iWidth < 1)
			iWidth = 1; // width should be at least 1
		if(InsertColumn(m_wndHeader.GetItemCount(), sColName, nFmt, iWidth) == -1)
			return FALSE;
	}

	return TRUE;
}

int CReportCtrl::InsertItemEx(int nIndex, LPCTSTR pszText, ...)
{
	const int iIndex = CListCtrl::InsertItem(nIndex, pszText);

	if (!_IsValidIndex(iIndex))
		return iIndex;

	CStringArray arr;
	arr.Add(pszText);

 	va_list list;
	va_start(list, pszText);

	for(int iColumn = 1; iColumn < GetColumnCount(); iColumn++)
	{
		LPCTSTR lpsz = va_arg(list, LPCTSTR);
		CString str = (lpsz == NULL) ? _T("") : lpsz;
		arr.Add(str);
		CListCtrl::SetItemText(iIndex, iColumn, str);
	}

	va_end(list);

	_AssignNewItemData(iIndex, arr.GetData(), arr.GetSize());

	return iIndex;
}

void CReportCtrl::_FreeItemMemory(const int iItem)
{
	ASSERT(_IsValidIndex(iItem));
	ItemData* pid = reinterpret_cast<ItemData*>(CListCtrl::GetItemData(iItem));
	if (pid)
	{
		delete pid;
		pid = NULL;
	}

	VERIFY(CListCtrl::SetItemData(iItem, NULL));
}

BOOL CReportCtrl::DeleteItem(int iItem)
{
	if (!_IsValidIndex(iItem))
		return FALSE;
	
//	if (lpFunc != NULL && !lpFunc(GetItemData(iItem), lParam))
//		return FALSE;

	DWORD dwData = CListCtrl::GetItemData(iItem);
	if (CListCtrl::DeleteItem(iItem))
	{
		// Free memory
		ItemData* pData = reinterpret_cast<ItemData*>(dwData);
		if (pData != NULL)
			delete pData;

		return TRUE;
	}
	else
	{
		return FALSE;
	}
}
BOOL CReportCtrl::DeleteItem(int iItem, BOOL bSelectNextItem, ITEMDATAPROC lpFunc, LPARAM lParam)
{
	if (!_IsValidIndex(iItem))
		return FALSE;
	
	if (lpFunc != NULL && !lpFunc(GetItemData(iItem), lParam))
		return FALSE;

	DWORD dwData = CListCtrl::GetItemData(iItem);
	if (CListCtrl::DeleteItem(iItem))
	{
		// Free memory
		ItemData* pData = reinterpret_cast<ItemData*>(dwData);
		if (pData != NULL)
			delete pData;

		if (bSelectNextItem)
			SelectItem(iItem, TRUE);

		return TRUE;
	}
	else
	{
		return FALSE;
	}
}

BOOL CReportCtrl::DeleteAllItems()
{

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -