Page 1 of 2

Custom Listview (derved from CListView)

Posted: 06 Jul 2011, 09:10
by Ovidiu Cucu
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 366 times

Re: Custom Listview (derved from CListView)

Posted: 07 Jul 2011, 00:39
by Silviu Ardelean
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. :)

Re: Custom Listview (derved from CListView)

Posted: 07 Jul 2011, 08:23
by Ovidiu Cucu
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!

Problema ON_NOTIFY_REFLECT_EX

Posted: 07 Jul 2011, 08:45
by mesajflaviu
Trebuie sa recunosc ca e mai bun CListOneView decat cel incercat de mine, e altcumva gandit ...

Re: Problema ON_NOTIFY_REFLECT_EX

Posted: 07 Jul 2011, 09:56
by Ovidiu Cucu
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!" ;)

Re: Custom Listview (derved from CListView)

Posted: 07 Jul 2011, 12:47
by Silviu Ardelean
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. :)

Re: Custom Listview (derved from CListView)

Posted: 08 Jul 2011, 11:27
by mesajflaviu
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 ?

Re: Custom Listview (derved from CListView)

Posted: 08 Jul 2011, 11:55
by Ovidiu Cucu
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.

Re: Custom Listview (derved from CListView)

Posted: 08 Jul 2011, 14:36
by mesajflaviu
Oricum, cea mai interesanta idee din implementare mi s-a parut tratarea mesajelor OnInsertColumn, etc., in CListOneView ... simplu si eficient (evident, comparand cu CListCtrlExt).

Re: Custom Listview (derved from CListView)

Posted: 08 Jul 2011, 15:18
by mesajflaviu
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 ...

Re: Custom Listview (derved from CListView)

Posted: 08 Jul 2011, 15:32
by Ovidiu Cucu
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 338 times
// am solvat si bug-ul raportat de Silviu. :)

Re: Custom Listview (derved from CListView)

Posted: 08 Jul 2011, 22:23
by mesajflaviu
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 ?

Re: Custom Listview (derved from CListView)

Posted: 09 Jul 2011, 09:36
by Silviu Ardelean
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.

Re: Custom Listview (derved from CListView)

Posted: 09 Jul 2011, 10:55
by Ovidiu Cucu
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 352 times
Contine ultimile modificari si in plus l-am aranjat putin.

Re: Custom Listview (derved from CListView)

Posted: 09 Jul 2011, 13:41
by mesajflaviu
Simplu.
Si eficient.