Atasare CHeaderCtrlEx la CListCtrlEx

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

Atasare CHeaderCtrlEx la CListCtrlEx

Post by mesajflaviu » 14 Dec 2010, 12:27

As vrea sa combin 2 clase , extensii ale CHeaderCtrl si CListCtrl , insa intampin o problema peste care nu pot trece : nu pot atasa CHeaderCtrlEx la CListCtrlEx ...
Am o clasa , CListCtrlEx cu mai multe capabilitati decat CListCtrl :

Code: Select all

// ListCtrlEx.h : header file
class CListCtrlEx : public CListCtrl
{
	DECLARE_DYNAMIC(CListCtrlEx)
...
...
protected:
	virtual void PreSubclassWindow();
...
}
si

Code: Select all

// ListCtrlEx.cpp : implementation file
...
...
void CListCtrlEx::PreSubclassWindow()
{
	m_clrDefBack = GetTextBkColor() | 0xFF000000;
	m_clrDefText = GetTextColor();

	SetExtendedStyle(LVS_EX_FULLROWSELECT);
	ModifyStyle(0,LVS_REPORT);

	CListCtrl::PreSubclassWindow();
}
...
...
dar aceasta clasa nu are control pe header ( nu memoreaza latimea coloanei , ordinea lor , etc. ) si am gasit o clasa aici care face aceste lucruri .
Prototipul acestei clase CListctrlEx de aici este :

Code: Select all

// ListCtrlEx.h : header file

#include "HeaderCtrlEx.h"

class CListCtrlEx : public CListCtrl
{
	DECLARE_DYNAMIC(CListCtrlEx)
	CHeaderCtrlEx* GetHeaderCtrl(){return &m_wndHeader;}
...
protected:
	CHeaderCtrlEx m_wndHeader;
...
	virtual void PreSubclassWindow();
}
iar atasarea cu CHeaderCtrlEx se face in modul urmator :

Code: Select all

void CListCtrlEx::PreSubclassWindow()
{
	// TODO: Add your specialized code here and/or call the base class

	HWND hWnd = ::GetWindow(m_hWnd, GW_CHILD);
	ASSERT(hWnd);
	if(hWnd)m_wndHeader.SubclassWindow(hWnd);

	CListCtrl::PreSubclassWindow();
}
Ok, codul merge frumos ...
includ clasa CHeaderCtrlEx la proiectul meu , si incerc sa o atasez la clasa mea CListCtrlEx :

Code: Select all


#include "HeaderCtrlEx.h"

void CListCtrlEx::PreSubclassWindow()
{
	HWND hWnd = ::GetWindow(m_hWnd, GW_CHILD);
	ASSERT(hWnd);
	if(hWnd)m_wndHeader.SubclassWindow(hWnd);

	m_clrDefBack = GetTextBkColor() | 0xFF000000;
	m_clrDefText = GetTextColor();

	SetExtendedStyle(LVS_EX_FULLROWSELECT);
	ModifyStyle(0,LVS_REPORT);

	CListCtrl::PreSubclassWindow();
}
dar da eroare :

Code: Select all

Second Chance Assertion Failed: File wincore.cpp, Line 311
la aceasta linie in wincore.cpp

Code: Select all

//    linia 311
BOOL CWnd::Attach(HWND hWndNew)
e clar ca nu atasez bine CHeaderCtrlEx de CListCtrlEx , dar intrebarea este , cum fac asta ? De ce in proiectul original atasarea se face , dar in proiectul meu nu ?
Am citit pe net articole despre cum se face subclasarea , dar nici o solutie nu merge in acest caz ...

M-as bucura mult de orice ajutor !



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

Re: Atasare CHeaderCtrlEx la CListCtrlEx

