Problema ON_NOTIFY_REFLECT_EX

Intrebari legate de programarea cu biblioteci precum MFC, ATL, WTL si GDI+.
mesajflaviu
Membru++
Membru++
Posts: 687
Joined: 10 Sep 2008, 21:40
Judet: Cluj

Re: Problema ON_NOTIFY_REFLECT_EX

Post by mesajflaviu » 02 Jul 2011, 23:14

Da , intradevar asta era situatia mea, CTestList6View derivata din CListViewExt , iar CListViewExt deritvata din CListView. In mod normal nu este nevoie de OnColumnClick si in parinte si in copil, dar fiindca nu functiona ON_NOTIFY_REFLECT_EX eram curios cum se poate rezolva problema ... si am vazut-o rezolvata elegant.
Daca tot am primit o solutie buna, as intreba inca ceva : in CListViewExt am cateva metode care tin de CListCtrl, de exemplu InsertItem(...), care se poate apela in CTestList6View simplu : InsertItem(...), adica fara GetListCtrl().InsertItem(...). Ok, dar nu toate metodele CListCtrl sant implementate in CListViewExt, asa ca un eventual programator nu stie cand sa apeleze metode ale CListViewExt, si cand metode CListCtrl ... De exemplu InsertItem(...) trebuie folosita ca atare si nu GetListCtrl().InsertItem(...) .... dar de exemplu SetItemText(...) nu are implementare in CListViewExt, si atunci aceasta metoda trebuie folosita GetListCtrl().SetItemText(...).

Bine, asta pentru ca totul sa fie facut cum trebuie, nu ca nu ar merge si asa ... eu am gasit o solutie, dar nu stiu daca e tocmai cea mai inspirata : am implementat in CListViewExt toate metodele CListCtrl ( care intamplator nu sant tocmai putine ) si atunci in CTestList6View se pot apela metode specifice CListCtrl fara GetListCtrl() in fata, eventual cu GetListCtrlExt() care aduce o referinta la CListViewExt.



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 » 03 Jul 2011, 11:49

Nu, nu-i Ok.
Nu numai ca scrii mult cod degeaba (pui metode care pur si simplu apeleaza o alta metoda) dar mai mai sunt si alte motive:
  1. Daca portezi proiectul sau daca muti clasa CListViewExt in alt proiect sub o versiune mai noua de MFC ce faci? Te apuci s-o aduci la zi cu metodele noi din CListCtrl? Eu zic ca-i naspa.
  2. Un programator care stie clasa CListView sau se uita in documentatie, vede o singura metoda CListView::GetListCtrl si va ramane mofluz. Ce faci? Te apuci sa scrii ditamai documentatia pentru CListViewExt repetand ce scrie la CListCtrl, tinand-o la zi asa cum am spus la punctul #1? Scrii in document pur si simplu "metodele CListViewExt sunt identice cu cele din CListCtrl"? C'mon, are you sure? (see #1 again).
  3. La orice ora cineva poate sa-ti "sunteze" (cu voie sau din greseala) o metoda din CListViewExt cu cea din CListCtrl. Daca sa zicem, in CListViewExt ai pus si ceva in plus, a dat-o-n bara.
  4. si cred ca-ar mai fi...
NU-i un minus de performanta daca scrii ceva gen:

Code: Select all

   CFoo& foo = GiveMeAReferenceToFoo();
   foo.DoSomething();
   foo.DoSomethingElse();
   // ... and so on
Dimpotriva, un minus de performanta ar in cazul

Code: Select all

   /*this->*/DoSomething();
   /*this->*/DoSomethingElse();
   // ...
...unde this->DoSomething() si this->DoSomethingElse() cheama la randul lor foo.DoSomething() si foo.DoSomethingElse().
// Ok, eu unul nu ma rup in paispe cu "performanta" la cod de genul asta, dar daca se poate simplu "mai bine", de ce nu?
NU doare mana pe nimeni sa lipeasca cu Ctrl+V toate acele "list." in cod.

Ar parea justificata "dublarea" in cazul in care ai metode de CListCtrl la care adaugi ceva in plus in CListViewExt (fac ce fac in CListViewExt apoi chem metoda corespunzatoare din CListCtrl).
Sa zicem, exemplul lui CListCtrl::InsertColumn, pe care il "dublez" cu CListViewExt::InsertColumn caruia ii mai adaug ceva argumente cu informatii suplimentare (culoare, tip (text, data,etc)) .
NU, nu-i OK. E confusing pentru cine stie cat de cat sau se uita in documentatie si in plus o poate sunta, asa cum am spus la #3.

Concluzii
Lasa asa cum e si cum se stie si cum a fost proiectat de aia ce-au facut MFC-ul! N-o fi design-ul lui "peste" si in general, lumea se prinde mai greu care-i relatia intre CListCtrl in CListView. Dar mie mi se pare destul de econimic si elegant modul cum au fost gandite.
NU te apuca sa "dublezi" metodele lui CListCtrl in CListViewExt!
Lasa-le asa cum sunt, sa fie apelate via referinta obtinuta cu GetListCtrl().
Pune in CListViewExt doar metode cu functionalitati noi!
Daca ai nevoie de argumente suplimentare nu le adauga la metodele deja existente. Pune metode noi in CListViewExt. In exemplul de mai sus, SetColumnColor, sau SetColumnData etc si NU pune o functie CListViewExt::InsertItem similara cu cea din CListCtrl dat avand argumente suplimentare.

Asa e mai clar, nu da cu barda-n ce exista, nu da nastere la confuzii si n-ai nici o frica de suntari.

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

