Custom Listview (derved from CListView)

Intrebari legate de programarea cu biblioteci precum MFC, ATL, WTL si GDI+.
User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Custom Listview (derved from CListView)

Post by Ovidiu Cucu » 06 Jul 2011, 09:10

Am atasat aici un proiectel cu un listview custom (derivat din CListView).

Zic eu, e simplu si curat, nu foloseste hook-uri si alte "avioane" ca prin tot felul de codeproject-uri de pe net la care ma doare capul numai daca ma uit, nu suprascrie functii "generice" ca PreTranslateMessage si nu "redirectioneaza" mesaje si notificari de colo colo, nu ascunde metode din clasa de baza, s.a.m.d.
E inca in lucru dar asa cum e acum, cred ca-i un "skeleton" pe care se poate intelege mai bine ce si cum trebuie facut.

Descriere, pe scurt:
  • Am implemetat editarea sub-itemurilor intr-un control edit; ramane de adaugat editarea cu alte controale cum ar fi cotrol date-time, etc.
  • Se face sortarea pentru coloane de tip text (la un click pe headerul cloanei); in viitor voi pune si sortare dupa ate tipuri (numar, data calendaristica, etc).
  • Arata cum se trateaza mesajele trimise listei (ex. LVM_INSERTCOLUMN) pentru a adauga functii custom.
  • Arata cum se trateaza notificarile (ex. LVN_COLUMNCLICK)) si cum se pot "trimite" mai departe in clasele derivate: vezi handlerul si functia virtulala CListOneView::OnColumnClick.
  • Grosul codului de customizare l-am mutat in clasa CListManager si poate fi refolosit in alte tipuri de liste: control (derivat din CListCtrl) si ActiveX (derivat din COleControl).
Daca sunt intrebari, nelamuriri si sugestii, va rog nu ezitati sa le spuneti!
ListOne Working Version.zip
(42.44 KiB) Downloaded 356 times



User avatar
Silviu Ardelean
Senior
Senior
Posts: 1175
Joined: 12 Jul 2007, 09:22
Judet: Timiş
Location: Timisoara
Contact:

Re: Custom Listview (derved from CListView)

Post by Silviu Ardelean » 07 Jul 2011, 00:39

Am gasit un crash in CInPlaceEdit::OnKeyDown() daca dai enter si iti intra pe cazul VK_RETURN. Crash-ul se produce ptr. ca stergi si pui pe NULL m_pInPlaceCtrl iar apoi apepezi CEdit::OnKeyDown().
Muta apelul lui OnKeyDown() la inceputul metodei si everything is fine. :)

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Custom Listview (derved from CListView)

Post by Ovidiu Cucu » 07 Jul 2011, 08:23

Intr-o versiune anterioara nu dadeam delete la m_pInPlaceCtrl decat in destructor si de aici a aparut problema.
Ca de obicei :), am terminat pe "ultima suta de metri" si am facut upload fara sa testez suficient.
L-am reparat.

Mersi mult!

mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Problema ON_NOTIFY_REFLECT_EX

Post by mesajflaviu » 07 Jul 2011, 08:45

Trebuie sa recunosc ca e mai bun CListOneView decat cel incercat de mine, e altcumva gandit ...

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Problema ON_NOTIFY_REFLECT_EX

Post by Ovidiu Cucu » 07 Jul 2011, 09:56

mesajflaviu wrote:Trebuie sa recunosc ca e mai bun CListOneView decat cel incercat de mine, e altcumva gandit ...
E gandit MFC-style.
When in Rome, do as the Romans do!
In traducere libera: "When write MFC extensions, use MFC features!" ;)

User avatar
Silviu Ardelean
Senior
Senior
Posts: 1175
Joined: 12 Jul 2007, 09:22
Judet: Timiş
Location: Timisoara
Contact:

Re: Custom Listview (derved from CListView)

Post by Silviu Ardelean » 07 Jul 2011, 12:47

Ovidiu Cucu wrote:Intr-o versiune anterioara nu dadeam delete la m_pInPlaceCtrl decat in destructor si de aici a aparut problema.
Ca de obicei :), am terminat pe "ultima suta de metri" si am facut upload fara sa testez suficient.
L-am reparat.