Post by Ovidiu Cucu » 16 Dec 2010, 00:01

  • Code: Select all

    ModifyStyle(0, LVS_REPORT)
    Daca tipul a fost de exemplu LVS_LIST, atunci va ramane tot LVS_LIST (LVS_LIST|LVS_REPORT == LVS_LIST; vezi cum sunt definite).
    Corect:

    Code: Select all

    ModifyStyle(LVS_TYPEMASK, LVS_REPORT);
  • Code: Select all

    HWND hWnd = ::GetWindow(m_hWnd, GW_CHILD);
    Da asta un handle la controlul header? O fi, dar nu poti baga mana-n foc.
    Corect:

    Code: Select all

    HWND hWnd = (HWND)::SendMessage(m_hWnd, LVM_GETHEADER, 0, 0);
  • Code: Select all

    CHeaderCtrlEx* GetHeaderCtrl(){return &m_wndHeader;}
    Nu prea-i OK. Poate ca lista nu are header si mai departe ai necazuri.
    Oricum un pic mai frumos e:

    Code: Select all

    CMyHeaderCtrl* CMyListCtrl::GetHeaderCtrl()
    {
       return (CMyHeaderCtrl*)CListCtrl::GetHeaderCtrl();
    }
Observatiile de mai sus sunt la modul general.
Sa zicem totusi ca lista ta custom e musai una avand stilul report si foloseste acel header custom.
In cazul asta, eu as scrie simplu, cam asa:

Code: Select all

void CMyListCtrl::PreSubclassWindow() 
{
   ASSERT((GetStyle() & LVS_TYPEMASK) == LVS_REPORT); // must have LVS_REPORT type
   HWND hWnd = (HWND)::SendMessage(m_hWnd, LVM_GETHEADER, 0, 0);
   m_headerCtrl.SubclassWindow(hWnd);
   //...etc.
}

User avatar
Andreas
Membru
Membru
Posts: 117
Joined: 09 Nov 2008, 12:13
Judet: Timiş
Location: Timisoara

Re: Atasare CHeaderCtrlEx la CListCtrlEx

Post by Andreas » 16 Dec 2010, 14:59

cum creezi controlul lista? din resursa sau manual, cu Create? in al doilea caz fereastra control header nu exista la momentul apelarii PreSubclassWindow de catre MFC; in primul caz, crearea din resursa ca in exemplu de pe net, fereastra control header este tot timpul creata...
si mai o chestie, cred ca faci confuzie cu ce la cine se ataseaza?...
e clar ca nu atasez bine CHeaderCtrlEx de CListCtrlEx , dar intrebarea este , cum fac asta ?
nu, in cazul tau atasezi obiectul header creat de framework la obiectul CHeaderCtrlEx, adica m_wndHeader, astfel incat toate mesajele transmise la cel din framework trec prin acesta; aceasta subclsare dinamica poate fi inteleasa ca un obiect-filtru de mesaje a unui obiect preexistent, de altfel asa si este denumit in alte framework-uri gen Qt, "adevarata" subclasare fiind cea statica cum e cazul lui CListCrl din exemplul tau(doar un obiect de genul asta exista la runtime, cu avantajul metodelor adaugate)

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

Re: Atasare CHeaderCtrlEx la CListCtrlEx

Post by Ovidiu Cucu » 16 Dec 2010, 18:36

Controlul (fereastra) header pentru un listview nu trebuie creat prin program (cu CHeaderCtrl::Create or whatever).
Controlul header exita in momentul apelarii CListCtrl::PreSubclassWindow.
Pentru amandua, conditia este ca listview-ul sa fie de tip "report".
A subclasa un control inseamna pur si simplu a-i schimba functia fereastra default cu una definita in aplicatie.

In Qt o fi altfel, mai obiectual, mai bengos, nu stiu. Aici suntem in MFC si suntem mai aproape de "trivial Windows programming". :)
Am atasat un mic demo de listview cu header custom.

Andreas, te rog sa-mi spui daca ceva ma trebuie creat, daca se subclaseaza gresit, daca se pierde vreun mesaj etc.
Nimeni nu-i perfect deci poate sa greseasca. ;)
HeaderTest.zip
(14.68 KiB) Downloaded 302 times

User avatar
Andreas
Membru
Membru
Posts: 117
Joined: 09 Nov 2008, 12:13
Judet: Timiş
Location: Timisoara

Re: Atasare CHeaderCtrlEx la CListCtrlEx

Post by Andreas » 16 Dec 2010, 23:33

