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

📄 clistctrlex.cpp

📁 VC网络程序设计实例导航配套代码
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/*
	CListCtrlEx.cpp
	Classe derivata per la gestione di CListCtrl con menu a comparsa (MFC).
	Luca Piergentili, 06/07/98
	lpiergentili@yahoo.com
	http://www.geocities.com/lpiergentili/
*/
#include "env.h"
#include "pragma.h"
#include "window.h"
#include <commctrl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "strcpyn.h"
#include "win32api.h"
#include "CNodeList.h"
#include "CListCtrlEx.h"

static BOOL		bAscending = FALSE;				// flag per direzione ordinamento righe
static char		cType = 'C';					// tipo dati per ordinamento righe
static int CALLBACK	CompareItems(LPARAM,LPARAM,LPARAM);// confronta i due elementi (ordinamento)
static LPCSTR		GetItemToken(int,LPCSTR);		// estrae dalla riga il campo relativo alla colonna

BEGIN_MESSAGE_MAP(CListCtrlEx,CListCtrl)
	ON_WM_LBUTTONDOWN()							// click bottone sinistro
	ON_WM_LBUTTONUP()							// rilascio bottone sinistro
	ON_WM_RBUTTONDOWN()							// click bottone destro
	ON_WM_RBUTTONUP()							// rilascio bottone destro
	ON_WM_LBUTTONDBLCLK()						// doppio click bottone sinistro
	ON_WM_RBUTTONDBLCLK()						// doppio click bottone destro
	ON_NOTIFY_REFLECT(LVN_COLUMNCLICK,OnColumnClick)	// click sull'header della colonna
END_MESSAGE_MAP()

/*
	CListCtrlEx()
*/
CListCtrlEx::CListCtrlEx()
{
	Initialize();
}

/*
	~CListCtrlEx()
*/
CListCtrlEx::~CListCtrlEx()
{
	Destroy();
}

/*
	Initialize()
*/
void CListCtrlEx::Initialize(void)
{
	m_nRedrawCount          = 0;
	m_nCurrentItem          = LB_ERR;
	m_nTotColumns           = 0;
	/*
	#define ILC_MASK                0x0001
	#define ILC_COLOR               0x0000
	#define ILC_COLORDDB            0x00FE
	#define ILC_COLOR4              0x0004
	#define ILC_COLOR8              0x0008
	#define ILC_COLOR16             0x0010
	#define ILC_COLOR24             0x0018
	#define ILC_COLOR32             0x0020
	#define ILC_PALETTE             0x0800      // (not implemented)
	*/
	m_IlcColor              = ILC_MASK;
	m_pWnd                  = NULL;
	m_pWinApp               = NULL;
	m_Point.x               = 0;
	m_Point.y               = 0;
	m_nMenuMessage          = (UINT)-1;
	m_nLButtonDownMessage   = (UINT)-1;
	m_nLButtonUpMessage     = (UINT)-1;
	m_nRButtonDownMessage   = (UINT)-1;
	m_nRButtonUpMessage     = (UINT)-1;
	m_nLButtonDblClkMessage = (UINT)-1;
	m_nRButtonDblClkMessage = (UINT)-1;
	m_bRightClickSelects    = FALSE;
	m_NullRow.ico           = -1;
	m_NullRow.item = new char[8];
	if(m_NullRow.item)
		strcpy(m_NullRow.item,"[null]");
	m_NullRow.menu          = -1;
	m_NullRow.selected      = FALSE;
	m_NullRow.index         = -1;
	m_bMultipleSelection    = FALSE;
}

