Vous devez avoir un compte Developpez.com et être connecté pour pouvoir participer aux discussions.

Identifiez-vous
Identifiant
Mot de passe
Mot de passe oublié ?
Créer un compte

Vous n'avez pas encore de compte Developpez.com ? L'inscription est gratuite et ne vous prendra que quelques instants !

Je m'inscris !

Developpez.com

C++

Choisissez la catégorie, puis la rubrique :

logo
Sommaire > Contrôles > CListCtrl
        Comment initialiser et remplir une CListCtrl ?
        Comment récupérer les informations sur une colonne d'une CListCtrl ?
        Comment détecter le changement de ligne sur une CListCtrl ?
        Comment sélectionner et faire apparaître la dernière ligne d'une CListCtrl ?
        Comment intercepter le message de sélection dans une CListCtrl ?
        Comment retrouver le nombre de colonnes d'une CListCtrl ?
        Comment mettre une case à cocher dans une CListCtrl ?
        Comment cocher/décocher une case à cocher dans une CListCtrl ?
        Comment récupérer l'état d'une case à cocher dans une CListCtrl ?
        Comment récupérer la notification de changement d'état pour une case à cocher dans une CListCtrl ?
        Comment empêcher le changement de taille d'une colonne dans une CListCtrl ?
        Comment mettre en surbrillance la ligne entière d'une CListCtrl ?
        Comment changer les couleurs dans une CListCtrl ?
        Comment personnaliser l'affichage d'une CListCtrl ?
        Comment personnaliser l'entête d'une CListView ou CListCtrl ?
        Comment ne pas afficher d'image sur la première colonne d'une ClistCtrl ?
        Comment récupérer les informations d'une ligne pour les différents clics souris dans une CListCtrl ?
        Comment afficher des icônes dans les subitems en mode 'report' dans un CListCtrl
        Comment intercepter les messages du clavier dans une CListCtrl ?
        Comment désélectionner une ligne d'une CListCtrl ?
        Comment intercepter les messages du clavier dans une CListCtrl ?
        Comment déplacer une ligne dans une CListCtrl ?
        Comment récupérer l'index de la première ligne sélectionnée d'une CListCtrl ?
        Comment redimensionner une CListCtrl et ses colonnes ?



Comment initialiser et remplir une CListCtrl ?
Créé le 20/05/2006[haut]
auteur : Farscape
L'exemple ci-dessous montre comme créer un entête de cinq colonnes centrées à gauche, avec une taille initiale de 70 pixels.
On commence par insérer la ligne puis on met à jour les colonnes.
Pour montrer les différentes possibilités une ligne sur deux est sélectionnée, ainsi que le type LVS_EX_FULLROWSELECT permettant d'avoir une ligne de sélection non limitée à la première colonne.

void CSdiSplitterView::OnInitialUpdate()
{
    CListView::OnInitialUpdate();
    
    CListCtrl& theCtrl = GetListCtrl();
    
    // TODO: You may populate your ListView with items by directly accessing
    //  its list control through a call to GetListCtrl().
    CString strText;
    for(int nc=0;nc<5;nc++)
    {
        strText.Format(TEXT("ColHeader%d"),nc);
        theCtrl.InsertColumn(nc,strText,LVCFMT_LEFT,70);
    }
    // force le mode report ,
    //inutile si fixé dans les ressources dans le cas d'un controle CListCtrl.
    theCtrl.ModifyStyle(0,LVS_REPORT); 
    // style etendu voir MSDN pour les autres styles possibles.
    theCtrl.SetExtendedStyle(theCtrl.GetExtendedStyle() | LVS_EX_FULLROWSELECT );
    
    static_cast<CMainFrame *>(AfxGetMainWnd())->m_wndSplitter.SetColumnInfo(0,5*70,100);
    
    for (int i=0;i < 10;i++)
    {
        strText.Format(TEXT("item %d"), i);
        
        // Insert the item, select every other item.
        theCtrl.InsertItem(LVIF_TEXT|LVIF_STATE, i, strText,(i%2)==0?LVIS_SELECTED : 0, LVIS_SELECTED,0, 0);
        
        // Initialize the text of the subitems.
        for (int j=1;j<theCtrl.GetHeaderCtrl()->GetItemCount();j++)
        {
            strText.Format(TEXT("Sub-Item %d %d"), i, j);
            theCtrl.SetItemText(i, j, strText);
        }
    }
}
Note : l'exemple ci-dessous s'applique à une CListView ,dans le cas d'utilisation directe d'un CListCtrl la variable theCtrl sera remplacée par la variable contrôle lié au contrôle présent dans les ressources.

Exemple : http://farscape.developpez.com/Samples/SdiSplitter.zip


Comment récupérer les informations sur une colonne d'une CListCtrl ?
Créé le 20/05/2006[haut]
auteur : Farscape
En mode report la CListCtrl ou la CListView possède une têtière qui dépend de la classe CHeaderCtrl.
Pour récupérer les informations d'une colonne du HeaderCtrl on procédera comme suit :

Avec une CListCtrl :