@Ovidiu:hmm...eu vorbeam despre crearea lui CListCtrl, nu despre CHeaderCtrl

Code: Select all

Andreas, te rog sa-mi spui daca ceva ma trebuie creat, daca se subclaseaza gresit, daca se pierde vreun mesaj etc. 
asta e o ironie pe care ti-o trec cu vederea...mai sunt si altele dar chiar nu conteaza

despre subclsarea unui control "chiar in MFC": sunt convins ca o folosesti perfect, dar explicatia ta nu este completa
despre ce ziceam eu:CWnd::SubclassWindow afirma celasi lucru

depsre Qt(Java, C#,alte abordari) etc...se pare ca prea mult MFC strica :)

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

Re: Atasare CHeaderCtrlEx la CListCtrlEx

Post by Ovidiu Cucu » 17 Dec 2010, 12:39

Andreas wrote:explicatia ta nu este completa
despre ce ziceam eu:CWnd::SubclassWindow afirma celasi lucru
Ar fi trebuit sa se cheme CWnd::AttachAndSubclassWindow. :biggrin: ;)

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

Re: Atasare CHeaderCtrlEx la CListCtrlEx

Post by mesajflaviu » 17 Dec 2010, 14:02

Andreas wrote:cum creezi controlul lista? din resursa sau manual, cu Create? in al doilea caz fereastra control header nu exista la momentul apelarii PreSubclassWindow de catre MFC; in primul caz, crearea din resursa ca in exemplu de pe net, fereastra control header este tot timpul creata...
si mai o chestie, cred ca faci confuzie cu ce la cine se ataseaza?...
e clar ca nu atasez bine CHeaderCtrlEx de CListCtrlEx , dar intrebarea este , cum fac asta ?
nu, in cazul tau atasezi obiectul header creat de framework la obiectul CHeaderCtrlEx, adica m_wndHeader, astfel incat toate mesajele transmise la cel din framework trec prin acesta; aceasta subclsare dinamica poate fi inteleasa ca un obiect-filtru de mesaje a unui obiect preexistent, de altfel asa si este denumit in alte framework-uri gen Qt, "adevarata" subclasare fiind cea statica cum e cazul lui CListCrl din exemplul tau(doar un obiect de genul asta exista la runtime, cu avantajul metodelor adaugate)
Lista o creez manual , cu Create :

Code: Select all

int CTestList4View::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if(CListView::OnCreate(lpCreateStruct) == -1)return -1;

	// TODO: Add your specialized creation code here

	DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_TABSTOP | CS_DBLCLKS | LVS_REPORT;

	BOOL bResult = m_List1.Create(dwStyle,CRect(0,0,0,0),this,IDC_LIST1);

	return (bResult ? 0 : -1);

//	return 0;
}
si

Code: Select all

void CTestList4View::OnSize(UINT nType, int cx, int cy) 
{
	CListView::OnSize(nType, cx, cy);

	// TODO: Add your message handler code here

	if(::IsWindow(m_List1.m_hWnd))m_List1.MoveWindow(0,0,cx,cy,TRUE);
}
dar , din acest motiv :?: , daca incerc sa creez ( tot cu Create ) controlul lista facut de Ovidiu , nu isi face pe deplin datoria ?
Attachments
TestList4.rar
(84.69 KiB) Downloaded 281 times

User avatar
Andreas
Membru
Membru
Posts: 117
Joined: 09 Nov 2008, 12:13
Judet: Timiş
Location: Timisoara

Re: Atasare CHeaderCtrlEx la CListCtrlEx

Post by Andreas » 17 Dec 2010, 15:28

exemplul tau confirma ce ziceam depsre CListCtrl, din resursa sau creat: daca e din resursa MFC creeaza automat si headerul, altfel acesta nu este creat
exemplul lui Ovidiu merge cu resursa list view; al tau nu merge, e suficient sa urmaresti handle-ul de fereastra pentru header in PreSubclassWindow. Daca puneai ASSERT pe el sigur tipa.
De fapt MFC foloseste acelasi mecanism de subclasare a controalelor, ca cel pus la dispozitie programatorului. Pentru asta uita-te in DDX_Control, unde mfc face uz de acesta:

