SortItems und CompareFunction



  • Schlage mich gerade mit der SortItems Funktion rum von CListCtrl.

    Füge zunächst ein Element hinzu zu meinem ListCtrl.

    CString* pstr = new CString(iter->first);
    LPCTSTR psz = *pstr;
    int itemInserted = m_lcMy.InsertItem(LVIF_PARAM | LVIF_TEXT, i, psz, 0, 0, 0, reinterpret_cast<LPARAM>(pstr));
    

    Danach füge ich über SetItem mehrere Spalten hinzu: hier mal ein Beispiel:

    CString* pdir = new CString(direction);
    LPCTSTR psdir = *pdir;
    m_lcGroupVars.SetItem(itemInserted,1, LVIF_IMAGE | LVIF_TEXT, psdir, i+1, 0, 0, reinterpret_cast<LPARAM>(psdir));
    

    (einfach mal ein Stück Code rauskopiert)

    Beim Klick auf eine Spaltenüberschrift wird dann unter anderem SortItems aufgerufen. Und meine Compare Funktion übergeben.

    Hier liegt nun mein Problem. Über die Paramter lParam1 und lParam2 gelange ich an die Werte die Spalte 1. Aber wie erhalte ich nun die Werte der anderen Spalten. Wenn ich doch auf Spalte 2 klicke brauche ich zum Sortieren auch die Werte von Spalte 2.



  • Habe ich noch was unklar beschrieben. Werden noch mehr Informationen benötigt?


  • Mod

    Schau Dir SortItemsEx an
    http://msdn.microsoft.com/de-de/library/bb387110.aspx

    Das ist wesentlich einfacher und effektiver.

    Ansonsten bietet sich folgendes an.
    Mit SetItem setzt Du einen Zeiger auf die gesamte Datenstruktur, die letzten Endes in dem ListCtrl abgespeichert wird. Dann kannst Du diesen Zeiger casten und entsprechend alle Daten verwenden.
    Die Daten doppelt zu speichern ist unsinnig.

    BTW: Warum nimmst Du nicht gleich die Daten/Zeiger aus iter->first? Warum legst Du autonome Kopien an?



  • Hallo.

    Einen Unterschied habe ich bei den beiden Funktionen SortItems und SortItemsEx nicht festgestellt. Auf jeden Fall keinen der mich in meinem Problem weiterbringt.

    Die Daten doppelt zu speichern ist unsinnig.

    BTW: Warum nimmst Du nicht gleich die Daten/Zeiger aus iter->first? Warum legst Du autonome Kopien an?

    Der Zeiger iter verweißst auf eine Map die der Funktion übergeben wird, die die Liste füllt. Sprich danach nicht mehr verfügbar ist.


  • Mod

    1. Die Daten stehen doch irgendwo.
    2. SortItemsEx übergibt die ID des zu sortierenden Items! Es löst also Dein Problem, weil Du auf die entsprechende Zeile des ListControls zugreifen kannst und auch Subitems auslesen kannst.



  • 1. Die Daten stehen doch irgendwo.

    Ja im ListCtrl. Aber sonst speichere ich die Daten nirgends. Ich muss die Daten also noch wo speichern ausser im ListCtrl oder?


  • Mod

    Nein! Musst Du nicht. Nur wenn es so wäre könnte man diese benutzen und müsste nicht doppelt Speicher verwenden.

    Siehe also SortItemsEx...



  • Also irgendwie verstehe ich das nicht wenn ich mir das Beispiel von SortItemsEx anschaue aus der MSDN dann steht dort

    CListCtrl* pListCtrl = (CListCtrl*) lParamSort;
    CString    strItem1 = pListCtrl->GetItemText(static_cast<int>(lParam1), 1);
    CString    strItem2 = pListCtrl->GetItemText(static_cast<int>(lParam2), 1);
    

    lParamSort enthält also das ListCtrl
    lParam1 und lParam2 enthalten nun Werte aus der ersten Spalte. Und wo steht nun welche Spalte aufgerufen wurde?



  • Nochmal die Frage: Wo steht nun welche Spalte aufgerufen wurde?


  • Mod

    Atomi schrieb:

    Nochmal die Frage: Wo steht nun welche Spalte aufgerufen wurde?

    Das steht in diesem Beispiel nicht. Du könntest Dir die Übergabe der Parameteranders gestalten und eine Struktur übergeben, in der steht welches List-Control es ist, und welche Spalte.

    Ich habe mir dazu eine eigene CListCtrlEx gebaut, die diese ganze Sortiererrei von selbst handhabt.

    BTW: Hättest Du Google bemüht zu den Themen "SortItemsEx CListCtrl" wärest Duim dritten Link auf ein passendes Beispiel gestoßen:
    http://www.codeproject.com/KB/list/clistctrl_sort.aspx

    Und in der Gruppe
    http://www.codeproject.com/KB/list/index.aspx?#List Controls
    findest Du noch mehr...



  • Hallo.

    Den ersten Beitrag habe ich auch gefunden. Wenn ich aber dort das Beispiel anschaue wird dort das Makro ListView_SortItemsEx verwendet. Und nicht SortItemsEx.

    Ehrlich gesagt bin ich jetzt erst recht verwirrt.



  • Gibt es kein Beispiel wo das genau erklärt wird

    Angefangen von den Daten hinzufügen über den Aufruf der SortFunktion und ermitteln der Daten in der Comparefunktion

    In allen Beispielen ist es immer so, dass alle Daten einer Spalte in z.B. einen String durch Kommas getrennt oder in ein array abgelegt werden und dies dann im lparam übergeben wird. Und dies am Anfang wenn der Dialog initialisiert wird.

    Dies geht in meinem Fall nicht. Die Spalten und Zeilen werden zur Laufzeit dynamisch gefüllt. Das heißt ich fülle zuerst die komplette erste Spalte. Zu der Zeit habe ich noch keine Informationen zur 2ten bis 3ten Spalte. Diese werden später hinzugefügt hierbei wird der entsprechende Eintrag gesucht und im einen Wert zugewiesen. Die Werte in der 4ten Spalte ändern sich ständig.

    Hierzu habe ich noch nirgends was gefunden.


  • Mod

    Warum muss auch alles haarklein erklärt werden?

    ListView_SortItemsEx ist nichts andres als der Wrapper-Makro für SendMessage LVM_SORTITEMSEX, also nichts anderes als der Aufruf des MFC Wrapper für SortItemsEx!

    In dem besagten Beispiel wird eine komplette Struktur übergeben, die das sortieren einer beliebigen Spalte erlaubt...



  • Ich habe aber keine komplette Struktur weil jeder Wert für sich dynamisch ist. Und dafür finde ich halt kein Beispiel.

    Warum muss auch alles haarklein erklärt werden?

    Weil ich nicht auf die Lösung komme.



  • Ein kleines Beispiel zum probieren, den Code mußt allerdings an Dein Programm anpassen, es dient ja auch legendlich als Hilfestellung.

    //Wir sortieren aufsteigend
    int CALLBACK ST_SORTDOWN(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
    {
    	if (lParam1 == 0 || lParam2 == 0)
    	{
    		return 0;
    	}
    
    	CString* pA = (CString*)lParam1;  
    	CString* pB = (CString*)lParam2;
    
    	return pA->Compare(LPCTSTR(*pB));
    }
    
    //Wir sortieren absteigend
    int CALLBACK ST_SORTUP(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
    {
    	if (lParam1 == 0 || lParam2 == 0)
    	{
    		return 0;
    	}
    
    	CString* pA = (CString*)lParam1;  
    	CString* pB = (CString*)lParam2;
    
    	return pB->Compare(LPCTSTR(*pA));
    }
    
    //Der User hat mit der linken Maustaste in den Header des CListCtrl geklick.
    void CSchluesseltabelle::OnHdnItemclickStSchluesseltabelle(NMHDR *pNMHDR, LRESULT *pResult)
    {
    	LPNMHEADER phdn = reinterpret_cast<LPNMHEADER>(pNMHDR);
    
    	CString	strTemp;
    
    	if ((phdn->iButton == 0) && (nStatusDatensatz != 0))
        {
    
            if (phdn->iItem == nSortedColumn)
    		{
    			bSortAscending = !bSortAscending;
    		}
            else
    		{
    			bSortAscending = FALSE;
    		}
    
            // die Spalte holen, nach der sortiert werden soll.
            nSortedColumn = phdn->iItem;
    
    		pList = (CListCtrlEx*) GetDlgItem(IDC_ST_SCHLUESSELTABELLE);
    
    		SetHeaderBitmap(pList, nSortedColumn, bSortAscending);
    
    		// Itemdatas mit Text versehen.
    		for (int i = 0; i < m_Schluesseltabelle.GetItemCount(); ++i)
    		{
    			strTemp = m_Schluesseltabelle.GetItemText(i, nSortedColumn);
    
    			if (nSortedColumn == 0)
    			{
    				while (strTemp.GetLength() < 8)
    				{
    					strTemp = _T("0") + strTemp;
    				}
    			}
    
    			m_Schluesseltabelle.SetItemData(i, (DWORD)(new CString(strTemp)));
    		}
    
    		if (bSortAscending)
    		{
    			m_Schluesseltabelle.SortItems(ST_SORTUP, 0);
    		}
    		else
    		{
    			m_Schluesseltabelle.SortItems(ST_SORTDOWN, 0);
    		}
    
    		// Itemdatas wieder freigeben.
    		for (int i = 0; i < m_Schluesseltabelle.GetItemCount(); ++i)
    		{
    			CString* pA = (CString*) m_Schluesseltabelle.GetItemData(i); 
    			delete pA;
    			m_Schluesseltabelle.SetItemData(i, 0);
    		}
    	}
    
    	*pResult = 0;
    }
    

    Turmfalke64



  • Hallo Turmfalke.

    Erstmal vielen Dank für deine Hilfe. Wo aber immer noch mein Problem liegt ist darin wie die Daten in das ListCtrl eingefügt werden müssen. Da ich wie gesagt nicht alle Daten einer Zeile auf einmal einfügen kann.



  • Ist denn kein einfaches Beispiel drin, dass ich weiß wie ich die Daten zu meinem ListCtrl hinzufüge so dass ich diese dann auch sortieren kann. Bitte.


  • Mod

    Atomi schrieb:

    Ist denn kein einfaches Beispiel drin, dass ich weiß wie ich die Daten zu meinem ListCtrl hinzufüge so dass ich diese dann auch sortieren kann. Bitte.

    Liest Du eigentlich was man Dir schreibt.
    Ich habe Dir ziemlich am Anfang genau dieses komplette Sample genannt:
    http://www.codeproject.com/KB/list/clistctrl_sort.aspx

    👎 Für mich war dies das letzte Posting zu diesem Thema ... und Tschüss.



  • Liest Du eigentlich was man Dir schreibt.
    Ich habe Dir ziemlich am Anfang genau dieses komplette Sample genannt:

    Super. Und ich schrieb, dass das Beipiel bei mir nicht funktioniert, da die Werte alle am Anfang beim initialisieren gefüllt werden. Und alle am Stück hinzugefügt werden. Statt das hier einem einfach ein kurzes Codestück gegeben wird das einem zeigt wie man Daten hinzufügt wird auf ein riesen großes Beispiel verwiesen wo 100 Ausnahmen drin sind und man dann erst nicht recht weiß was man nun genau machen muss.

    Danke.



  • Hallo Turmfalke64

    Du hast mir doch ein einfaches Beispiel genannt zur Sortierung. Kannst du mir nicht auch sagen wie ich Daten zu meinem ListCtrl hinzufüge, so dass ich nach einzelnen Spalten sortieren kann.



  • Wie soll ich das nun verstehen, willst mir jetzt damit sagen, das Du ein
    leeres CListCtrl hast,in dem noch keine Daten vorhanden sind.

    Sollte das der Fall sein, schaue mal in die MSDN Schlagwort CListCtrl und schaue
    Dir unter members mal die Funktionen InsertItem und SetItemText an.

    Sollte es jedoch mit Daten gefüllt sein, funktioniert der oben gepostet Code,
    nach Anpassung.

    Wenn man programmieren lernen will, so macht es keinen Sinn, einem alles
    vorzukauen, da dies zu keinem Erfolg führt und man es auch nicht versteht,
    warum das ganze nun funktioniert oder auch nicht.

    Turmfalke64


Log in to reply