📄 clistctrlex.cpp
字号:
/*
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 + -