TCHAR szText[255];
HDITEM hdi;
hdi.mask = HDI_WIDTH|HDI_FORMAT|HDI_TEXT|HDI_IMAGE|HDI_BITMAP;
hdi.pszText = szText;
hdi.cchTextMax = sizeof(szText);
VERIFY(MyListCtrl.GetHeaderCtrl()->GetItem(iPos, &hdi));
La fonction GetItem charge la structure HDITEM en fonction du contenu du mask.
Pour l'exemple j'ai choisi de tout demander.
Dans le cas du libellé il faut fournir l'adresse d'une chaîne de caractères valide comme dans l'exemple.

Avec une CListView :


TCHAR szText[255];
HDITEM hdi;
hdi.mask = HDI_WIDTH|HDI_FORMAT|HDI_TEXT|HDI_IMAGE|HDI_BITMAP;
hdi.pszText = szText;
hdi.cchTextMax = sizeof(szText);
CListCtrl& theCtrl = GetListCtrl(); 

VERIFY(theCtrl.GetHeaderCtrl()->GetItem(iPos, &hdi));

Comment détecter le changement de ligne sur une CListCtrl ?
auteur : Farscape
En interceptant avec ClassWizard l'événement LVN_ITEMCHANGED ,complété du test qui suit dans l'exemple.

BEGIN_MESSAGE_MAP(CTestMDIView, CFormView)
//{{AFX_MSG_MAP(CTestMDIView)
ON_NOTIFY(LVN_ITEMCHANGED, IDC_LISTCTRL, OnItemchangedListctrl)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CTestMdiView::OnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult) 
{
      NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
      // TODO: Add your control notification handler code here         

    if(pNMListView->iItem>=0 && (pNMListView->uNewState & LVIS_SELECTED))
    {
            // affichage de l'id et du texte colonne 0
           TRACE("\nItem:%d:%s",pNMListView->iItem,
            (const char *)m_ListCtrl.GetItemText(pNMListView->iItem,0));
    }
*pResult = 0;
} 

Comment sélectionner et faire apparaître la dernière ligne d'une CListCtrl ?
Mise à jour le 12/02/2006[haut]
auteur : Farscape
Exemple de sélection et de scroll éventuel sur la dernière ligne d'une CListCtrl:

int nCount = pMyListCtrl->GetItemCount(); // nombre d'elements 
if (nCount > 0)
{
   //pour la sélection
   pMyListCtrl->SetItemState(nCount-1, LVIS_SELECTED, LVIS_SELECTED); 

   // pour faire apparaître la ligne au besoin par un scroll
   pMyListCtrl->EnsureVisible(nCount-1, FALSE); 
}

Comment intercepter le message de sélection dans une CListCtrl ?
auteur : Farscape
A partir de ClassWizard sélectionner l'identifiant de la CListCtrl ,
Générer la fonction en réponse au message NM_CLICK .
On obtiendra les informations de sélection en castant le pointeur pNMHDR en pointeur sur la structure NMITEMACTIVATE.

BEGIN_MESSAGE_MAP(CTestMdiView, CFormView)
//{{AFX_MSG_MAP(CTestMdiView)
ON_NOTIFY(NM_CLICK, IDC_LIST, OnClickList)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

void CTestMdiView::OnClickList(NMHDR* pNMHDR, LRESULT* pResult) 
{
    // TODO: Add your control notification handler code here
    NMITEMACTIVATE *pItem=(NMITEMACTIVATE *)pNMHDR;

    TRACE("\n iItem:%d iSubItem:%d",pItem->iItem,pItem->iSubItem);
   *pResult = 0;
}

Comment retrouver le nombre de colonnes d'une CListCtrl ?
auteur : Farscape
Une ClistCtrl utilise un CHeaderCtrl pour la gestion de l'entête.
Pour retrouver le nombre de colonnes il suffit de faire :

int nColHeader=m_ListCtrl.GetHeaderCtrl()->GetItemCount() ;

Comment mettre une case à cocher dans une CListCtrl ?
auteur : Farscape
Il suffit de spécifier le style LVS_EX_CHECKBOXES

m_ListCtrl.SetExtendedStyle(m_ListCtrl.GetExtendedStyle() | LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);

Comment cocher/décocher une case à cocher dans une CListCtrl ?
auteur : Farscape

void SetLstCtrlCheck (CListCtrl &rListCtrl,WPARAM nItemIndex, BOOL bCheck)
{
     ListView_SetCheckState(rListCtrl. GetSafeHwnd( ), nItemIndex, bCheck);
/* ou 
    ListView_SetItemState (rListCtrl. GetSafeHwnd( ), nItemIndex, 
    UINT((int(bCheck) + 1) << 12), LVIS_STATEIMAGEMASK);  */
}

Comment récupérer l'état d'une case à cocher dans une CListCtrl ?
auteur : Farscape

BOOL GetLstCtrlCheck (CListCtrl &rListCtrl,WPARAM nItemIndex)
{    
    return (ListView_GetCheckState(rListCtrl. GetSafeHwnd( ), nItemIndex)); 
}

Comment récupérer la notification de changement d'état pour une case à cocher dans une CListCtrl ?
auteur : Farscape
Il faut récupérer la notification de message LVN_ITEMCHANGED sur la ListCtrl :

BEGIN_MESSAGE_MAP(CTestMdiView, CFormView)
//{{AFX_MSG_MAP(CTestMdiView)
ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST1, OnItemchangedList)
END_MESSAGE_MAP()