/*
	Destroy()
*/
void CListCtrlEx::Destroy(void)
{
	m_nCurrentItem          = LB_ERR;
	m_RowList.DeleteAll();
	m_ColList.DeleteAll();
	m_ImageList.DeleteImageList();
	m_ImageListSmall.DeleteImageList();
	m_nTotColumns           = 0;
	m_pWnd                  = NULL;
	m_pWinApp               = NULL;
	m_Point.x               = 0;
	m_Point.y               = 0;
	m_nMenuMessage          = (UINT)-1;
	m_nLButtonDownMessage   = (UINT)-1;
	m_nLButtonUpMessage     = (UINT)-1;
	m_nRButtonDownMessage   = (UINT)-1;
	m_nRButtonUpMessage     = (UINT)-1;
	m_nLButtonDblClkMessage = (UINT)-1;
	m_nRButtonDblClkMessage = (UINT)-1;
	m_bRightClickSelects    = FALSE;
	m_NullRow.ico           = -1;
	if(m_NullRow.item)
	{
		delete [] m_NullRow.item;
		m_NullRow.item = NULL;
	}
	m_NullRow.menu          = -1;
	m_NullRow.selected      = FALSE;
	m_NullRow.index         = -1;
}

/*
	Create()

	Crea il controllo.
	
	CWnd* pCWnd = AfxGetMainWnd()		puntatore alla finestra principale per l'invio dei messaggi
	CWinApp* pCWinApp = AfxGetApp()	puntatore all'applicazione principale gli id delle icone
*/
BOOL CListCtrlEx::Create(CWnd* pCWnd,CWinApp* pCWinApp)
{
	// inizializza
	Destroy();
	Initialize();

	// puntatore alla finestra/applicazione principale
	m_pWnd = pCWnd;
	m_pWinApp = pCWinApp;

	// elimina le colonne eventualmente presenti
	while(CListCtrl::DeleteColumn(0))
		;

	// elimina le righe eventualmente presenti
	CListCtrl::DeleteAllItems();

	// liste immagini
	BOOL bCreated = TRUE;
	if(bCreated)
		bCreated = m_ImageList.Create(32,32,m_IlcColor/*ILC_COLOR32*/ /*1*/,0,5);
	if(bCreated)
		bCreated = m_ImageListSmall.Create(16,16,m_IlcColor/*ILC_COLOR32*/ /*1*/,0,5);

	return(bCreated);
}

/*
	SetRedraw()
*/
void CListCtrlEx::SetRedraw(BOOL bRedraw)
{
	if(!bRedraw)
	{
		if(m_nRedrawCount++ <= 0)
			CListCtrl::SetRedraw(false);
	}
	else
	{
		if(--m_nRedrawCount <= 0)
		{
			CListCtrl::SetRedraw(true);
			m_nRedrawCount = 0;
			CListCtrl::Invalidate();
		}
	}
}

/*
	AutoSizeColumns()

	Dimensiona automaticamente le colonne in base al contenuto/etichetta.
	Da chiamare dopo aver riempito il controllo.l
	Da usare solo se il controllo si trova in modalita' report.
*/
void CListCtrlEx::AutoSizeColumns(int nCol/*=-1*/,int nWidth/*=0*/) 
{
	SetRedraw(FALSE);

	if(!(GetStyle() & LVS_REPORT))
		return;

	int nMinCol = nCol < 0 ? 0 : nCol;
	int nMaxCol = nCol < 0 ? GetColumnCount()-1 : nCol;
	
	for(nCol = nMinCol; nCol <= nMaxCol; nCol++) 
	{
		if(nWidth==0)
		{
			CListCtrl::SetColumnWidth(nCol,LVSCW_AUTOSIZE);
			int nWidthAutosize = CListCtrl::GetColumnWidth(nCol);

			CListCtrl::SetColumnWidth(nCol,LVSCW_AUTOSIZE_USEHEADER);
			int nWidthUseHeader = CListCtrl::GetColumnWidth(nCol);

			CListCtrl::SetColumnWidth(nCol,max(MINCOLWIDTH,max(nWidthAutosize,nWidthUseHeader)));
		}
		else
			CListCtrl::SetColumnWidth(nCol,nWidth);     
	}

	SetRedraw(TRUE);
}

/*
	GetColumnCount()

	Ricava il numero di colonne del controllo.
*/
int CListCtrlEx::GetColumnCount(void)
{
	CHeaderCtrl* pHeader = (CHeaderCtrl*)CListCtrl::GetDlgItem(0);
	return(pHeader ? pHeader->GetItemCount() : 0);
}