Mersi mult!
Cu placere! Asta e munca noastra... Cum nimeni nu e perfect, ne mai scapa anumite detalii. :)

mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Custom Listview (derved from CListView)

Post by mesajflaviu » 08 Jul 2011, 11:27

In aceasta implementare nu cred ca sant disponibile SetItemData / GetItemData ... am incercat :

Code: Select all

listCtrl.SetItemData(nIndex,nIndex + 100);
dar nu merge ... se poate rezolva ?

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Custom Listview (derved from CListView)

Post by Ovidiu Cucu » 08 Jul 2011, 11:55

Hmmm... CListCtrl::SetItemData chiar c-ar trebui "ascunsa".
In item data tin un pointer la o structura SItemData si nu un simplu numar.
Daca vine Gigel si face asa in clasa lui derivata din CListOneView...

Code: Select all

   CListCtrl& listCtrl = GetListCtrl();
   listCtrl.SetItemData(0, 666); // Ptiu, uciga-l toaca! :)))
...s-a dus naibii pointerul si cu prima ocazie... "Kaboom!".

O sa ma gandesc ce si cum trebuie si-o sa plasez un update.

mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Custom Listview (derved from CListView)

Post by mesajflaviu » 08 Jul 2011, 14:36

Oricum, cea mai interesanta idee din implementare mi s-a parut tratarea mesajelor OnInsertColumn, etc., in CListOneView ... simplu si eficient (evident, comparand cu CListCtrlExt).

mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Custom Listview (derved from CListView)

Post by mesajflaviu » 08 Jul 2011, 15:18

Ovidiu Cucu wrote:Hmmm... CListCtrl::SetItemData chiar c-ar trebui "ascunsa".
In item data tin un pointer la o structura SItemData si nu un simplu numar.
Daca vine Gigel si face asa in clasa lui derivata din CListOneView...

Code: Select all

   CListCtrl& listCtrl = GetListCtrl();
   listCtrl.SetItemData(0, 666); // Ptiu, uciga-l toaca! :)))
...s-a dus naibii pointerul si cu prima ocazie... "Kaboom!".

O sa ma gandesc ce si cum trebuie si-o sa plasez un update.
Ar fi de rezolvat daca ar exista vreun mesaj de returnat pentru SetItemData / GetItemData, dar asa ...

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Custom Listview (derved from CListView)

Post by Ovidiu Cucu » 08 Jul 2011, 15:32

Pentru CListCtrl::GetItemData:
Ca sa te asiguri ca programatorul nu face prostii punand "avioane" in item data in loc de un pointer la SItemData, tratezi mesajul LVM_SETITEM si faci o verificare inainte de a apela Default.
Se poate folosi, de exemplu, ASSERT_KINDOF:

Code: Select all

LRESULT CListOneView::OnSetItem(WPARAM wParam, LPARAM lParam)
{
   SItemData* pItemData = (SItemData*)((LPLVITEM)lParam)->lParam; 
   ASSERT_KINDOF(SItemData, pItemData); // Not a valid SItemData

   return Default();
}
SItemData trebuie derivat din CObject si sa aiba DECLARE_DYNAMIC si IMPLEMENT_DYNAMIC.

La CListCtrl::GetItemData nu cred ca mai trebuie nimic. O sa intoarca acel pointer si gata.

Vezi in proiectul atasat ce se intampla cand selectezi meniul "Test/Test" in mod DEBUG.
ListOne_working.zip
(64.02 KiB) Downloaded 327 times
// am solvat si bug-ul raportat de Silviu. :)

mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Custom Listview (derved from CListView)

Post by mesajflaviu » 08 Jul 2011, 22:23

Bun, eu ma gandeam la o rezolvare care sa mentina GetItemData / SetItemData, daca vreau sa incarc in ListOneView o lista de produse si la SetItemData sa pun ID-ul fiecaruia ? Cum fac ?

User avatar
Silviu Ardelean
Senior
Senior
Posts: 1175
Joined: 12 Jul 2007, 09:22
Judet: Timiş
Location: Timisoara
Contact:

Re: Custom Listview (derved from CListView)

Post by Silviu Ardelean » 09 Jul 2011, 09:36

Intr-un list control de tip raport reprezinti propietatile unor obiecte (ex. ai o structura address cu diverse propietati si tu in list reprezinti acele propietati pe diferite coloane). In SetItemData() practic setezi pointeri la niste obiecte si informatia iti este utila cand ai nevoie sa faci sortarea, etc.

Un exemplu de folosire corecta a lui SetItemData() il gasesti aici.

User avatar
Ovidiu Cucu
Fondator
Fondator
Posts: 3778
Joined: 11 Jul 2007, 16:10
Judet: Iaşi
Location: Iasi
Contact:

Re: Custom Listview (derved from CListView)

Post by Ovidiu Cucu » 09 Jul 2011, 10:55

Silviu Ardelean wrote: Un exemplu de folosire corecta a lui SetItemData() il gasesti aici.
Ughhh! Sa fiu sef la MS si sa am un machinegun, l-as ciurui pe-ala care-a scris articolul. :)
// E un fel de "lasa-ma sa te las" in problema sortarii listview-urilor.
Sa-l iertam totusi, pentru ca articolul e scris pe vremea lui Pazvante (se specifica asta acolo: Retired KB Content Disclaimer). ;)

Dar mai sunt si altii pe net, prin tot felul de codeprojecturi, care pornind de la asa ceva baga "improvements": trantesc un std::vector sau sau std::list sau alt container STL (ca-i cool) in care baga itemurile din lista, trag un std::sort sau std::list::sort (ca-i si mai cool), golesc lista, dupa care o umplu din nou (asta nu mai e asa de cool dar ei se face ca nu stie :)).
Pe aia... i-as detona. :D
// A se citi cu atentie Este necesara utilizarea STL intr-o aplicatie MFC?

Pai bine mah, oameni buni! Odata ce tinem informatiile din lista intr-un array/container extern si facem sortarea extern, nu mai bine facem o lista virtuala si ne bagam picioarele in el CListCtrl::SortItems?

Hai sa lasam avioanele cu care ne procopseste goagle sărci si sa incercam sa facem o treaba seriasa! ;)

Deci, de unde am ramas:
In item data listei de la mama ei (acel lParam din LVITEM), acum tinem pointeri la o structura SItemData si nu-i putem inlocui cu altceva.
Daca Gigel incearca sa puna avioane in clasa derivata din CListOneView, atunci "halt! verboten!" (acel ASSERT_KINDOF din CListOneView::OnSetItem).
Nu vad alta solutie mai buna. Oricum e bine sa nu uiti sa documentezi chestia asta daca nu vrei ca mai tarziu vreun coleg sa te faca sa sughiti.

Acuma, daca vrem totusi sa tinem ceva user-data in item-urile listei, no problem.
Adaug la SItemData un membru, sa-i zicem LPARAM m_lParam iar in CListOneView doua metode publice SetItemUserData si GetItemUserData:

Code: Select all

BOOL CListOneView::SetItemUserData(int nItem, DWORD dwData)
{
   CListCtrl& listCtrl = GetListCtrl();
   SItemData* pItemData = (SItemData*)listCtrl.GetItemData(nItem);
   pItemData->m_lParam = (LPARAM)dwData;
   return listCtrl.SetItemData(nItem, (DWORD)pItemData);
}

Code: Select all

DWORD CListOneView::GetItemUserData(int nItem)
{
   CListCtrl& listCtrl = GetListCtrl();
   SItemData* pItemData = (SItemData*)listCtrl.GetItemData(nItem);
   return (DWORD)pItemData->m_lParam;
}
Simplu.

Poti sa iei din nou proiectul.
ListOne_working.zip
(59.36 KiB) Downloaded 341 times
Contine ultimile modificari si in plus l-am aranjat putin.

mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Custom Listview (derved from CListView)

Post by mesajflaviu » 09 Jul 2011, 13:41

Simplu.
Si eficient.

Post Reply