CListCtrl mit Checkbox
-
Hallo Leute kann ich ein CListCtrl so gestalten das in dr ersten Spalte jeweils eine Checkbox ist? Und kann man dann beim verlassen vom dialog
abprüfen welche Zeile gecheckz ist? Gibt es irgendwo Beispiele?Gruß,
Stalin
-
Ja geht, du musst dir eine eigene Klasse von ClistCtrl ableiten.
Ich hab source zu hause, wie ich es gemacht habe, sobald
ich zuhause bin schreib ich mal ein how to...Devil
-
das wäre echt nett von dir.
Danke!
-
Supi!
Ich schließe mich voller Erwartung mit einem Danke im Voraus an.
-
So, hier steht jetzt wie es geht *g*
Also ich hab lange Gesucht, und festgestellt, das es da 2 Möglichkeiten gibt:
a) Man subclassed das CListCtrl und zeichnet das ding in der Klasse selber von Hand.
Diese Methode findet man überall bei Codeguru und Co, ist aber finde ich etwas umständlich
für ne einfache Checkbox.
b) Man subclassed das CListCtrl und nimmt für die Checkbox 2 Bitmaps oder Icons.Lösung a steht bei Codeguru (viel spass :D), Lösung b steht nun hier:
Als erstes brauchen wir einen weg den Status der Checkbox zu speichern, dafür
legen wir uns eine Klasse CData an:class CData { public: bool GetA()const{return a;}; bool GetB()const{return b;}; string GetS()const{return s;}; bool a,b; string s; CData(string S,bool A, bool B):a(A),b(B),s(S){}; CData(const CData ©) { s = copy.GetS(); a = copy.GetA(); b = copy.GetB(); }; virtual ~CData(); };
Diese enthält jetzt für jede Checkbox eine variable vom Typ bool.
Und auch noch n string, damit das Beispiel was besser aussieht(spielt aber eigentlich keine Rolle)
So nun leiten wir uns unsere Klasse von CListCtrl ab:
class CCheckListCtrl : public CListCtrl { vector<CData> data; CImageList list; // Konstruktion public: CCheckListCtrl(); void Update(); void InsertData(CData Data); void Init(); virtual ~CCheckListCtrl(); protected: //{{AFX_MSG(CCheckListCtrl) afx_msg void OnClick(NMHDR* pNMHDR, LRESULT* pResult); //}}AFX_MSG DECLARE_MESSAGE_MAP() };
So nun zur Implementation:
Die Klasse enthält einen Vector, der aus CData objekten besteht,
jede Zeile hat also sein eigenes Objekt. (Hier kann auch eine Referenz genommen werden,
dann liegen die Daten _nicht_ in der ListCtrlklasse).Die Funktion Init() legt das CListCtrl an, und dient dem Zweck das
man das ganze nicht in die OnInitDialog reinhauen muss. (ist also nicht zwingend)void CCheckListCtrl::Init() { //Hier ist der eigentliche Trick: LVS_EX_SUBITEMIMAGES erlaubt es in den SubItems mit images rumzumalen... ListView_SetExtendedListViewStyle(m_hWnd,/* LVS_EX_CHECKBOXES |*/LVS_EX_SUBITEMIMAGES| LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES); InsertColumn ( 0, "Name", LVCFMT_LEFT, 80 ); InsertColumn ( 1, "Checkbox1", LVCFMT_LEFT, 80 ); InsertColumn ( 2, "Checkbox2", LVCFMT_LEFT, 80 ); list.Create(16,16,ILC_COLOR,1,0); list.Add(AfxGetApp()->LoadIcon(IDI_CHECK));//Ich lade Icons, man könnte aber auch bitmaps nehmen list.Add(AfxGetApp()->LoadIcon(IDI_CHECKED)); SetImageList(&list,LVSIL_SMALL); }
InsertData(CData Data)
Hier werden neue CData Objekte eingefügt... (Mit dieser Funktion befüllt man die Liste)void CCheckListCtrl::InsertData(CData Data) { data.push_back(Data);//element in den vector pushen InsertItem(GetItemCount(),data[GetItemCount()].s.c_str()); if(data[GetItemCount()-1].a) SetItem(GetItemCount()-1,1,LVIF_IMAGE,"",1,0,0,0); else SetItem(GetItemCount()-1,1,LVIF_IMAGE,"",0,0,0,0); if(data[GetItemCount()-1].b) SetItem(GetItemCount()-1,2,LVIF_IMAGE,"",1,0,0,0); else SetItem(GetItemCount()-1,2,LVIF_IMAGE,"",0,0,0,0); }
Update Aktualisiert die Liste
void CCheckListCtrl::Update() { int size = data.size(); DeleteAllItems(); for(int i =0; i < size; i++) { InsertItem(i,data[i].s.c_str()); if(data[i].a) SetItem(i,1,LVIF_IMAGE,"",1,0,0,0); else SetItem(i,1,LVIF_IMAGE,"",0,0,0,0); if(data[i].b) SetItem(i,2,LVIF_IMAGE,"",1,0,0,0); else SetItem(i,2,LVIF_IMAGE,"",0,0,0,0); } }
Und die eigentlichen Checkboxen werden in der OnClick behandelt:
void CCheckListCtrl::OnClick(NMHDR* pNMHDR, LRESULT* pResult) { LPNMITEMACTIVATE lpNMItem = (LPNMITEMACTIVATE) pNMHDR; if(lpNMItem->iItem > -1 && lpNMItem->iSubItem > -1) { switch(lpNMItem->iSubItem) { case 1: if(data[lpNMItem->iItem].a) { SetItem(lpNMItem->iItem,1,LVIF_IMAGE,"",0,0,0,0); data[lpNMItem->iItem].a=false; } else { SetItem(lpNMItem->iItem,1,LVIF_IMAGE,"",1,0,0,0); data[lpNMItem->iItem].a=true; } break; case 2: if(data[lpNMItem->iItem].b) { SetItem(lpNMItem->iItem,2,LVIF_IMAGE,"",0,0,0,0); data[lpNMItem->iItem].b=false; } else { SetItem(lpNMItem->iItem,2,LVIF_IMAGE,"",1,0,0,0); data[lpNMItem->iItem].b=true; } break; } } *pResult = 0; }
So, das müsst alles gewesen sein. Evtl. in die FAQ verschieben
-
In der ersten Spalte eine Checkbox
SetExtendedStyle
ist eine Memberfunktion der CListCtrl
Einfach in derr MSDN nachschauen dann braucht man auch keine eigene Klasse
-
Unix-Tom schrieb:
In der ersten Spalte eine Checkbox
Das machts aber auch nur für die erstes Spalte möglich...
Devil
-
Wow, da hab ich jetzt aber was zu lesen.
Dankeschön.
-
Danke. Werde es mal ausprobieren.
Welche Icons nimmst du da?
Sind die schon mit dem Studio mitgeliefert?
-
äh, nö, selbst gezeichnet.
Schwarzes Recheck halt, welches noch mal n graues dring hat,
einmal mit haken, einmal ohneDevil