ERLEDIGT
NEIN
NEIN
ANTWORTEN
36
36
ZUGRIFFE
6460
6460
EMPFEHLEN
-
17.03.04 11:15 #1
- Registriert seit
- Nov 2003
- Ort
- Hamburg
- Beiträge
- 157
Hallo,
weiß jemand, wie man ein Listenelement sortieren lassen kann, wenn man auf den Titel einer Spalte klickt?
Ich hab bisher einiges gesucht und gefunden aber hab das nicht so richtig verwenden können bzw. teilweise nicht verstanden...
Ist es dann auch möglich, das die benachbarten Spalten sich so mitändern, das jede Zeile in sich gleich bleibt?
-
17.03.04 13:39 #2
- Registriert seit
- Jul 2003
- Ort
- Duisburg (NRW)
- Beiträge
- 1.788
Ja, du musst CListCtrl::SortItems() verwenden. Signatur ist folgende:
BOOL SortItems( PFNLVCOMPARE pfnCompare, DWORD dwData );
pfnCompare ist eine Vergleichsfunktion, die zwei Items vergleicht. Die musst du zu Verfügung stellen und als Pointer übergeben:
pfnCompare
Address of the application-defined comparison function. The comparison function is called during the sort operation each time the relative order of two list items needs to be compared. The comparison function must be either a static member of a class or a stand alone function that is not a member of any class.
The comparison function has the following form:
int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
Chor: "Wir sind der Chor, und wir stimmen zu. Wir stimmen zu, wir stimmen zu, wir stimmen zu."
-
18.03.04 09:59 #3
- Registriert seit
- Nov 2003
- Ort
- Hamburg
- Beiträge
- 157
Ähm irgendwie steig ich da noch nicht 100% durch.
Erstmal wie mache ich es denn, das etwas passiert, wenn man auf den Titel einer Spalte in meinem Listenelement klickt?
Und muss cih dann zwei Funktionen erstellen, die sortitem und die callback und was schireben cih da für parameter rein bzw was ruft wen auf?
Sorry aber noch versteh ich das nicht wirklich...
-
18.03.04 11:29 #4
- Registriert seit
- Jul 2003
- Ort
- Duisburg (NRW)
- Beiträge
- 1.788
Das ist alles ganz schön kompliziert. Da ich selber noch nicht mit der SortItemsfunktion gearbeitet habe, habe ich mich drangesetzt, es mal auszuprobieren.
Zunächst mal: Um eine Reaktion auf den Klick auf den Spaltenheader zu erhalten, musst du dir vom Classwizard folgenden Messagehandler reinmachen lassen: OnColumnclick... mit der Message LVN_COLUMNCLICK. Kriegst du das hin?
Ich habe das mal gemacht und zum Testen folgenden Code verwendet:
An die Vergleichsfunktion werden die Itemdatas übergeben und zum Vergleich herangezogen. Bei mir hatte ich testweise die Items 0...n mit den Itemdatas 0...n versehen (mit SetItemData). Obiger Code dreht dann die Reihenfolge der Zeilen um.Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
int CALLBACK sortitems( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort ) { TRACE( "%d, %d\n", lParam1, lParam2 ); if ( lParam1 < lParam2 ) return +1; if ( lParam1 > lParam2 ) return -1; return 0; } void CSomeStatisticsDlg::OnColumnclickListResult(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; MessageBox( "OnColumnclickListResult" ); m_ctlListResult.SortItems( sortitems, 0 ); *pResult = 0; }
Ist das soweit verständlich? Wenn du genauer sagen kannst, wonach du sortieren willst, kann ich vielleicht einen Vorschlag machen, wie du das realisieren kannst.Chor: "Wir sind der Chor, und wir stimmen zu. Wir stimmen zu, wir stimmen zu, wir stimmen zu."
-
18.03.04 11:48 #5
- Registriert seit
- Nov 2003
- Ort
- Hamburg
- Beiträge
- 157
HI,
also ich habe den Messagehandler für den Spaltenkopf angelegt, sieht bei mir so aus:
Code :1 2 3 4 5 6 7 8 9 10
void CAccess_testDlg::OnColumnclickList(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; // TODO: Code für die Behandlungsroutine der Steuerelement-Benachrichtigung hier einfügen MessageBox( "OnColumnclickListResult" ); m_ctlList.SortItems( sortitems, 0 ); *pResult = 0; }
Wenn cih nun die CALLBCK FUnktion anlegen will mit Hilfe der Funktion um Mebmber-Funktionen hinzuzufügen erhalte ich allerdings dieses:
Code :1 2 3 4 5 6 7 8
int CALLBACK CAccess_testDlg::sortitems(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) { TRACE( "%d, %d\n", lParam1, lParam2 ); if ( lParam1 < lParam2 ) return +1; if ( lParam1 > lParam2 ) return -1; return 0; }
Und dann gibt er mir noch die Fehlermeldung aus, das:
Also ich habe ein Listenelement mit 5 Spalten und in denen steht Text, nun möchte ich bei klicken auf den Spaltenkopf das die Texte alphabetisch sortiert werde in der angeklickten Spalte aber sich auch gleichzeitig die Zeilen richtig mitsortieren, so das die Logik richtig bleibt zwischen den Spalten...Code :1 2
error C2664: 'SortItems' : Konvertierung des Parameters 1 von 'int (long,long,long)' in 'int (__stdcall *)(long,long,long)' nicht moeglich Keine Funktion mit diesem Namen im Gueltigkeitsbereich stimmt mit dem Zieltyp ueberein
-
18.03.04 12:30 #6
- Registriert seit
- Jul 2003
- Ort
- Duisburg (NRW)
- Beiträge
- 1.788
Das darf keine Memberfunktion sein. Richtig ist int CALLBACK sortitems(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) .int CALLBACK CAccess_testDlg::sortitems(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
Wegen unterschiedlicher Spalten: Der Columnclick gibt dir einen Pointer auf eine Struktur, die weitere Infos beinhaltet.
Für dich ist wahrscheinlich iSubItem interessant - darin sollte die Spalte stehen.Code :1 2 3 4 5 6 7 8 9 10
typedef struct tagNMLISTVIEW{ NMHDR hdr; int iItem; int iSubItem; UINT uNewState; UINT uOldState; UINT uChanged; POINT ptAction; LPARAM lParam; } NMLISTVIEW, FAR *LPNMLISTVIEW;
Du kommst folgendermassen dran:Code :1
int iColumn = pNMListView->iSubItem; //ohne Gewähr - keine Zeit zum Testen.
Chor: "Wir sind der Chor, und wir stimmen zu. Wir stimmen zu, wir stimmen zu, wir stimmen zu."
-
18.03.04 12:58 #7
- Registriert seit
- Nov 2003
- Ort
- Hamburg
- Beiträge
- 157
So nun funktioniert das erstmal, dass ich die Spaltennummer herausbekomme.
Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
int CALLBACK sortitems( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort ) { TRACE( "%d, %d\n", lParam1, lParam2 ); if ( lParam1 < lParam2 ) return +1; if ( lParam1 > lParam2 ) return -1; return 0; } void CAccess_testDlg::OnColumnclickList(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; // TODO: Code für die Behandlungsroutine der Steuerelement-Benachrichtigung hier einfügen int iColumn = pNMListView->iSubItem; CString spaltennummer; mensch.Format("%d", iColumn+1); MessageBox( spaltennummer ); m_ctlList.SortItems( sortitems, 0 ); *pResult = 0; }
Abernun gibt er mir in der Messagebox nur die Spaltennumemr aus, aber sortiert nichts sondern gibt im AUsgabefenster 15 mal "0, 0" und das obwohl nur 10 Zeilen vorhanden sind.
Hast du noch weitere Tipps?
Hab nämlich nicht ganz verstanden, was ich mit der Struktur nun anfangen soll....
-
18.03.04 13:05 #8
- Registriert seit
- Jul 2003
- Ort
- Duisburg (NRW)
- Beiträge
- 1.788
Ich zitiere mich noch mal selbst:
Meine Sortierfunktion war nur ein Test. Es ist klar, dass da so nix Sinnvolles bei rauskommt, wenn alle ItemDatas 0 sind. Jetzt musst du dir überlegen, wonach du sortieren willst. Vorschläge? Gib mal ein Beispiel für den Inhalt der Tabelle.An die Vergleichsfunktion werden die Itemdatas übergeben und zum Vergleich herangezogen. Bei mir hatte ich testweise die Items 0...n mit den Itemdatas 0...n versehen (mit SetItemData). Obiger Code dreht dann die Reihenfolge der Zeilen um.Chor: "Wir sind der Chor, und wir stimmen zu. Wir stimmen zu, wir stimmen zu, wir stimmen zu."
-
18.03.04 13:10 #9
- Registriert seit
- Nov 2003
- Ort
- Hamburg
- Beiträge
- 157
Was sind denn ItemDatas, ist das nicht der sichtbare text?
Also ich habe eine Liste, in der mehrere Spalten sind. 1. Spalte heißt "ID" und beinhaltet Zahlen, zweite Spalte heißt "Titel" und beinhaltet Titel von Büchern, 3. Spalte heißt "Autor" udn beinhaltet die Namen der Autoren etc.
Es ist also eine Bücherliste.
War das so verständlich?
-
18.03.04 13:28 #10
- Registriert seit
- Jul 2003
- Ort
- Duisburg (NRW)
- Beiträge
- 1.788
Jedes Item hat noch eine Art Userdata. Das sind 4 Byte, die nicht verwendet werden. Der User kann hier zusätzliche infos reinschreiben, wie zum Beispiel eine ID oder auch - was ich häufiger brauche - einen Zeiger auf weitere Daten.Was sind denn ItemDatas, ist das nicht der sichtbare text?
Lies mal das hier: http://www.tutorials.de/tutorials149542.htmlChor: "Wir sind der Chor, und wir stimmen zu. Wir stimmen zu, wir stimmen zu, wir stimmen zu."
-
18.03.04 13:40 #11
- Registriert seit
- Nov 2003
- Ort
- Hamburg
- Beiträge
- 157
Also ich habe nun
data wird von 0 an hochgezählt so oft wie es einträge gibt.Code :1 2 3 4 5 6 7
m_ctlList.InsertItem(iZeile, sBuch_ID); m_ctlList.SetItemText(iZeile, 1, m_strTitel); m_ctlList.SetItemData(data, data); m_ctlList.SetItemText(iZeile, 2, m_strAutor); m_ctlList.SetItemText(iZeile, 3, m_strJahr); m_ctlList.SetItemText(iZeile, 4, m_strVerlag); m_ctlList.SetItemText(iZeile, 5, m_strIsbn);
nun sortiert es auch, aber egal welche spalte ich anklicke es wird imemr die erste Spalte "ID" sortiert und nicht die anderen, die eigentlich sortiert werden sollen.
Wie mache cih das, dass er es für die jeweilige Spalte macht?
-
18.03.04 14:27 #12
- Registriert seit
- Jul 2003
- Ort
- Duisburg (NRW)
- Beiträge
- 1.788
Eigentlich sollten alle Spalten mitsortiert werden, aber nach dem Itemdata, was bei dir der Spalte 0 (ganz links) entspricht, oder?nun sortiert es auch, aber egal welche spalte ich anklicke es wird imemr die erste Spalte "ID" sortiert und nicht die anderen, die eigentlich sortiert werden sollen.
Hier eine mögliche Lösung für ein Sortieren nach Spalte 1:
Da gibt es noch Einiges für dich umzubauen, aber das sollte für dich kein Problem mehr sein.Code :1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
//- Vergleichsfunktion, nimmt an, dass die Itemdatas Pointer auf CStrings enthalten int CALLBACK SortItemsWithString( LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort ) { //- irgendwas 0? if ( lParam1 == 0 || lParam2 == 0 ) return 0; //-die Strings rausholen CString* pA = (CString*)lParam1; CString* pB = (CString*)lParam2; //- vergleichen und Resultat zurückgeben return pA->Compare( LPCTSTR( *pB ) ); } void CSomeStatisticsDlg::OnColumnclickListResult(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; int subitem = 1; // BAUSTELLE! dies anpassen - ist so nur für Spalte 1 int i = 0; //- "Itemdatas mit Text füllen" for ( i = 0; i < m_ctlListResult.GetItemCount(); ++i ) { CString strTemp = m_ctlListResult.GetItemText( i, subitem ); m_ctlListResult.SetItemData( i, (DWORD)( new CString( strTemp ) ) ); } //- in jedem Itemdata steht jetzt ein Pointer auf einen String, //- nach dem sortiert werden kann //- sortieren m_ctlListResult.SortItems( SortItemsWithString, 0 ); //- Itemdatas wieder freigeben for ( i = 0; i < m_ctlListResult.GetItemCount(); ++i ) { CString* pA = (CString*) m_ctlListResult.GetItemData( i ); delete pA; m_ctlListResult.SetItemData( i, 0 ); } *pResult = 0; }Geändert von Kachelator (18.03.04 um 14:39 Uhr)
Chor: "Wir sind der Chor, und wir stimmen zu. Wir stimmen zu, wir stimmen zu, wir stimmen zu."
-
18.03.04 15:24 #13
- Registriert seit
- Nov 2003
- Ort
- Hamburg
- Beiträge
- 157
Das ist genial, es klappt (fast) perfekt.
Ich hab noch eine kleine Änderung vorgenommen, weil er sonst erst alle Gro0buchstaben sortiert und danach alle kleinen und man so dann sozusagen zweimal das Alphabet stehen hat.
Änderung:
Code :1 2 3 4 5 6 7
//- "Itemdatas mit Text füllen" for ( i = 0; i < m_ctlList.GetItemCount(); ++i ) { CString strTemp = m_ctlList.GetItemText( i, subitem ); strTemp.MakeLower(); m_ctlList.SetItemData( i, (DWORD)( new CString( strTemp ) ) ); }
Und noch ein Änderung damit es für jede Spalte funktioniert
Code :1 2 3 4 5 6 7 8 9 10
void CAccess_testDlg::OnColumnclickList(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; int iSpalte = pNMListView->iSubItem; int subitem = iSpalte; // BAUSTELLE! dies anpassen - ist so nur für Spalte 1 int i = 0; //- "Itemdatas mit Text füllen" for ( i = 0; i < m_ctlList.GetItemCount(); ++i )
Allerdings eine Kleinigkeit bleibt, in der "ID" Spalte sind ja nur zahlen vorhanden, Und nun sortiert er so, dass erst alle Zahlen kommen, die mit eins anfangen und dann die mit 2 anfangen etc, also ist eine 2 hinter z.B. einer 13 Also der Sortiert dann so:
1
11
12
13
..
2
21
22
..
3
Gibt es da noch einen kleinen Trick?
Man cih frag dir hier Löcher in den Bauch odeR? *gg+
P.S.: Hätte sogar noch eine zweite Frage, wie stellt man es an, das es wenn es sortiert ist, bei einem weietren Klick sich andersherum sortiert?
-
18.03.04 16:29 #14
- Registriert seit
- Jul 2003
- Ort
- Duisburg (NRW)
- Beiträge
- 1.788
Verwende einfach CString::CompareNoCase()!Ich hab noch eine kleine Änderung vorgenommen, weil er sonst erst alle Gro0buchstaben sortiert und danach alle kleinen und man so dann sozusagen zweimal das Alphabet stehen hat.
[...]
strTemp.MakeLower();
Ja, schreib die führenden Nullen mit rein (also aus "1" wird "01" oder "0001" usw., je nachdem, wieviele Stellen nötig sind).1
11
12
13
..
2
21
22
..
3
[...]
Gibt es da noch einen kleinen Trick?
Ja.Man cih frag dir hier Löcher in den Bauch odeR?
Merk dir für jede Spalte, in welche Richtung du zuletzt sortiert hast. Ein Bool würde dafür reichen. Du könntest zum Beispiel ein Array dafür verwenden.P.S.: Hätte sogar noch eine zweite Frage, wie stellt man es an, das es wenn es sortiert ist, bei einem weietren Klick sich andersherum sortiert?
Aber man sagt, dass auch Spalten ein "ItemData" haben können...
(Tipp: CListCtrl::GetHeaderCtrl(), CHeaderCtrl, HDITEM, lParam ).
Geändert von Kachelator (18.03.04 um 16:37 Uhr)
Chor: "Wir sind der Chor, und wir stimmen zu. Wir stimmen zu, wir stimmen zu, wir stimmen zu."
-
Ich bins mal wieder

Habe mir diese "Diskussion" mal durchgelesen, genau so etwas brauchte ich - danke!
Zu dem wollte ich noch wissen, wie ich den namen (caption, text, oder wie auch immer...
) von der ersten spalte meines liestview rausbekomme 
Das hilft mir beim sortieren mit deinem Tipp:
Bloß, wenn ich einen Text habe, dann kann ich keine Nullen dranhängen, sonst sortiert er logischerweise nich richtig.Ja, schreib die führenden Nullen mit rein (also aus "1" wird "01" oder "0001" usw., je nachdem, wieviele Stellen nötig sind).
Deshalb wollte ich über die Caption des Columns abfragen, ob die Spalte Zahlen oder Text beinhaltet (Zahlen im Sinne von ID, Text, ja... Text halt
)
mfG
MAN
Ähnliche Themen
-
IE Listenelement Lücke
Von dezerver im Forum CSSAntworten: 4Letzter Beitrag: 19.11.07, 12:53 -
Listenelement IE und FF
Von Luna1000 im Forum CSSAntworten: 2Letzter Beitrag: 11.09.07, 16:55 -
Text im Listenelement
Von udo_the_man im Forum HTML & XHTMLAntworten: 1Letzter Beitrag: 22.04.06, 21:32 -
Hintergrund für Listenelement
Von ares99kk im Forum CSSAntworten: 6Letzter Beitrag: 09.12.04, 10:05 -
Listenelement, Farbe, checkbox
Von jma im Forum VisualStudio & MFCAntworten: 1Letzter Beitrag: 22.03.04, 12:22





Zitieren
Login