Re: Problema ON_NOTIFY_REFLECT_EX

Post by mesajflaviu » 04 Jul 2011, 10:08

Era nevoie doar de cateva metode ale clasei CListViewExt care au acelasi nume si functionalitate ca si ale clasei CListCtrl, InsertColumn, InsertItem, DeleteColumn, DeleteItem, etc. ... le-am pus in coada cate un Ext ... si parca nu mai e asa ceata ... Asa, cu GetListCtrlExt(). am metode ale clasei CListViewExt si cu GetListCtrl(). am metode ale clasei CListCtrl.

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 » 04 Jul 2011, 11:36

Aici, parca-parca o mica diagrama de clase ar fi necesara ca sa intelegem... :). Incerc totusi in cuvinte.

Pana la urma eu as face asa:
Derivez totusi o clasa CListCtrlExt din CListCtrl, careia ii adaug metodele necesare.
"Ascund" CListView::GetListCtrl in CListViewExt. Cu alte cuvinte definesc o metoda CListViewExt::GetListCtrl:

Code: Select all

  inline CListCtrlExt& CListViewExt::GetListCtrl() const
	{ return *(CListCtrlEx*)this; } 
Odata ce CListCtrlExt mosteneste CListCtrl, in CListViewExt nu este nevoie de o metoda noua CListViewExt::GetListCtrlExt (cu Ext in coada).
Ma mult incurca. Sper ca m-am exprimat suficient de clar, fara patratele si sagetute UML. :D

Alta cale ar fi cea pe care mersesem pana acum:
Nu mai derivez din CListCtrl si pun metodele noi direct in CListViewExt. In cazul asta, nici acel GetListCtrlExt si nici redefinirea lui GetListCtrl n-ar avea absolut nici un sens.

// Ambele ar face un architect care habar n-are Windows/MFC sa faca infarct privind la acel cast din GetListCtrl si cautand o legatura intre CListView si CListCtrl (respectiv CListViewEx si CListCtrlEx) ca sa puna sagetute pe diagrama. :biggrin:

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

Re: Problema ON_NOTIFY_REFLECT_EX

Post by mesajflaviu » 04 Jul 2011, 14:25

Desi ar fi mai buna, prima metoda nu stiu daca functioneaza :

Code: Select all

// ListViewExt.h
	inline CListCtrlExt& CListViewExt::GetListCtrl() const
		{return *(CListCtrlExt*)this;}
... am atasat proiectul de test.
Attachments
TestList.rar
(123.11 KiB) Downloaded 253 times

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 » 04 Jul 2011, 16:22

Intai si-ntai, incearca te rog programelul urmator care simuleaza fenta cu GetListCtrl.

Code: Select all

#include <iostream>

struct CFoo
{
   void foo() { std::cout << "Wuz ere!"; }
};

struct CBar
{
   CFoo& GetFoo() { return *(CFoo*)this; }
};

int main()
{
   CBar bar;
   bar.GetFoo().foo();
   return 0;
}
Merge? N-are de ce sa nu mearga.
Acuma hai sa "perfectionam" pe CFoo si sa-l facem pe CFoo::foo() virtual.

Code: Select all

struct CFoo
{
   virtual void foo() { std::cout << "Wuz ere!"; }
};
// ... la fel ca mai sus
Mai merge? Mai merge dar prin balarii. :)

La fel ai facut si tu cu gasca aia de functii CListCtrlExt::InsertColumn s.a.m.d.
Trebuie sa fie virtuale? Nu. Sterge repede "virtual" de acolo. ;)

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 » 04 Jul 2011, 17:17

La Biblia C++ scrie asa

9.3.1 Nonstatic member functions
[...]
If a nonstatic member function of a class X is called for an object that is not of type X, or of a type derived from X, the behavior is undefined.
Este exact ce face MFC-ul cu acel CListView::GetListCtrl.
Naspa daca ne luam dupa scripturi, dar in practica functioneaza atata timp cat GetListCtrl().DoSomething() nu se atinge de vreo data membru din CListCtrl si nu este virtuala.
Cum spuneam, metodele lui CListView sunt in general simple wrappere peste SendMessage deci no problem.

Ok. Acum scotand 'virtual' de acolo tot nu rezolvi problema.
Ai pus m_HeaderCtrl.SubclassWindow(hWnd) in CListCtrlExt::PreSubclassWindow care nu se apeleaza niciodata. Si mai naspa. N-o sa mearga nici chiar daca in CListViewExt apelezi direct GetListCtrl().SubclassWindow(). De ce? Pentru ca PreSubclassWindow e... virtuala de la mama ei, CWnd.

Asa ca, sa nu ne mai invartim in jurul cozii si sa ne apucam de versiunea 2 (de fapt cea pe care am recomandat-o de la inceput):
Nu mai derivam din CListCtrl si pun metodele noi direct in CListViewExt.
// daca o sa ai un pic de rabdare, poate termin un schelet in proiectul ListOne care sa te ajute sa vezi ce si cum trebuie facut.

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

Re: Problema ON_NOTIFY_REFLECT_EX

Post by mesajflaviu » 04 Jul 2011, 20:38

Ai pus m_HeaderCtrl.SubclassWindow(hWnd) in CListCtrlExt::PreSubclassWindow care nu se apeleaza niciodata. Si mai naspa. N-o sa mearga nici chiar daca in CListViewExt apelezi direct GetListCtrl().SubclassWindow().
Asta am incercat si eu :(

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 » 06 Jul 2011, 09:13


Post Reply