void CTestMdiView::OnItemchangedList(NMHDR* pNMHDR, LRESULT* pResult) 
{
NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
// TODO: Add your control notification handler code here         

    *pResult = 0;

    if (!pNMListView->uOldState && !pNMListView->uNewState) return;    // pas de changement

    // ancien etat de la check
    BOOL bPrevState=(BOOL)(((pNMListView->uOldState & LVIS_STATEIMAGEMASK)>>12)-1);  
    if(bPrevState<0) bPrevState = 0;  // au depart pas d'ancien etat on met false (unchecked)
        
    // nouvel etat.
    BOOL bChecked =(BOOL)(((pNMListView->uNewState & LVIS_STATEIMAGEMASK)>>12)-1); 
    if(bChecked<0) bChecked = 0; 

    if (bPrevState==bChecked) return;  

    // votre code ici !!!!
}
voir MSDN pour le shift right qui permet de récupérer la valeur de l'état de l'item.


Comment empêcher le changement de taille d'une colonne dans une CListCtrl ?
Mise à jour le 07/07/2008[haut]
auteur : Farscape
Il faut définir une classe dérivée de CListCtrl, intercepter le message WM_NOTIFY et procéder au test suivant :

CMyListCtrl::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT *pResult)
{
    HD_NOTIFY *pHDN = reinterpret_cast<HD_NOTIFY*> (lParam);

    if    (
            (
            (pHDN->hdr.code == HDN_BEGINTRACKA) ||
            (pHDN->hdr.code == HDN_BEGINTRACKW) ||
            (pHDN->hdr.code == HDN_DIVIDERDBLCLICKA) ||
            (pHDN->hdr.code == HDN_DIVIDERDBLCLICKW)
            ) &&
        (pHDN->iItem == 2)  // Redimensionnement interdit sur la colonne 2.
        )
    {
        *pResult = TRUE;
        return TRUE;
    }

    return CListCtrl::OnNotify(wParam, lParam, pResult);
}

Comment mettre en surbrillance la ligne entière d'une CListCtrl ?
auteur : Farscape
Par défaut la sélection sur une CListCtrl se fait uniquement sur la première colonne.
Pour que la sélection soit active sur toute la ligne procéder comme suit :

m_ListCtrl.SetExtendedStyle(m_ListCtrl.GetExtendedStyle() | LVS_EX_FULLROWSELECT);

Comment changer les couleurs dans une CListCtrl ?
auteur : Farscape
Changement de la couleur de fond :

m_MyListControl.SetBkColor(RGB(202,202,255));


Changement de la couleur d'écriture :

m_MyListControl.SetTextColor(RGB(120,120,120));


Changement de la couleur de fond du texte :

m_MyListControl.SetTextBkColor(RGB(202,202,255));

Comment personnaliser l'affichage d'une CListCtrl ?
Créé le 20/05/2006[haut]
auteur : Farscape
Il faudra passer par une classe héritée du contrôle de base CListCtrl et redéfinir la fonction OnDrawItem pour le dessin des lignes.

Exemple d'implémentation:

#if !defined(AFX_LISTCTRLEX_H__BB73C7E9_F905_4D3A_A0B7_AB9515DA9DA1__INCLUDED_)
#define AFX_LISTCTRLEX_H__BB73C7E9_F905_4D3A_A0B7_AB9515DA9DA1__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// ListCtrlEx.h : header file
//
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx window

class CListCtrlEx : public CListCtrl
{
    // Construction
public:
    CListCtrlEx();
    
    // Attributes
private:
    COLORREF m_cBkColor[3];
    COLORREF m_cTxtColor[3];
    
    // Operations
public:
    
    // Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CListCtrlEx)
    
    //}}AFX_VIRTUAL
    virtual voidDrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
    // couleur ligne Pair/impair
    void SetLineColor(COLORREF Bkclr,COLORREF TxtColor,bool bLinePair=true)
    {
        m_cBkColor[!bLinePair]=Bkclr;
        m_cTxtColor[!bLinePair]=TxtColor;
    }
    // couleur bandeau de selection.
    void SetSelColor(COLORREF Bkclr,COLORREF TxtColor)
    {
        m_cBkColor[2]=Bkclr;
        m_cTxtColor[2]=TxtColor;
    }
    // Implementation
public:
    virtual ~CListCtrlEx();
    
    // Generated message map functions
protected:
    //{{AFX_MSG(CListCtrlEx)
    //}}AFX_MSG
    
    DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_LISTCTRLEX_H__BB73C7E9_F905_4D3A_A0B7_AB9515DA9DA1__INCLUDED_)
le .cpp

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx
CListCtrlEx::CListCtrlEx()
{
    m_cBkColor[0]=m_cBkColor[1]=RGB(255, 255, 255);
    m_cTxtColor[0]=m_cTxtColor[1]=RGB(0, 0, 0);
    m_cBkColor[2]=RGB(0  ,0  ,255);
    m_cTxtColor[2]=RGB(255,255,0);
}
CListCtrlEx::~CListCtrlEx()
{
}
BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
//{{AFX_MSG_MAP(CListCtrlEx)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx message handlers
void CListCtrlEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    // TODO: Add your message handler code here and/or call default
    if(lpDrawItemStruct == NULL) return; 
    
    CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
    int nSavedDC = pDC->SaveDC();
    
    RECT r;
    CRect rItem( lpDrawItemStruct->rcItem );
    CBrush* pBrush;
    
    r.left = lpDrawItemStruct->rcItem.left;
    r.right = lpDrawItemStruct->rcItem.right;
    r.top = lpDrawItemStruct->rcItem.top;
    r.bottom = lpDrawItemStruct->rcItem.bottom;
    CRect rect(r);
    
    int item = lpDrawItemStruct->itemID;
    
    BOOL sel =
        (
        (/*(lpDrawItemStruct->itemAction & ODA_FOCUS) &&*/ (lpDrawItemStruct->itemState & ODS_FOCUS)) ||
        ( (lpDrawItemStruct->itemState & ODS_SELECTED))
        );
    if( sel )
    {
        CBrush brush( m_cBkColor[2]); // bleue
        pBrush = pDC->SelectObject( &brush );
        
        pDC->FillRect(&rect, &brush);
        pDC->SetTextColor(m_cTxtColor[2]); // jaune
        pDC->SetBkColor(m_cBkColor[2] ); // bleue
        
        pDC->SelectObject( pBrush );
    }
    else
    {
        //?RGB(0  ,255,0):RGB(128,128,0)
        CBrush brush(m_cBkColor[(item %2)!=0]);
        pBrush = pDC->SelectObject( &brush );
        pDC->FillRect(&rect, &brush);
        
        // RGB(0  ,0  ,0)
        pDC->SetTextColor(m_cTxtColor[(item %2)!=0]);
        pDC->SetBkColor( m_cBkColor[(item %2)!=0]);
        
        pDC->SelectObject( pBrush );
    }
    CString s;
    int nNoColumn, WidthColumn;
    char *p=0;
    int nNbColumns = GetHeaderCtrl()->GetItemCount();
    int ncx=0;
    LV_COLUMN lvc;
    char szItem[255];
    LVITEM  LvItem;
    CImageList *pImgList=GetImageList(LVSIL_NORMAL);
    if(!pImgList)pImgList=GetImageList(LVSIL_SMALL);
    
    bool bImage=(pImgList && pImgList->m_hImageList!=NULL);
    IMAGEINFO info;
    CRect SizeImg(0,0,0,0);
    if(bImage)
    {
        pImgList->GetImageInfo(0,&info);
        SizeImg=CRect(info.rcImage);
    }
    for( nNoColumn = 0; nNoColumn < nNbColumns ; nNoColumn++ )
    {        
        WidthColumn = GetColumnWidth( nNoColumn );
        lvc.mask = LVCF_FMT;        
        if( GetColumn( nNoColumn, &lvc ) ==0 ) continue;
        
        LvItem.mask=LVIF_TEXT |LVIF_IMAGE;
        LvItem.cchTextMax=sizeof(szItem);
        LvItem.pszText=szItem;
        LvItem.iItem=item;
        LvItem.iSubItem=nNoColumn;
        LvItem.iImage=0;
        
        GetItem( &LvItem );
        
        s=LvItem.pszText;
        CRect rZone=r;
        if(bImage && LvItem.iImage!=-1) 
        {
            rZone.left+=SizeImg.Width();
            pImgList->Draw(pDC,LvItem.iImage,CPoint(r.left,r.top),ILD_NORMAL);
        }
        if( lvc.fmt & LVCFMT_RIGHT )
        {
            pDC->SetTextAlign( TA_RIGHT );
            s += ' ';
            pDC->ExtTextOut( r.left + WidthColumn , r.top, ETO_OPAQUE|ETO_CLIPPED, &rZone, s, NULL );
        }
        else
        {
            pDC->SetTextAlign( TA_LEFT );
            s = ' ' + s;
            pDC->ExtTextOut( rZone.left ,r.top, ETO_OPAQUE|ETO_CLIPPED, &rZone, s, NULL );
        }
        r.left += WidthColumn;
    }
    pDC->RestoreDC( nSavedDC );
    if( lpDrawItemStruct->itemState & ODS_SELECTED )
        pDC->DrawFocusRect( &lpDrawItemStruct->rcItem );
}
Cette classe permet de paramétrer la couleur des lignes pairs/impairs ainsi que la couleur du bandeau de sélection.

Note:Le contrôle devra avoir l'option owner draw fixed cochée dans les ressources.


Comment personnaliser l'entête d'une CListView ou CListCtrl ?
Créé le 20/05/2006[haut]
auteur : Farscape
En mode report une têtière apparaît en haut du contrôle avec le nom des colonnes.
Ce composant de la classe CHeaderCtrl ne permet pas de personnalisation d'apparence.
Dans ce contexte comme faire pour le personnaliser ? , Hé bien il va falloir le subclasser et prendre en charge son dessin.
La première étape sera donc de fournir un composant dérivé de la classe CHeaderCtrl :

la définition:

/////////////////////////////////////////////////////////////////////////////
// CHeaderCtrlEx window

class CHeaderCtrlEx : public CHeaderCtrl
{
    // Construction
public:
    CHeaderCtrlEx();
    
    // Attributes
public:
    int m_iIndex,
        m_iHotIndex ;
    
    COLORREF m_Bkclr,m_BkclrInsSel;
    COLORREF m_Txtclr,m_TxtclrInsSel;
    CFont *m_pFont;
    
    // Operations
public:
    
    // Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CHeaderCtrlEx)
    //}}AFX_VIRTUAL
    
    // Implementation
public:
    virtual ~CHeaderCtrlEx();
    voidDrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
    
    void SetBackGround(COLORREF clr,COLORREF clrInSel);
    void SetTextColor (COLORREF clr,COLORREF clrInSel);
    void SetHeaderFont(CFont &rFont);
    
    // Generated message map functions
protected:
    //{{AFX_MSG(CHeaderCtrlEx)
    afx_msg void OnPaint();
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg UINT OnNcHitTest(CPoint point);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    //}}AFX_MSG
    
    DECLARE_MESSAGE_MAP()
};
Le code:

/////////////////////////////////////////////////////////////////////////////
// CHeaderCtrlEx
CHeaderCtrlEx::CHeaderCtrlEx()
{
    m_iIndex=-1;
    m_pFont=NULL;
    m_Bkclr=::GetSysColor(COLOR_BTNFACE);
    m_BkclrInsSel=RGB(0,0,0);
    m_Txtclr=RGB(0,0,0);
    m_TxtclrInsSel=RGB(255,255,255);
    
}
//------------------------------------------------------
CHeaderCtrlEx::~CHeaderCtrlEx()
{
}
//------------------------------------------------------
void CHeaderCtrlEx::SetBackGround(COLORREF clr,COLORREF clrInSel)
{
    // 
    m_Bkclr=clr;
    m_BkclrInsSel=clrInSel;
    if(m_hWnd) Invalidate();
}
//------------------------------------------------------
void CHeaderCtrlEx::SetTextColor(COLORREF clr,COLORREF clrInSel)
{
    // 
    m_Txtclr=clr;
    m_TxtclrInsSel=clrInSel;
    if(m_hWnd) Invalidate();
}
//------------------------------------------------------
void CHeaderCtrlEx::SetHeaderFont(CFont &rFont)
{
    // 
    m_pFont=&rFont;
    if(m_hWnd) Invalidate();
}

BEGIN_MESSAGE_MAP(CHeaderCtrlEx, CHeaderCtrl)
//{{AFX_MSG_MAP(CHeaderCtrlEx)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
ON_WM_NCHITTEST()
ON_WM_LBUTTONUP()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CHeaderCtrlEx message handlers
void CHeaderCtrlEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    
}
//--------------------------------------------------------------
void CHeaderCtrlEx::OnPaint() 
{
    CPaintDC dc(this); // device context for painting
    
    // TODO: Add your message handler code here
    
    // Do not call CHeaderCtrl::OnPaint() for painting messages
    int nItems = GetItemCount();
    CRect rect,rectItem;
    
    
    CBrush brBackGrnd(m_Bkclr);
    CPen PenWith(PS_SOLID ,1,RGB(255,255,255));
    
    CBrush brBackGrndSel(m_BkclrInsSel);
    CPen PenBackGrnd(PS_SOLID ,1,m_Bkclr);
    
    for(int i = 0; i <nItems; i++)
    {
        
        TCHAR buf1[256];
        HD_ITEM hditem1;
        
        hditem1.mask = HDI_TEXT | HDI_FORMAT | HDI_ORDER;
        hditem1.pszText = buf1;
        hditem1.cchTextMax = 255;
        GetItem( i, &hditem1 );
        
        GetItemRect(i, &rect);
        
        CPen PenBorder(PS_SOLID ,1,RGB(172,168,153));
        
        bool bPush=(m_iIndex>=0 && m_iIndex==i);
        CRect rFond=rect;
        rFond.top+=2;
        rFond.bottom-=1;
        rFond.left+=1;
        rFond.right-=1;
        
        dc.FillRect(&rFond,(bPush?&brBackGrndSel:&brBackGrnd));
        
        CPen* pOldPen=dc.SelectObject(&PenBackGrnd);
        dc.MoveTo(rect.right-1,rect.top+2);
        dc.LineTo(rect.right-1,rect.bottom-1);
        
        dc.MoveTo(rect.left,rect.top+2);
        dc.LineTo(rect.left,rect.bottom-1);
        
        dc.SelectObject(pOldPen);
        
        pOldPen=dc.SelectObject(&PenBorder);
        dc.MoveTo(rect.left,rect.top);
        dc.LineTo(rect.right,rect.top);
        
        dc.MoveTo(rect.left,rect.bottom);
        dc.LineTo(rect.right,rect.bottom);
        
        dc.MoveTo(rect.right-1,rect.top+3);
        dc.LineTo(rect.right-1,rect.bottom-2);
        
        dc.SelectObject(pOldPen);
        
        pOldPen=dc.SelectObject(&PenWith);
        dc.MoveTo(rect.left,rect.top+1);
        dc.LineTo(rect.right,rect.top+1);
        
        dc.MoveTo(rect.left,rect.top+3);
        dc.LineTo(rect.left,rect.bottom-2);
        
        dc.SelectObject(pOldPen);
        
        
        /*
        UINT utype=DFCS_BUTTONPUSH;
        if(m_iIndex>=0 && m_iIndex==i)utype|=DFCS_PUSHED;
        dc.DrawFrameControl(rect,DFC_BUTTON,utype);
        */
        
        DRAWITEMSTRUCTDrawItemStruct;
        GetItemRect(i, &rectItem);
        
        
        DrawItemStruct.CtlType= 100;
        DrawItemStruct.hDC= dc.GetSafeHdc();
        DrawItemStruct.itemAction= ODA_DRAWENTIRE; 
        DrawItemStruct.hwndItem = GetSafeHwnd(); 
        DrawItemStruct.rcItem= rectItem;
        DrawItemStruct.itemID= i;
        DrawItem(&DrawItemStruct);
        
        UINT uFormat = DT_SINGLELINE | DT_NOPREFIX | DT_TOP |DT_CENTER | DT_END_ELLIPSIS ;
        
        
        CFont font,*pCurrentFont;
        pCurrentFont=&font;
        if(m_pFont) pCurrentFont=m_pFont;
        else
        {
            LOGFONT lf;
            memset(&lf, 0, sizeof(LOGFONT));
            lf.lfHeight = 13;
            strcpy(lf.lfFaceName, "Sevenet 7");
            font.CreateFontIndirect(&lf);
        }
        CFont* pOldFont = dc.SelectObject(pCurrentFont);
        
        dc.SetBkMode(TRANSPARENT);
        rectItem.DeflateRect(2,2,2,2);
        
        dc.SetTextColor(bPush?m_TxtclrInsSel:m_Txtclr);
        
        TCHAR buf[256];
        HD_ITEM hditem;
        
        hditem.mask = HDI_TEXT | HDI_FORMAT | HDI_ORDER;
        hditem.pszText = buf;
        hditem.cchTextMax = 255;
        GetItem( DrawItemStruct.itemID, &hditem );
        
        dc.DrawText(buf, &rectItem, uFormat);
        dc.SelectObject(pOldFont);
}
}
//--------------------------------------------------------------
void CHeaderCtrlEx::OnLButtonDown(UINT nFlags, CPoint point) 
{
    // TODO: Add your message handler code here and/or call default
    UINT    m_nClickFlags = nFlags;
    CPoint  m_ptClickPoint = point;
    
    if(m_iIndex==-1 && m_iHotIndex>=0) 
    {
        CRect rect;
        m_iIndex=m_iHotIndex;
        GetItemRect(m_iIndex, &rect);
        InvalidateRect(rect);
    }
    CHeaderCtrl::OnLButtonDown(nFlags, point);
}
//--------------------------------------------------------------
UINT CHeaderCtrlEx::OnNcHitTest(CPoint point) 
{
    // TODO: Add your message handler code here and/or call default
    HDHITTESTINFO hdhtiHotItem;
    
    hdhtiHotItem.pt = point;
    ScreenToClient(&hdhtiHotItem.pt);
    
    m_iHotIndex = SendMessage(HDM_HITTEST, 0, (LPARAM)(&hdhtiHotItem));
    if(m_iHotIndex >= 0)
    {
        HDITEM hditem;
        hditem.mask = HDI_ORDER;
        VERIFY(GetItem(m_iHotIndex, &hditem));
    }
    
    return CHeaderCtrl::OnNcHitTest(point);
}
//--------------------------------------------------------------
void CHeaderCtrlEx::OnLButtonUp(UINT nFlags, CPoint point) 
{
    // TODO: Add your message handler code here and/or call default
    
    if(m_iIndex >=0)
    {
        CRect rect;
        GetItemRect(m_iIndex, &rect);
        m_iIndex =-1;
        InvalidateRect(rect);
    }
    CHeaderCtrl::OnLButtonUp(nFlags, point);
}
Dans la fonction je procède au dessin de toutes les colonnes avec une fonte spécifique et une couleur d'écriture bleue.
La simulation du clic sur la colonne est gérée par les fonctions :
OnLButtonUp,OnNcHitTest,OnLButtonDown..

Il faut maintenant indiquer à la CListView ou au CListCtrl de travailler avec ce nouveau composant en subclassant le précédent.

Pour une CListView :

void CCustomListView::OnInitialUpdate()
{
    CListView::OnInitialUpdate();
    
    // TODO: You may populate your ListView with items by directly accessing
    //  its list control through a call to GetListCtrl().
    CListCtrl& theCtrl = GetListCtrl();
    
    // m_HeaderCtrl va prendre le relai sur le composant par defaut.
    m_HeaderCtrl.SubclassWindow(theCtrl.GetHeaderCtrl()->m_hWnd);
    //?
Pour un CListCtrl :

void CCustomListCtrl::PreSubclassWindow() 
{
    // TODO: Add your specialized code here and/or call the base class
    m_HeaderCtrl.SubclassWindow(GetHeaderCtrl()->m_hWnd);
    CListCtrl::PreSubclassWindow();
}
Voila le mécanisme de base est en place pour implémenter d'autres effets ou fonctions pour faciliter la personnalisation du composant.

Le projet de test : http://farscape.developpez.com/Samples/CustomListview.zip


Comment ne pas afficher d'image sur la première colonne d'une ClistCtrl ?
Créé le 20/05/2006[haut]
auteur : Farscape
Pour pouvoir afficher des images sur toutes les colonnes d'une ClistCtrl il faudra modifier son style .
faq Comment afficher des icônes dans les subitems en mode 'report' dans un CListCtrl
Pour ne pas afficher d'image sur la première colonne on procédera comme suit :

On indiquera -1 pour l'indice de l'image.

m_listctrl.InsertItem(LVIF_TEXT|LVIF_STATE|LVIF_IMAGE, i, strText,0, 0,-1, 0);
Inconvénient la ClistCtrl ne tient pas compte de la non présence de l'image et réserve une place vide en lieu et place.
Pour remédier à ce problème il faudra faire sa propre classe dérivée et gérer le cas sur le dessin de la ligne dans la fonction OnDrawItem.
Ce sujet est traité dans la classe proposée dans faq Comment personnaliser l'affichage d'une CListCtrl ?


Comment récupérer les informations d'une ligne pour les différents clics souris dans une CListCtrl ?
Créé le 04/04/2005[haut]
auteur : Farscape
Pour récupérer les informations sur la ligne et la colonne sélectionnée pour les messages suivants :
NM_DBLCLK
NM_CLICK
NM_RCLICK
NM_RDBLCLK
On procédera comme suit :

void CSdiSplitterView::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult) 
{
    // TODO: Add your control notification handler code here
    NMITEMACTIVATE*pActive=(NMITEMACTIVATE *)pNMHDR;
    TRACE("item:%d subitem:%d",pActive->iItem,pActive->iSubItem);
   *pResult = 0;
}

Comment afficher des icônes dans les subitems en mode "report" dans un CListCtrl
Créé le 19/09/2005[haut]
auteur : tut
Ca se fait en deux étapes :
1 - Il faut d'abord associer une liste d'images à votre contrôle :

         m_ImageListSmall = new CImageList();
         if ( m_ImageListSmall->Create(16,16,ILC_COLOR32|ILC_MASK,3,3) )
         {         
            m_ImageListSmall->Add(pApp->LoadIcon(IDI_NOK));         
            m_ImageListSmall->Add(pApp->LoadIcon(IDI_OK));         
            m_ImageListSmall->Add(pApp->LoadIcon(IDI_UNDEFINED));
            m_list.SetImageList(m_ImageListSmall,LVSIL_SMALL);
         }
Ensuite, il faut mettre le style étendu de la liste dans l'init de votre contrôle.

// Set the extended style      
m_list.SetExtendedStyle(LVS_EX_SUBITEMIMAGES);
Ensuite, mettre tout ça dans le OnInitDialog() de la classe qui contient le CListCtrl.

2 - Maintenant que le contrôle est prêt, on peut lui demander d'afficher une icône sur les subitems :

m_list.SetItem(IndexItem, IndexSubItem, LVIF_IMAGE, 0, IndexIcon, 0,0,0);
Ceci va afficher l'icône d'index IndexIcon dans la liste, sur l'item d'index IndexItem, sur le subitem d'index IndexSubItem.


Comment intercepter les messages du clavier dans une CListCtrl ?
Créé le 20/05/2006[haut]
auteur : Farscape
Il suffit d'intercepter le message LVN_KEYDOWN sur la CListCtrl, on obtiendra la fonction suivante :

void CTestSDIView::OnKeydownListCtrl(NMHDR* pNMHDR, LRESULT* pResult) 
{ 
   LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR; 
   // TODO: Add your control notification handler code here 
   TRACE ("\nTouche :%d",pLVKeyDow->wVKey); 
   *pResult = 0; 
}
Le code de la touche est stocké dans la variable wVkey de la structure LV_KEYDOWN.
La variable presult permet de notifier si la touche doit être prise en compte par la CListCtrl .
si *presult=0 la ListCtrl traitera normalement le message clavier
si *presult=1 la ListCtrl ignorera le message clavier.


Comment désélectionner une ligne d'une CListCtrl ?
Créé le 20/05/2006[haut]
auteur : Farscape
En appelant la fonction SetItemState :

CListCtrl::SetItemState
BOOL SetItemState( 
int nItem, 
UINT nState, 
UINT nMask );
Exemple:

m_listCtrl.SetItemState(iItem, 
               0,              // nState 
               LVIS_SELECTED); // nMask
iItem représente l'index de la ligne dans la CListCtrl.


Comment intercepter les messages du clavier dans une CListCtrl ?
Créé le 22/01/2007[haut]
auteur : Farscape
Il suffit d'intercepter le message LVN_KEYDOWN sur la CListCtrl, on obtiendra la fonction suivante :

void CTestSDIView::OnKeydownListCtrl(NMHDR* pNMHDR, LRESULT* pResult) 
{ 
   LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR; 
   // TODO: Add your control notification handler code here 
   TRACE ("\nTouche :%d",pLVKeyDow->wVKey); 
   *pResult = 0; 
}
Le code de la touche est stocké dans la variable wVkey de la structure LV_KEYDOWN.


Comment déplacer une ligne dans une CListCtrl ?
Créé le 22/01/2007[haut]
auteur : Farscape
Le principe proposé :
On commence par mémoriser les éléments de la ligne en question.
On supprime cette ligne, et on la réinsère à l'offset initial -1 ou +1 suivant le sens de déplacement souhaité.

void MoveListCtrlLig(int nIndex,bool bUp)
{
    // nb de colonne de la listCtrl.
    int nCount = m_MyListCtrl.GetItemCount();
    CStringArray strArray;
    int i=0;
    for (i=0;i < nCount;i++)
    {
       // sauvegarde des éléments dans une CStringArray
       strArray.Add(m_MyListCtrl.GetItemText(nIndex,i));
    }
    // suppression de la ligne
    m_MyListCtrl.DeleteItem(nIndex);
    int nNewIndex=nIndex+(bUp?-1:1);
    // insertion au nouvel emplacement.
    m_MyListCtrl.Insertitem(LVIF_TEXT,nNewIndex , strArray[0],  0, 0,0, 0);
    // insertion des colonnes suivantes
    for (i=1;i <nCount;i++)
        {
           m_MyListCtrl->SetItemText(nNewIndex,i, strArray[i]);
        }
}



Comment récupérer l'index de la première ligne sélectionnée d'une CListCtrl ?
Créé le 22/01/2007[haut]
auteur : Farscape
Pour récupérer la première ligne sélectionnée on procédera comme suit :

int nItem=-1;
POSITION pos = m_MyListCtrl.GetFirstSelectedItemPosition();
if (pos! NULL)  
   nItem= m_MyListCtrl.GetNextSelectedItem(pos);

Note: pour les autres lignes il suffira de poursuive les appels à la fonction GetNextSelectedItem


Comment redimensionner une CListCtrl et ses colonnes ?
Créé le 17/09/2007[haut]
auteur : Farscape
L'exemple typique sera l'adaptation d'un contrôle CListCtrl à la taille de la fenêtre principale, les colonnes devant aussi s'adapter à l'expansion.

Voici comment procéder:
Pour le dimensionnement du contrôle on considèrera qu'il représente x pourcent de la fenêtre.

Pour gérer le dimensionnement dynamique :
Au début du dimensionnement de la fenêtre le message WM_ENTERSIZEMOVE avec wparam==SC_SIZE est envoyé, Il faut alors calculer la taille relative du contrôle dans la fenêtre.
Au niveau du contrôle il faudra mémoriser la taille relative des colonnes par rapport à la CListCtrl.


Ajuster la taille du contrôle :
Deux solutions :
-On peut effectuer le traitement dynamiquement avec le message WM_SIZE.
-Le traitement peut être fait en fin de dimensionnement en interceptant le message WM_EXITSIZEMOVE avec wparam==SC_SIZE.
Dans les deux cas il restera à appliquer les ratios calculés sur le contrôle par rapport à la fenêtre, puis on agira de même pour les colonnes de la CListCtrl.


Note: ces messages devront être implémentés manuellement, ils n'apparaissent pas dans classwizard

Exemple de traitement :

/////////////////////////////////////////////////////////////////////////////
LRESULT CResizeCListCtrlView::OnEnterSizeMove (WPARAM wParam, LPARAM lParam)
{
    // les dimensions sont sauvegardées la premiere fois.
    if(!m_RectInitialWindow.Width())
    {
        // la taille de la fenetre.
        GetClientRect(m_RectInitialWindow);
        // la taill du controle
        m_ListCtrl.GetClientRect(m_RectInitialCtrl);
        ScreenToClient(m_RectInitialCtrl);
        // les colonnes du controle
        HDITEM hdi;
        hdi.mask = HDI_WIDTH;    
        for(int i=0;i<m_ListCtrl.GetHeaderCtrl()->GetItemCount();i++)
        {
            m_ListCtrl.GetHeaderCtrl()->GetItem(i,&hdi);
            m_arWithCol.Add(hdi.cxy);        
        }        
    }    
    return (LRESULT)0;
}
/////////////////////////////////////////////////////////////////////////////
LRESULT CResizeCListCtrlView::OnExitSizeMove (WPARAM wParam, LPARAM lParam)
{

    double dRatiox,dRatioy;

    CRect RectCtrl,RectWindow;
        
    // calcul des ratios pour le controle
    dRatiox=static_cast<double>(m_RectInitialWindow.Width())/static_cast<double>(m_RectInitialCtrl.Width());
    dRatioy=static_cast<double>(m_RectInitialWindow.Height())/static_cast<double>(m_RectInitialCtrl.Height());

    // ratios sur les colonnes.
    HDITEM hdi;
    hdi.mask = HDI_WIDTH;    
    CArray<double,double> arWitdthCol;
    for(int i=0;i<m_arWithCol.GetSize();i++)            
        arWitdthCol.Add(static_cast<double>(m_RectInitialCtrl.Width())/static_cast<double>(m_arWithCol[i]));
    
    
    // apres changement de taille.
    double nx,ny;
    
    GetClientRect(RectWindow);
    nx=static_cast<double>(RectWindow.Width())/dRatiox;
    ny=static_cast<double>(RectWindow.Height())/dRatioy;

    RectCtrl=m_RectInitialCtrl;
    RectCtrl.right=RectCtrl.left+static_cast<int>(nx);
    RectCtrl.bottom=RectCtrl.top+static_cast<int>(ny);

    m_ListCtrl.SetWindowPos(NULL,0,0,RectCtrl.Width(),RectCtrl.Height(),SWP_NOMOVE | SWP_NOZORDER); // uniquement la taille
    
    // dimensionnement des colonnes.
    for(i=0;i<m_ListCtrl.GetHeaderCtrl()->GetItemCount();i++)
    {
        nx=static_cast<double>(RectCtrl.Width())/arWitdthCol[i];
        hdi.cxy=static_cast<int>(nx);
        m_ListCtrl.GetHeaderCtrl()->SetItem(i,&hdi);
    }

    return (LRESULT)0;
}



Consultez les autres F.A.Q.


Valid XHTML 1.0 TransitionalValid CSS!

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2004 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Contacter le responsable de la rubrique C++

Partenaire : Hébergement Web