/*
	GetRowByItem()

	Ricava il puntatore alla riga relativa all'elemento.
	L'elemento (indice base 0 dell'elemento di CListCtrl) corrisponde con l'indice (base 0) della riga,
	da mantenere aggiornato in base agli spostamenti degli items di ClistCtrl.
	Da non confondere con l'indice interno di CNodeList.

	int nItem		indice (base 0) dell'item per la riga da cercare
*/
CTRL_ROW* CListCtrlEx::GetRowByItem(int nItem)
{
	ITERATOR iter;
	CTRL_ROW* ra = NULL;

	if((iter = m_RowList.First())!=(ITERATOR)NULL)
		while(iter!=(ITERATOR)NULL)
		{
			ra = (CTRL_ROW*)iter->data;
			if(ra)
			{
				if(ra->index==nItem)
					break;
				else
					ra = NULL;
			}
			iter = m_RowList.Next(iter);
		}

	return(ra);
}

/*
	GetColByItem()

	Ricava il puntatore alla colonna relativa all'elemento.
	L'elemento (indice base 0 dell'elemento di CListCtrl) corrisponde con l'indice (base 0) della riga.
	Dato che le colonne non cambiano di posizione, tale indice corrisponde con l'indice interno di
	CNodeList, per cui la ricerca puo essere effettuata con FindAt().

	int nItem		indice (base 0) dell'item per la colonna da cercare
*/
CTRL_COL* CListCtrlEx::GetColByItem(int nItem)
{
	ITERATOR iter;
	CTRL_COL* ca = NULL;

	if((iter = m_ColList.FindAt(nItem))!=NULL)
		ca = (CTRL_COL*)iter->data;

	return(ca);
}

/*
	AddCol()

	Aggiunge la colonna al controllo.

	LPCSTR lpcszColumnText	testo per l'intestazione della colonna
	char cDataType	= 'C'	carattere per il tipo dei dati contenuti nella colonna: 'C' carattere, 'N' numerico
	int nWidth = -1		dimensione della colonna (in pixel)
	BOOL bDescend = FALSE	flag per ordinamento (FALSE=discendente, TRUE=ascendente)
*/
int CListCtrlEx::AddCol(LPCSTR lpcszColumnText,char cDataType,int nWidth,BOOL bDescend)
{
	int nCurrentCol = LB_ERR;

	// crea la colonna
	CTRL_COL* ca = new CTRL_COL;

	if(ca)
	{
		memset(ca,'\0',sizeof(CTRL_COL));
		int len = strlen(lpcszColumnText)+1;
		ca->item = new char[len];
		memset(ca->item,'\0',len);
		
		// aggiunge la colonna alla lista
		if(m_ColList.Add(ca))
		{
			CSize size;
			LPSTR lpToken;
			LV_COLUMN lvcolumn;

			// indice (base 0) della nuova colonna
			int nCol = m_nTotColumns++;

			strcpy(ca->item,lpcszColumnText);

			// ordinamento colonna (default FALSE = discendente)
			ca->type  = cDataType;
			ca->order = bDescend;
			
			// elemento
			lvcolumn.mask     = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT | LVCF_WIDTH;
			lvcolumn.fmt      = LVCFMT_LEFT;
			lvcolumn.pszText  = ca->item;
			lvcolumn.iSubItem = nCol;
			
			// calcola la dimensione (in pixel) della colonna in base alla dimensione del testo
			// della colonna e del testo della prima riga (+15 per l'icona)
			if(nWidth <= 0)
			{
				lpToken = "";

				if(CListCtrl::GetItemCount() > 0)
				{
					CTRL_ROW* ra;
					if((ra = GetRowByItem(0))!=NULL)
						lpToken = (LPSTR)GetItemToken(nCol,ra->item);
				}
				else
				{
					lpToken = ca->item;
				}

				int nColSize  = CListCtrl::GetStringWidth(lvcolumn.pszText);
				int nItemSize = CListCtrl::GetStringWidth(lpToken);
				size.cx       = nColSize > nItemSize ? nColSize : nItemSize;
				lvcolumn.cx   = size.cx + 15;
			}
			else
			{
				lvcolumn.cx = nWidth;
			}
			
			// inserisce la colonna
			if((nCurrentCol = CListCtrl::InsertColumn(nCol,&lvcolumn)) < 0)
				nCurrentCol = LB_ERR;
		}
	}

	return(nCurrentCol);
}

