Listenelement sortieren

B

ByeBye 31659

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?
 

Kachelator

Peter Jerz
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);

 
B

ByeBye 31659

Ä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...
 

Kachelator

Peter Jerz
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:
Code:
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;
}
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.

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.
 
B

ByeBye 31659

HI,

also ich habe den Messagehandler für den Spaltenkopf angelegt, sieht bei mir so aus:

Code:
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:
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:

Code:
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
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...
 

Kachelator

Peter Jerz
int CALLBACK CAccess_testDlg::sortitems(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
Das darf keine Memberfunktion sein. Richtig ist int CALLBACK sortitems(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) .

Wegen unterschiedlicher Spalten: Der Columnclick gibt dir einen Pointer auf eine Struktur, die weitere Infos beinhaltet.
Code:
typedef struct tagNMLISTVIEW{
    NMHDR   hdr;
    int     iItem;
    int     iSubItem;
    UINT    uNewState;
    UINT    uOldState;
    UINT    uChanged;
    POINT   ptAction;
    LPARAM  lParam;
} NMLISTVIEW, FAR *LPNMLISTVIEW;
Für dich ist wahrscheinlich iSubItem interessant - darin sollte die Spalte stehen.
Du kommst folgendermassen dran:
Code:
int iColumn = pNMListView->iSubItem; //ohne Gewähr - keine Zeit zum Testen.
 
B

ByeBye 31659

So nun funktioniert das erstmal, dass ich die Spaltennummer herausbekomme.

Code:
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....
 

Kachelator

Peter Jerz
Ich zitiere mich noch mal selbst:
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.
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.
 
B

ByeBye 31659

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?