Code: Select all

//...\MFC\SRC\DLGDATA.CPP
/////////////////////////////////////////////////////////////////////////////
// Special DDX_ proc for subclassing controls

void AFXAPI DDX_Control(CDataExchange* pDX, int nIDC, CWnd& rControl)
{
	if (rControl.m_hWnd == NULL)    // not subclassed yet
	{
		ASSERT(!pDX->m_bSaveAndValidate);

		HWND hWndCtrl = pDX->PrepareCtrl(nIDC);

		if (!rControl.SubclassWindow(hWndCtrl))
		{
			ASSERT(FALSE);      // possibly trying to subclass twice?
			AfxThrowNotSupportedException();
		}
#ifndef _AFX_NO_OCC_SUPPORT
		else
		{
			// If the control has reparented itself (e.g., invisible control),
			// make sure that the CWnd gets properly wired to its control site.
			if (pDX->m_pDlgWnd->m_hWnd != ::GetParent(rControl.m_hWnd))
				rControl.AttachControlSite(pDX->m_pDlgWnd);
		}
#endif //!_AFX_NO_OCC_SUPPORT

	}
}
cred ca exista totusi o solutie pentru crearea dinamica a unui list control...mai sapam

o alta chestie ce am observat la proeictul tau: folosesti o clasa view derivata din CListView(care incapsuleaza un CListCtrl), care ar fi suficienta pentru arhitectura document-view, dar il folosesti doar pe post de resizer pentru controlul lista custom al tau. Mi se pare redundant...

User avatar
Andreas
Membru
Membru
Posts: 117
Joined: 09 Nov 2008, 12:13
Judet: Timiş
Location: Timisoara

Re: Atasare CHeaderCtrlEx la CListCtrlEx

Post by Andreas » 17 Dec 2010, 16:19

da, trebuie sa fac ceva rectificari: CListCtrl::Create se comporta normal, adica creeaza si header-ul, dar se pare ca dupa apelul la PreSubclassWindow; MFC, cum am zis, face subclsarea in DDX_Control cand totul este deja creat(oricum aceasta subclasare nu se refera la CHeaderCtrl, ci la CListCtrl insusi pentru data exchange); oricum ce am inteles este ca in CListCtrl::Create se face apel la PreSubclassWindow inainte de crearea CHeaderCtrl...
prin urmare trebuie sa facem un apel in plus dupa Create:
1. public:
virtual void PreSubclassWindow();
2. BOOL bResult = m_List1.Create(dwStyle,CRect(0,0,100,100),this,0);
m_List1.PreSubclassWindow();

P.S. sau fa subclasarea in alta metoda...

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

Re: Atasare CHeaderCtrlEx la CListCtrlEx

Post by Ovidiu Cucu » 17 Dec 2010, 17:12

Ca sa completez ce-a spus Andreas
Mi se pare redundant...
Puteai sa pui lista intr-un CTreeView ca tot aia era. :)
Ai doua controale unul peste altul ca nu mai intelege nimeni (nici mcar MFC-ul ;)) ce-i pe acolo.
Eu zic ca, fara alte carpeli si giumbuslucuri, cel mai simplu ar fi sa-l pui intr-un CFormView si-ai scapat de dureri de cap.

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

Re: Atasare CHeaderCtrlEx la CListCtrlEx

Post by mesajflaviu » 17 Dec 2010, 17:42

Ovidiu Cucu wrote:Ca sa completez ce-a spus Andreas
Mi se pare redundant...
Puteai sa pui lista intr-un CTreeView ca tot aia era. :)
Ai doua controale unul peste altul ca nu mai intelege nimeni (nici mcar MFC-ul ;)) ce-i pe acolo.
Eu zic ca, fara alte carpeli si giumbuslucuri, cel mai simplu ar fi sa-l pui intr-un CFormView si-ai scapat de dureri de cap.
Exact , nu conteaza din clasa provine CMyView ...
Andreas wrote:da, trebuie sa fac ceva rectificari: CListCtrl::Create se comporta normal, adica creeaza si header-ul, dar se pare ca dupa apelul la PreSubclassWindow; MFC, cum am zis, face subclsarea in DDX_Control cand totul este deja creat(oricum aceasta subclasare nu se refera la CHeaderCtrl, ci la CListCtrl insusi pentru data exchange); oricum ce am inteles este ca in CListCtrl::Create se face apel la PreSubclassWindow inainte de crearea CHeaderCtrl...
prin urmare trebuie sa facem un apel in plus dupa Create:
1. public:
virtual void PreSubclassWindow();
2. BOOL bResult = m_List1.Create(dwStyle,CRect(0,0,100,100),this,0);
m_List1.PreSubclassWindow();

