📄 clistctrlex.cpp
字号:
nCmp = 1;
}
else if(cType=='C')
nCmp = strcmp(s1,s2);
}
else
{
if(cType=='N')
{
n1 = atoi(s1);
n2 = atoi(s2);
if(n2 < n1)
nCmp = -1;
else if(n2 > n1)
nCmp = 1;
}
else if(cType=='C')
nCmp = strcmp(s2,s1);
}
if(++n > 5)
{
n = 0;
::PeekAndPump();
}
return(nCmp);
}
/*
GetItemToken()
Estrae dalla riga l'elemento relativo alla colonna.
Gli elementi, all'interno della riga, devono essere separati dal carattere ';'.
int nItem indice (base 0) dell'elemento
LPCSTR lpcszRow riga contenente gli elementi separati dal carattere ';'
*/
LPCSTR GetItemToken(int nItem,LPCSTR lpcszRow)
{
int i;
LPSTR lpToken;
static char szItem[MAX_CTRLROW_SIZE + 1];
strcpy(szItem,"[null]");
if(lpcszRow && *lpcszRow)
{
strcpyn(szItem,lpcszRow,sizeof(szItem));
for(i = 0,lpToken = strtok(szItem,";"); lpToken!=NULL; i++)
{
if(i==nItem)
{
strcpyn(szItem,lpToken,sizeof(szItem));
break;
}
lpToken = strtok(NULL,";");
}
}
return(szItem);
}
/*
PopUpMenu()
Visualizza il menu popup sul controllo.
Il menu visualizzato e' il primo sottomenu (base 0) del menu relativo all'id nel caso in cui venga
fatto click su un elemento o il secondo se viene fatto click in una zona del controllo senza elementi.
const CPoint& point coordinate del click
*/
void CListCtrlEx::PopUpMenu(const CPoint& point)
{
int i;
CRect rect;
CMenu menu;
CMenu* pSubMenu = NULL;
CTRL_ROW* ra;
// coordinate dell'area client (CWnd, base 0,0)
CWnd::GetClientRect(&rect);
// trasforma le coordinate in assolute (schermo)
// da aggiungere alle coordinate del click del mouse per ottenere le coordinate a cui visualizzare il menu a comparsa
CWnd::ClientToScreen(&rect);
// click su un elemento del controllo
if((i = CListCtrl::HitTest(point)) >= 0)
{
// carica il menu relativo all'id specificato dall'elemento su cui e' stato fatto click
// (primo sottomenu, base 0)
if((ra = GetRowByItem(i))!=(CTRL_ROW*)NULL)
if(ra->menu > 0)
if(menu.LoadMenu(ra->menu))
pSubMenu = menu.GetSubMenu(0);
}
// click fuori dall'elemento
else
{
// click su una zona del controllo contenente almeno un elemento
if((ra = GetRowByItem(0))!=(CTRL_ROW*)NULL)
{
// carica il menu relativo all'id specificato dal primo elemento della lista
// (secondo sottomenu, base 0)
if(ra->menu > 0)
if(menu.LoadMenu(ra->menu))
pSubMenu = menu.GetSubMenu(1);
}
// click su una zona del controllo senza nessun elemento
else
{
// carica il menu di default
// (primo sottomenu, base 0)
if(m_NullRow.menu > 0)
if(menu.LoadMenu(m_NullRow.menu))
pSubMenu = menu.GetSubMenu(0);
}
}
// visualizza il menu popup
if(pSubMenu && m_pWnd)
{
if(m_nMenuMessage!=(UINT)-1)
::SendMessage(m_pWnd->m_hWnd,m_nMenuMessage,(WPARAM)m_nCurrentItem,(LPARAM)pSubMenu);
pSubMenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x+rect.left,point.y+rect.top,m_pWnd);
}
}
/*
Sort()
*/
void CListCtrlEx::Sort(int nCol/* = 0*/)
{
LRESULT lResult = 0L;
NM_LISTVIEW nm_listview;
memset(&nm_listview,'\0',sizeof(NM_LISTVIEW));
nm_listview.iSubItem = nCol;
OnColumnClick((NMHDR*)&nm_listview,&lResult);
}
/*
OnColumnClick()
Gestore per il click sull'header della colonna.
Ordina le righe presenti nella colonna.
*/
void CListCtrlEx::OnColumnClick(NMHDR* pNMHDR,LRESULT* pResult)
{
// verifica che il controllo contenga almeno un elemento
if(CListCtrl::GetItemCount() > 0)
{
NM_LISTVIEW* pNM_LISTVIEW = (NM_LISTVIEW*)pNMHDR;
int nCol = pNM_LISTVIEW->iSubItem;
CTRL_COL* ca = GetColByItem(nCol);
if(ca)
{
// imposta l'ordinamento corrente (ascendente/discendente) in base al precedente
ca->order = (ca->order==FALSE ? TRUE : FALSE);
bAscending = ca->order;
// distingue tra dati numerici e carattere
cType = ca->type;
if(cType!='C' && cType!='N')
cType = 'C';
// ordina le righe della colonna
CListCtrl::SortItems((PFNLVCOMPARE)CompareItems,nCol);
// rinumera l'indice (interno) delle rige secondo l'ordinamento corrente
// notare che l'ordinamento avviene considerando la prima colonna (base 0) della lista
// motivo per cui tale colonna non puo' contenere elementi duplicati: in tal caso il
// confronto (vedi la strcmp() di cui sotto) tra i due elementi selezionerebbe sempre
// il primo e tanti saluti alla rinumerazione dell'indice interno che se ne andrebbe a
// puttane
// il confronto non puo' essere fatto con memcmp() su n caratteri perche' fallirebbe
// nel caso in cui ci siano elementi che iniziano con gli stessi caratteri (ftp e ftp-wpd)
// per cui deve estrarre il testo relativo dal buffer interno (testo;testo;testo;etc.) e
// confrontarlo con quello della riga con strcmp()
ITERATOR iter;
CTRL_ROW* ra = NULL;
LPSTR p;
char szItem[MAX_CTRLITEM_SIZE+1];
char buffer[MAX_CTRLITEM_SIZE+1];
int tot = CListCtrl::GetItemCount();
register int i,n;
// per ogni riga
for(i = 0,n = 0; i < tot; i++)
{
// ricava il testo della riga a colonna 0
if(CListCtrl::GetItemText(i,0,buffer,sizeof(buffer)-1) > 0)
// cerca l'entrata corrispondente (testo;testo;testo;etc.) nella lista interna
if((iter = m_RowList.First())!=(ITERATOR)NULL)
while(iter!=(ITERATOR)NULL)
{
// puntatore alla riga
ra = (CTRL_ROW*)iter->data;
if(ra)
{
// estrae il testo corrispondente alla colonna 0
if((p = strchr(ra->item,';'))!=NULL)
{
int n = p - ra->item;
memcpy(szItem,ra->item,n);
szItem[n] = '\0';
if(strcmp(buffer,szItem)==0)
{
ra->index = i;
break;
}
}
}
iter = m_RowList.Next(iter);
}
if(++n > 5)
{
n = 0;
::PeekAndPump();
}
}
}
}
*pResult = 0;
}
/*
OnLButtonDown()
Gestore per il click con il bottone sinistro del mouse sull'elemento del controllo.
Imposta la riga come selezionata ed invia il messaggio alla finestra principale (in wParam l'indice
dell'elemento selezionato ed in lParam le coordinate del click).
Per catturare il rilascio del bottone sinistro del mouse con OnLButtonUp() anche quando il cursore
del mouse e' stato spostato fuori dall'area client, utilizzare la SetCapture().
*/
void CListCtrlEx::OnLButtonDown(UINT nFlags,CPoint point)
{
// salva le coordinate del click
m_Point.x = point.x;
m_Point.y = point.y;
m_MouseClick.point.x = point.x;
m_MouseClick.point.y = point.y;
m_MouseClick.flags = nFlags;
// chiama il gestore originale
CListCtrl::OnLButtonDown(nFlags,point);
// per continuare a ricevere i messaggi quando il mouse si sposta fuori dell'area client
//::SetCapture(this->m_hWnd);
// indice dell'elemento cliccato
m_nCurrentItem = CListCtrl::HitTest(point);
// imposta il flag relativo alla selezione
// se viene cambiato l'ordinamento del controllo l'elemento relativo all'indice non corrisponde a quanto
// presente nella lista del chiamante, per cui deve cercare l'elemento relativo prima di impostare il
// flag per la selezione
// effettua tale ricerca con il primo subitem (indice 0), per cui il valore presente in tale posizione
// deve essere unico
int nTotItems = CListCtrl::GetItemCount();
if(m_nCurrentItem >= 0 && m_nCurrentItem < nTotItems)
{
CTRL_ROW* ra = NULL;
ITERATOR iter;
register int i;
char buffer[MAX_CTRLITEM_SIZE+1];
// azzera le selezioni correnti
if((iter = m_RowList.First())!=(ITERATOR)NULL)
while(iter!=(ITERATOR)NULL)
{
ra = (CTRL_ROW*)iter->data;
if(ra)
ra->selected = FALSE;
iter = m_RowList.Next(iter);
}
// per ogni elemento del controllo verifica se e' stato selezionato, ricava il valore relativo al
// subitem con indice 0 e lo confronta con l'elemento corrente: se coincidono imposta il flag per
// la selezione
// deve scorrere il controllo per gestire le selezioni multiple (click sul primo, shift+click
// sull'ultimo)
for(i = 0; i < nTotItems/*CListCtrl::GetItemCount()*/; i++)
{
// il cazzo di elemento e' stato cliccato ?
// (click sull'elemento o elemento nel mezzo di una selezione click su i, shift+click su i+n)
if(CListCtrl::GetItemState(i,LVIS_SELECTED) & LVIS_SELECTED)
{
memset(buffer,'\0',sizeof(buffer));
LV_ITEM lvitem;
lvitem.mask = LVIF_TEXT;
lvitem.iItem = i;
lvitem.iSubItem = 0;
lvitem.pszText = buffer;
lvitem.cchTextMax = sizeof(buffer)-1;
CListCtrl::GetItem(&lvitem);
if((ra = GetRowByItem(i))!=(CTRL_ROW*)NULL)
{
if(memcmp(ra->item,buffer,strlen(buffer))==0)
{
ra->selected = TRUE;
break;
}
}
if(!m_bMultipleSelection)
break;
}
}
}
// salva l'indice (base 0) dell'elemento corrente (selezionato), controllando l'intervallo
if(m_nCurrentItem < 0)
m_nCurrentItem = LB_ERR;
else if(m_nCurrentItem >= nTotItems/*CListCtrl::GetItemCount()*/)
m_nCurrentItem = nTotItems/*CListCtrl::GetItemCount()*/ - 1;
// se e' stato specificato un gestore, invia il messaggio relativo
// in wParam l'indice dell'elemento ed in lParam le coordinate del click
if(m_pWnd!=NULL && m_nLButtonDownMessage!=(UINT)-1)
::SendMessage(m_pWnd->m_hWnd,m_nLButtonDownMessage,(WPARAM)m_nCurrentItem,(LPARAM)&m_MouseClick);
}
/*
OnLButtonUp()
Gestore per il rilascio del bottone sinistro del mouse.
Invia il messaggio alla finestra principale (in wParam l'indice dell'elemento su cui e' stato rilasciato
il mouse ed in lParam le coordinate del rilascio).
Vedi le note in OnLButtonDown() a proposito di SetCapture().
*/
void CListCtrlEx::OnLButtonUp(UINT nFlags,CPoint point)
{
// salva le coordinate del click
m_Point.x = point.x;
m_Point.y = point.y;
// chiama il gestore originale
CListCtrl::OnLButtonUp(nFlags,point);
// per terminare di ricevere i messaggi con il mouse fuori dell'area client
//if(::GetCapture()==this->m_hWnd)
// ::ReleaseCapture();
// indice dell'elemento su cui e' stato effettuato il rilascio
int m_nCurrentItem = CListCtrl::HitTest(point);
// se e' stato specificato un gestore, invia il messaggio relativo
// in wParam l'indice dell'elemento ed in lParam le coordinate del rilascio
if(m_pWnd!=NULL && m_nLButtonUpMessage!=(UINT)-1)
::SendMessage(m_pWnd->m_hWnd,m_nLButtonUpMessage,(WPARAM)m_nCurrentItem,(LPARAM)&m_Point);
}
/*
OnRButtonDown()
Gestore per il click con il bottone destro del mouse sull'elemento del controllo.
Visualizza il menu popup ed invia il messaggio alla finestra principale (in wParam
l'indice dell'elemento selezionato ed in lParam le coordinate del click).
*/
void CListCtrlEx::OnRButtonDown(UINT nFlags,CPoint point)
{
// salva le coordinate del click
m_Point.x = point.x;
m_Point.y = point.y;
// chiama il gestore originale
CListCtrl::OnRButtonDown(nFlags,point);
// indice dell'item cliccato
m_nCurrentItem = CListCtrl::HitTest(point);
// a seconda del flag imposta l'item corrente come selezionato
// (per default solo il click con il sinistro imposta l'elemento come selezionato)
if(m_bRightClickSelects)
{
// resetta le selezioni correnti dato la selezione multiple puo' effettuarsi solo con CTRL+click destro
ResetItemsSelection();
// seleziona l'item
SetItemSelection(m_nCurrentItem,TRUE);
}
// visualizza il menu a comparsa
PopUpMenu(point);
// se e' stato specificato un gestore, invia il messaggio relativo
// in wParam l'indice dell'elemento ed in lParam le coordinate del click
if(m_pWnd!=NULL && m_nRButtonDownMessage!=(UINT)-1)
::PostMessage(m_pWnd->m_hWnd,m_nRButtonDownMessage,(WPARAM)m_nCurrentItem,(LPARAM)&m_Point);
}
/*
OnRButtonUp()
Gestore per il rilascio del bottone destro del mouse.
Invia il messaggio alla finestra principale (in wParam l'indice dell'elemento su cui e' stato rilasciato
il mouse ed in lParam le coordinate del rilascio).
*/
void CListCtrlEx::OnRButtonUp(UINT nFlags,CPoint point)
{
// salva le coordinate del click
m_Point.x = point.x;
m_Point.y = point.y;
// chiama il gestore originale
CListCtrl::OnRButtonUp(nFlags,point);
// indice dell'elemento su cui e' stato effettuato il rilascio
int m_nCurrentItem = CListCtrl::HitTest(point);
// se e' stato specificato un gestore, invia il messaggio relativo
// in wParam l'indice dell'elemento ed in lParam le coordinate del rilascio
if(m_pWnd!=NULL && m_nRButtonUpMessage!=(UINT)-1)
::SendMessage(m_pWnd->m_hWnd,m_nRButtonUpMessage,(WPARAM)m_nCurrentItem,(LPARAM)&m_Point);
}
/*
OnLButtonDblClk()
Gestore per il doppio click con il bottone sinistro del mouse sull'elemento del controllo.
Invia il messaggio alla finestra principale (in wParam l'indice dell'elemento selezionato ed in lParam
le coordinate del click).
*/
void CListCtrlEx::OnLButtonDblClk(UINT nFlags,CPoint point)
{
// salva le coordinate del click
m_Point.x = point.x;
m_Point.y = point.y;
// chiama il gestore originale
CListCtrl::OnLButtonDblClk(nFlags,point);
// indice dell'elemento cliccato
m_nCurrentItem = CListCtrl::HitTest(point);
// se e' stato specificato un gestore, invia il messaggio relativo
// in wParam l'indice dell'elemento ed in lParam le coordinate del click
if(m_pWnd!=NULL && m_nLButtonDblClkMessage!=(UINT)-1)
::PostMessage(m_pWnd->m_hWnd,m_nLButtonDblClkMessage,(WPARAM)m_nCurrentItem,(LPARAM)&m_Point);
}
/*
OnRButtonDblClk()
Gestore per il doppio click con il bottone destro del mouse sull'elemento del controlo.
Invia il messaggio alla finestra principale (in wParam l'indice dell'elemento selezionato ed in lParam
le coordinate del click).
*/
void CListCtrlEx::OnRButtonDblClk(UINT nFlags,CPoint point)
{
// salva le coordinate del click
m_Point.x = point.x;
m_Point.y = point.y;
// chiama il gestore originale
CListCtrl::OnRButtonDblClk(nFlags,point);
// indice dell'elemento cliccato
m_nCurrentItem = CListCtrl::HitTest(point);
// se e' stato specificato un gestore, invia il messaggio relativo
// in wParam l'indice dell'elemento ed in lParam le coordinate del click
if(m_pWnd!=NULL && m_nRButtonDblClkMessage!=(UINT)-1)
::PostMessage(m_pWnd->m_hWnd,m_nRButtonDblClkMessage,(WPARAM)m_nCurrentItem,(LPARAM)&m_Point);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -