FAQ VC++ et MFCConsultez toutes les FAQ
Nombre d'auteurs : 20, nombre de questions : 545, dernière mise à jour : 5 avril 2013 Ajouter une question
Cette faq a été réalisée pour répondre aux questions les plus fréquement posées sur le forum Développement Visual C++
Je tiens à souligner que cette faq ne garantit en aucun cas que les informations qu'elle contient sont correctes ; Les auteurs font le maximum, mais l'erreur est humaine. Si vous trouvez une erreur, ou si vous souhaitez devenir redacteur, lisez ceci.
Sur ce, je vous souhaite une bonne lecture. Farscape
- Comment activer la sélection multiple dans une CListBox ?
- Comment supprimer la ligne sélectionnée dans une CListbox ?
- Comment supprimer une ligne dans une CListbox ?
- Comment empêcher le tri des données dans une CListBox ?
- Comment sélectionner le dernier élément d'une ClistBox ?
- Comment insérer un élément dans une ClistBox ?
- Comment détruire tous les éléments d'une ClistBox ?
- Comment récupérer le texte d'une ligne dans une CListBox ?
- Comment personnaliser l'affichage des lignes dans une CListBox?
- Comment simuler des colonnes dans une CListBox ?
- Comment implémenter l'ascenseur horizontal sur une CListBox ?
- Comment régler la hauteur des lignes dans une CListBox ?
- Comment activer/désactiver dynamiquement l'ascenseur d'une CListBox ?
- Comment enlever dynamiquement la propriété de tri d'une CListBox.
Sur les propriétés de la CListBox, il suffit de mettre le type de sélection à :extended et les combinaisons de touches ctrl ou maj seront opérationnelles.
En utilisant la fonction GetCurSel qui renvoie l'indice courant sélectionné.
Code c++ : | Sélectionner tout |
1 2 3 | int nIndex = myListBox.GetCurSel(); if((nIndex != LB_ERR)) myListBox.DeleteString( nindex ); |
Si on ne dispose pas du numéro index de la ligne il faudra la rechercher en utilisant la fonction FindString :
Code c++ : | Sélectionner tout |
1 2 3 | CListBox::FindString int FindString( int nStartAfter, LPCTSTR lpszItem ) const; |
Code c++ : | Sélectionner tout |
1 2 3 4 | // ou nIndex = myListBox.FindString(0,"coucou"); if((nIndex != LB_ERR)) myListBox.DeleteString( nindex ); |
Il suffit d'enlever la coche ‘Sort ‘ sur les propriétés de la listbox dans l'éditeur de ressources.
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 | // nombre d'éléments dans la listbox int nCount = MyListBox.GetCount(); // si pas d'erreur listbox non vide , sélection sur l'item nombre d'éléments -1 // puisque les indices commencent à zéro if (nCount > 0) MyListBox.SetCurSel(nCount-1); |
Code c++ : | Sélectionner tout |
1 2 3 | CListBox::AddString int AddString( LPCTSTR lpszItem ); |
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 | CString str; for (int i=0;i < 10;i++) { str.Format(_T("item string %d"), i); MyListBox.AddString( str ); } |
Avec la fonction ResetContent( )
Code c++ : | Sélectionner tout |
1 2 3 4 | // prototype de la méthode: CListBox::ResetContent void ResetContent( ); |
Code c++ : | Sélectionner tout |
1 2 3 4 | // Détruire tous les éléments d'une ClistBox MyListBox.ResetContent(); ASSERT(MyListBox.GetCount() == 0); |
Avec la fonction GetText :
Code c++ : | Sélectionner tout |
1 2 3 4 | CListBox::GetText int GetText( int nIndex, LPTSTR lpszBuffer ) const; void GetText( int nIndex, CString& rString ) const; |
Code c++ : | Sélectionner tout |
1 2 3 4 5 | CStrng str; int nIndex = myListBox.GetCurSel(); if((nIndex != LB_ERR)) myListBox.GetText( nindex,str ); AfxMessageBox(str); |
En utilisant la fonction virtuelle DrawItem
Code c++ : | Sélectionner tout |
1 2 3 | CListBox::DrawItem virtual void DrawItem( LPDRAWITEMSTRUCT lpDrawItemStruct ); |
Il faudra bien sûr créer une classe dérivée de CListBox avec l'aide de ClassWizard et surcharger la fonction DrawItem toujours avec ClassWizard.
Exemple d'implémentation issue de la documentation MSDN :
Affichage du texte centré horizontalement.
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | // CMyListBox is my owner-drawn list box derived from CListBox. This // example draws an item's text centered vertically and horizontally. The // list box control was created with the following code: // pmyListBox->Create( // WS_CHILD|WS_VISIBLE|WS_BORDER|WS_HSCROLL|WS_VSCROLL| // LBS_SORT|LBS_MULTIPLESEL|LBS_OWNERDRAWVARIABLE, // myRect, pParentWnd, 1); // void CMyListBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { // TODO: Add your code to draw the specified item ASSERT(lpDrawItemStruct->CtlType == ODT_LISTBOX); LPCTSTR lpszText=NULL ; CString str; // si le style est <> de LBS_HASSTRINGS on considère que la valeur à afficher //est dans ItemData. if(lpDrawItemStruct->itemID!=CB_ERR && !(GetStyle() & LBS_HASSTRINGS)) lpszText=(LPCTSTR) lpDrawItemStruct->itemData; else { // Récupération de la chaîne grâce à l'index stocké dans ItemID. GetText(lpDrawItemStruct->itemID,str); lpszText= str; } ASSERT(lpszText != NULL); CDC dc; dc.Attach(lpDrawItemStruct->hDC); // Save these value to restore them when done drawing. COLORREF crOldTextColor = dc.GetTextColor(); COLORREF crOldBkColor = dc.GetBkColor(); // If this item is selected, set the background color // and the text color to appropriate values. Also, erase // rect by filling it with the background color. if ((lpDrawItemStruct->itemAction | ODA_SELECT) && (lpDrawItemStruct->itemState & ODS_SELECTED)) { dc.SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT)); dc.SetBkColor(::GetSysColor(COLOR_HIGHLIGHT)); dc.FillSolidRect(&lpDrawItemStruct->rcItem, ::GetSysColor(COLOR_HIGHLIGHT)); } else dc.FillSolidRect(&lpDrawItemStruct->rcItem, crOldBkColor); // If this item has the focus, draw a red frame around the // item's rect. if ((lpDrawItemStruct->itemAction | ODA_FOCUS) && (lpDrawItemStruct->itemState & ODS_FOCUS)) { CBrush br(RGB(255, 0, 0)); dc.FrameRect(&lpDrawItemStruct->rcItem, &br); } // Draw the text. dc.DrawText( lpszText, strlen(lpszText), &lpDrawItemStruct->rcItem, DT_CENTER|DT_SINGLELINE|DT_VCENTER); // Reset the background color and the text color back to their // original values. dc.SetTextColor(crOldTextColor); dc.SetBkColor(crOldBkColor); dc.Detach(); } |
En insérant dans la chaîne le caractère tabulation entre chaque portion et en appelant la fonction SetTabStop pour fixer les intervalles.
Il faut aussi coché l'option use tab stop sur le contrôle dans l'éditeur de ressources .
Code c++ : | Sélectionner tout |
1 2 3 4 5 | // Set tabstops at 100 and 200 dialog units int tab_stop[2] = {100, 200}; VERIFY(m_listbox.SetTabStops(2, tab_stop)); m_listbox.AddString("String1\tString2\tString3"); |
L'ascenseur horizontal dans une ClistBox n'est pas géré malgré la propriété disponible sur le contrôle dans l'éditeur de ressources.
Le code ci-dessous est une classe template permettant l'association à toute classe dérivée d'une CListBox.
Ce code est une version remaniée d'un exemple MSDN.
Code c++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 | #if !defined(AFX_TPLSCROLLLISTBOX_H__6D3C28EE_84F0_4612_92CF_4E59952F30C9__INCLUDED_) #define AFX_TPLSCROLLLISTBOX_H__6D3C28EE_84F0_4612_92CF_4E59952F30C9__INCLUDED_ #if _MSC_VER > 1000 #pragma once #endif // _MSC_VER > 1000 // TplScrollListBox.h : header file // ///////////////////////////////////////////////////////////////////////////// // TplScrollListBox window ///////////////////////////////////////////////////////////////////////////// typedef CArray<int,int> CIntArray; template <class PARENT_LISTBOX> class TplScrollListBox : public PARENT_LISTBOX { // Construction public: TplScrollListBox() { m_bLocked = FALSE; // start out in auto mode m_nLongestExtent = 0; // tracks longest extent, initially 0 m_nTabStops = 0; // no tab stops m_lpTabStops = NULL; // array of tab stops } // Attributes public: BOOL m_bLocked; CIntArray m_arrExtents; int m_nLongestExtent; int m_nTabStops; int* m_lpTabStops; // Operations public: void LockHExtentUpdate(){m_bLocked = TRUE;} void UnlockHExtentUpdate(){m_bLocked = FALSE;} void UpdateHExtent() { m_arrExtents.RemoveAll(); m_nLongestExtent = 0; int nCount = GetCount(); CDC* pDC = GetDC(); HFONT hFont = (HFONT)SendMessage(WM_GETFONT); CFont *pFont = CFont::FromHandle(hFont); ASSERT(pFont); CFont* pPrevFont = pDC->SelectObject(pFont); CString str; for(int i=0; i<nCount; i++) { GetText(i, str); InsertNewExtent(i, str, pDC); } SetHorizontalExtent(m_nLongestExtent); pDC->SelectObject(pPrevFont); ReleaseDC(pDC); } // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(TplScrollListBox) public: virtual BOOL OnWndMsg(UINT message,WPARAM wParam,LPARAM lParam,LRESULT* pResult) { switch(message) { case LB_ADDSTRING:*pResult=OnAddString(wParam,lParam); break; case LB_INSERTSTRING:*pResult=OnInsertString(wParam,lParam); break; case LB_DELETESTRING:*pResult=OnDeleteString(wParam,lParam); break; case LB_SETTABSTOPS :*pResult=OnSetTabStops(wParam,lParam); break; default:return PARENT_LISTBOX::OnWndMsg(message,wParam,lParam,pResult); } return TRUE; } virtual BOOL OnChildNotify(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pLResult) { switch (message) { case WM_DRAWITEM: DrawItem((LPDRAWITEMSTRUCT)lParam); break; case WM_MEASUREITEM:MeasureItem((LPMEASUREITEMSTRUCT)lParam); break; case WM_COMPAREITEM: *pLResult = CompareItem((LPCOMPAREITEMSTRUCT)lParam); break; case WM_DELETEITEM: DeleteItem((LPDELETEITEMSTRUCT)lParam); break; default:return PARENT_LISTBOX::OnChildNotify(message, wParam, lParam, pLResult); } return TRUE; } //}}AFX_VIRTUAL // Implementation public: virtual ~TplScrollListBox() { delete [] m_lpTabStops; } // Generated message map functions protected: void InsertNewExtent(int nItem, LPCTSTR lpszStr) { if (m_bLocked) return; CDC* pDC = GetDC(); HFONT hFont = (HFONT)SendMessage(WM_GETFONT); CFont *pFont = CFont::FromHandle(hFont); ASSERT(pFont); CFont* pPrevFont = pDC->SelectObject(pFont); InsertNewExtent(nItem, lpszStr, pDC); SetHorizontalExtent(m_nLongestExtent); pDC->SelectObject(pPrevFont); ReleaseDC(pDC); } void InsertNewExtent(int nItem, LPCTSTR lpszStr, CDC* pDC) { if (NULL == m_lpTabStops)InitTabStops(); CSize newExtent; if (GetStyle() & LBS_USETABSTOPS) newExtent = pDC->GetTabbedTextExtent(lpszStr, strlen(lpszStr),m_nTabStops, m_lpTabStops); else newExtent = pDC->GetTextExtent(lpszStr, strlen(lpszStr)); newExtent.cx += 6; m_arrExtents.InsertAt(nItem, newExtent.cx); if (newExtent.cx > m_nLongestExtent) { m_nLongestExtent = newExtent.cx; } } void InitTabStops() { int nDefault = 2; SetTabStops(1, &nDefault); } //{{AFX_MSG(TplScrollListBox) // NOTE - the ClassWizard will add and remove member functions here. //}}AFX_MSG afx_msg LRESULT OnAddString(WPARAM wParam, LPARAM lParam) { LRESULT lResult = Default(); if (LB_ERR == lResult || LB_ERRSPACE == lResult) // check for error first! return lResult; InsertNewExtent(lResult, (LPCTSTR)lParam); return lResult; } afx_msg LRESULT OnInsertString(WPARAM wParam, LPARAM lParam) { LRESULT lResult = Default(); if (LB_ERR == lResult || LB_ERRSPACE == lResult) // check for error first! return lResult; InsertNewExtent(lResult, (LPCTSTR)lParam); return lResult; } afx_msg LRESULT OnDeleteString(WPARAM wParam, LPARAM lParam) { LRESULT lResult = Default(); if (LB_ERR == lResult) // check for error first! return lResult; if (m_bLocked) // don't do anything if locked return lResult; int nExtent = m_arrExtents[wParam]; m_arrExtents.RemoveAt(wParam); if (nExtent >= m_nLongestExtent) { m_nLongestExtent = 0; for(int i = 0; i<lResult; i++) { if (m_arrExtents[i] > m_nLongestExtent) m_nLongestExtent = m_arrExtents[i]; } } SetHorizontalExtent(m_nLongestExtent); return lResult; } afx_msg LRESULT OnSetTabStops(WPARAM wParam, LPARAM lParam) { LRESULT lResult = Default(); if (!lResult) return lResult; m_nTabStops = wParam; if (NULL != m_lpTabStops) { delete [] m_lpTabStops; m_lpTabStops = NULL; } if (m_nTabStops > 0) { m_lpTabStops = new int[m_nTabStops]; memcpy(m_lpTabStops, (void*)lParam, m_nTabStops * sizeof(int)); CDC* pDC = GetDC(); HFONT hFont = (HFONT)SendMessage(WM_GETFONT); CFont *pFont = CFont::FromHandle(hFont); ASSERT(pFont); CFont* pPrevFont = pDC->SelectObject(pFont); CSize size; GetTextExtentPoint32(pDC->GetSafeHdc(), _T("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"), 52, &size); pDC->SelectObject(pPrevFont); ReleaseDC(pDC); int aveCharWidth = (size.cx/26 +1)/2; for(int i=0; i<m_nTabStops; i++) m_lpTabStops[i] = (m_lpTabStops[i] * aveCharWidth + 2)/4; } if (!m_bLocked) UpdateHExtent(); // tabs changed, recalc everything! return lResult; } }; ///////////////////////////////////////////////////////////////////////////// //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_TPLSCROLLLISTBOX_H__6D3C28EE_84F0_4612_92CF_4E59952F30C9__INCLUDED_) |
Code c++ : | Sélectionner tout |
1 2 | TplScrollListBox<CListBox> m_MyListBox; |
Le réglage de la hauteur pourra s'effectuer avec la fonction :
Code C++ : | Sélectionner tout |
1 2 | CListBox::SetItemHeight int SetItemHeight( int nIndex, UINT cyItemHeight ); |
Dans le cas d'une Listbox classique l'argument nIndex n'est pas pris en compte et doit rester à zéro, l'ensemble des lignes de la Listbox aura la même hauteur.
Exemple :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 | CSize sz; CDC* pDC = m_ListboxNormal.GetDC(); m_ListboxNormal.GetText( 0, str ); CFont* pOldFont = pDC->SelectObject(&m_Font); sz = pDC->GetTextExtent(str); m_ListboxNormal.SetItemHeight(0,sz.cy*2); pDC->SelectObject(pOldFont); m_ListboxNormal.ReleaseDC(pDC); |
L'argument nIndex sera pris en compte avec une Listbox possédant le style LBS_OWNERDRAWVARIABLE, permettant ainsi de spécifier la hauteur de chaque ligne de la ListBox.
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // extrait de MSDN // réglage de la hauteur de chaque ligne de listbox avec la fonte courante. CString str; CSize sz; int dx=0; CDC* pDC = pmyListBox->GetDC(); for (int i=0;i < pmyListBox->GetCount();i++) { pmyListBox->GetText( i, str ); sz = pDC->GetTextExtent(str); pmyListBox->SetItemHeight( i, sz.cy ); } pmyListBox->ReleaseDC(pDC); |
Si la Listbox est LBS_OWNERDRAWFIXED SetItemHeight permettra de spécifier la hauteur pour l'ensemble des lignes de la Listbox .
Dans le cas où la listbox est LBS_OWNERDRAWVARIABLE nous disposons d'une autre possibilité pour spécifier la hauteur d'une ligne :
Redéfinir la fonction virtuelle MeasureItem avec l'aide de classwizard.
Code C++ : | Sélectionner tout |
virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
Exemple:
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | void CMyListBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) { // TODO: Add your code to determine the size of specified item CDC *pDC = GetDC(); if(m_pFont) { CFont* pOldFont = pDC->SelectObject(m_pFont); TEXTMETRIC tm; pDC->GetTextMetrics(&tm); lpMeasureItemStruct->itemHeight = tm.tmHeight + tm.tmExternalLeading; lpMeasureItemStruct->itemHeight += lpMeasureItemStruct->itemHeight / 2; pDC->SelectObject(pOldFont); } ReleaseDC(pDC); } |
Note: ici l'ensemble des lignes sera réglé à la même hauteur, il est possible de personnaliser la hauteur de chaque ligne grâce la zone itemData de la structure MEASUREITEMSTRUCT
Le projet de tests : CustomListBox.zip
La première réponse serait de faire :
Code C++ : | Sélectionner tout |
1 2 | MyListBox.ModifyStyle(WS_VSCROLL,0); // enlève la scrollbar MyListBox.ModifyStyle(0,WS_VSCROLL); // remet la scrollbar |
Malheureusement ça ne fonctionne pas,
la Listbox n'accepte pas les changements de style après sa création ,
Il faut donc la recréer pour que le style soit pris en compte.
On procédera par recopie des infos de l'objet à l'identique :
Code C++ : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | //--------------------------------------- BOOL CMyListBox::Recreate(LPVOID lpParam/*=0*/) { if (GetSafeHwnd() == NULL)return FALSE; CWnd* pParent = GetParent(); if (pParent == NULL) return FALSE; // get current attributes DWORD dwStyle = GetStyle(); DWORD dwStyleEx = GetExStyle(); CRect rc; GetWindowRect(&rc); pParent->ScreenToClient(&rc);// map to client co-ords UINT nID = GetDlgCtrlID(); CFont* pFont = GetFont(); CWnd* pWndAfter = GetNextWindow(GW_HWNDPREV); // get the currently selected text (and whether it is a valid list selection) CString sCurText; int nCurSel = GetCurSel(); BOOL bItemSelValid = nCurSel != -1; if (bItemSelValid)GetText(nCurSel, sCurText); CMyListBox listboxNew; if (! listboxNew.CreateEx(dwStyleEx, _T("ListBox"), _T(""), dwStyle, rc, pParent, nID, lpParam)) return FALSE; listboxNew.SetFont(pFont); int nNumItems = GetCount(); for (int n = 0; n < nNumItems; n++) { CString sText; GetText(n, sText); int nNewIndex = listboxNew.AddString(sText); listboxNew.SetItemData(nNewIndex,GetItemData(n)); } // re-set selected text if (bItemSelValid) listboxNew.SetCurSel(listboxNew.FindStringExact(-1, sCurText)); // destroy the existing window, then attach the new one DestroyWindow(); HWND hwnd = listboxNew.Detach(); Attach(hwnd); // position correctly in z-order SetWindowPos(pWndAfter == NULL ? &CWnd::wndBottom : pWndAfter, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); return TRUE; } |
Le projet de tests : CustomListBox.zip
Les propriétés sont modifiables en utilisant la fonction de la classe CWnd :ModifyStyle qui permet de supprimer /d'ajouter en un seul appel des styles au contrôle.
Code c++ : | Sélectionner tout |
1 2 | MyListBox.ModifyStyle(LBS_SORT ,0); |
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes 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 © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et 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.