P.S. sau fa subclasarea in alta metoda...
Merge acum controlul cu o mentiune : PreSubclassWindow() nu trebuie declarata protected , ca sa poata fi accesata de m_List1 , sau asa cum ai zis , apelata cu o metoda publica a controlului .
Acum sa iau la pila CHeaderCtrlEx si CListCtrlEx ...

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

Re: Atasare CHeaderCtrlEx la CListCtrlEx

Post by Ovidiu Cucu » 17 Dec 2010, 17:58

mesajflaviu wrote: Merge acum controlul cu o mentiune : PreSubclassWindow() nu trebuie declarata protected , ca sa poata fi accesata de m_List1 , sau asa cum ai zis , apelata cu o metoda publica a controlului .
Acum sa iau la pila CHeaderCtrlEx si CListCtrlEx ...
Punem pariu ca o sa trebuiasca sa iei mai multe la pila, inclusiv CTestList4View-ul?
De ce nu incerci cu un CFormView?
Pui lista in resurse, ii setezi tipul "report" si-ai scapat de tras la pila.

User avatar
Andreas
Membru
Membru
Posts: 117
Joined: 09 Nov 2008, 12:13
Judet: Timiş
Location: Timisoara

Re: Atasare CHeaderCtrlEx la CListCtrlEx

Post by Andreas » 17 Dec 2010, 18:11

-am specificat "in scris" ca PreSubclassWindow trebuie sa fie "public" ;)
-cum a zis Ovidiu, e "clasica" o aplicatie document-view SDI, cu clasa view derivata din CFormView cand vrei alte controale in GUI

cum era bancul ala cu avionul : "...tot tanc a iesit, dar l-am luat la pila"? ...glumesc, e vineri :)

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

Re: Atasare CHeaderCtrlEx la CListCtrlEx

Post by mesajflaviu » 18 Dec 2010, 10:57

Ovidiu Cucu wrote:
mesajflaviu wrote: Merge acum controlul cu o mentiune : PreSubclassWindow() nu trebuie declarata protected , ca sa poata fi accesata de m_List1 , sau asa cum ai zis , apelata cu o metoda publica a controlului .
Acum sa iau la pila CHeaderCtrlEx si CListCtrlEx ...
Punem pariu ca o sa trebuiasca sa iei mai multe la pila, inclusiv CTestList4View-ul?
De ce nu incerci cu un CFormView?
Pui lista in resurse, ii setezi tipul "report" si-ai scapat de tras la pila.
Se vede treaba ca vreau sa deschid conserva prin partea opusa cheitei ... cheita e pentru cei care n-au brisca ! :biggrin:

Pana la urma am rezolvat controlul , cu ajutorul vostru , bineinteles , pentru care va multumesc frumos !!! :whorship:

Dau bere , si nu virtuala ! Nu aveti drum prin Cluj ? ( Ca prin Turda sigur nu aveti , acuma ca e gata autostrada ... ) :beerhug:
Attachments
TestList3.rar
(149.55 KiB) Downloaded 266 times

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

Re: Atasare CHeaderCtrlEx la CListCtrlEx

Post by Ovidiu Cucu » 18 Dec 2010, 13:02

mesajflaviu wrote: Nu aveti drum prin Cluj ?
Dupa cum spuneam si eu si Andreas, CListView nu face acolo decat sa incurce.
Deriveaza direct din CView si-atunci poate iau "trenu foamei" si trag o fuga la Cluj... :D

Post Reply