/*
	AddItem()

	Aggiunge la riga al controllo.

	LPCSTR lpcszItemText	testo per l'elemento della riga (separare il testo per le colonne con ';')
	int nIconIndex = 0		indice dell'icona relativa
	int nMenuIndex = -1		indice del menu relativo
*/
int CListCtrlEx::AddItem(LPCSTR lpcszItemText,int nIconIndex,int nMenuIndex) 
{
	int nCurrentItem = LB_ERR;

	// crea la riga
	CTRL_ROW* ra = new CTRL_ROW;
	
	if(ra)
	{
		memset(ra,'\0',sizeof(CTRL_ROW));
		int len = strlen(lpcszItemText)+1;
		ra->item = new char[len];
		memset(ra->item,'\0',len);
		strcpy(ra->item,lpcszItemText);

		// aggiunge la riga alla lista
		if(m_RowList.Add(ra))
		{
			int nItem,nSubItem;
			LV_ITEM lvitem;

			// indice (base 0) della nuova riga
			nItem = CListCtrl::GetItemCount();

			// colonne della riga
			for(nSubItem = 0,nCurrentItem = 0; nSubItem < m_nTotColumns && nCurrentItem!=LB_ERR; nSubItem++)
			{
				// status della riga (default su non selezionata)
				ra->ico      = nIconIndex;
				ra->menu     = nMenuIndex;
				ra->selected = FALSE;
				ra->index    = nItem;

				// la riga viene passata in un unico buffer, diviso in colonne dal carattere ';'
				lvitem.pszText = (LPSTR)GetItemToken(nSubItem,ra->item);
				
				int nItemSize = CListCtrl::GetStringWidth(lvitem.pszText);
				//int nColSize = CListCtrl::GetColumnWidth(nSubItem);
				if(nItemSize >= CListCtrl::GetColumnWidth(nSubItem))
					CListCtrl::SetColumnWidth(nSubItem,nItemSize+15);

				lvitem.iSubItem = nSubItem;

				if(nSubItem==0)
				{
					lvitem.mask   = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
					lvitem.iItem  = nItem;
					lvitem.iImage = ra->ico; // icona relativa (indice base 0 nell'array delle immagini)
					lvitem.lParam = (LPARAM)(ra->item);
					
					if((nCurrentItem  = CListCtrl::InsertItem(&lvitem)) < 0)
						nCurrentItem = LB_ERR;
				}
				else
				{
					lvitem.mask  = LVIF_TEXT;
					lvitem.iItem = nCurrentItem;
					
					CListCtrl::SetItem(&lvitem);
				}
			}
		}
	}

	return(nCurrentItem);
}

/*
	UpdateItem()

	Aggiorna l'elemento del controllo.
*/
BOOL CListCtrlEx::UpdateItem(int nItem,LPCSTR lpcszItemText,int nIconIndex/*=0*/,int nMenuIndex/*=-1*/)
{
	BOOL bUpdated = FALSE;
	ITERATOR iter;
	CTRL_ROW* ra = NULL;

	// cerca la riga relativa all'indice
	if((iter = m_RowList.First())!=(ITERATOR)NULL)
	{
		while(iter!=(ITERATOR)NULL)
		{
			ra = (CTRL_ROW*)iter->data;
			if(ra)
			{
				if(ra->index==nItem)
					break;
				else
					ra = NULL;
			}
			iter = m_RowList.Next(iter);
		}
	}

	if(ra)
	{
		int nCurrent = GetCurrentItem();
		
		CListCtrl::DeleteItem(nItem);

		if(ra->item)
		{
			delete [] ra->item;
			ra->item = NULL;
		}
		int len = strlen(lpcszItemText)+1;
		ra->item = new char[len];
		memset(ra->item,'\0',len);

⌨️ 快捷键说明

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