Listenelement sortieren

B

ByeBye 31659

Also ich habe nun

Code:
		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);
data wird von 0 an hochgezählt so oft wie es einträge gibt.
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?
 

Kachelator

Peter Jerz
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.
Eigentlich sollten alle Spalten mitsortiert werden, aber nach dem Itemdata, was bei dir der Spalte 0 (ganz links) entspricht, oder?

Hier eine mögliche Lösung für ein Sortieren nach Spalte 1:
Code:
//- 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;
}
Da gibt es noch Einiges für dich umzubauen, aber das sollte für dich kein Problem mehr sein.
 
Zuletzt bearbeitet:
B

ByeBye 31659

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:
//- "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:
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?
 

Kachelator

Peter Jerz
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();
Verwende einfach CString::CompareNoCase()! ;)

1
11
12
13
..
2
21
22
..
3
[...]
Gibt es da noch einen kleinen Trick?
Ja, schreib die führenden Nullen mit rein (also aus "1" wird "01" oder "0001" usw., je nachdem, wieviele Stellen nötig sind).

Man cih frag dir hier Löcher in den Bauch odeR?
Ja. :)

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?
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.
Aber man sagt, dass auch Spalten ein "ItemData" haben können... ;) (Tipp: CListCtrl::GetHeaderCtrl(), CHeaderCtrl, HDITEM, lParam ).
 
Zuletzt bearbeitet:

MAN

Erfahrenes Mitglied
Column-Text rausfinden

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:

Ja, schreib die führenden Nullen mit rein (also aus "1" wird "01" oder "0001" usw., je nachdem, wieviele Stellen nötig sind).
Bloß, wenn ich einen Text habe, dann kann ich keine Nullen dranhängen, sonst sortiert er logischerweise nich richtig.

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
 

Kachelator

Peter Jerz
Zu dem wollte ich noch wissen, wie ich den namen (caption, text, oder wie auch immer... ^^) von der ersten spalte meines liestview rausbekomme
Also den Text in der linken Spalte? Das müsste mit GetItemText() gehen. Subitem dafür ist vermutlich 0.


Bloß, wenn ich einen Text habe, dann kann ich keine Nullen dranhängen, sonst sortiert er logischerweise nich richtig.
Hmm? Verstehe dein Problem nicht.
 

MAN

Erfahrenes Mitglied
Ich hab zum Beispiel so eine Liste (mal abgesehen von den restlichen spalten in der ListView):

Code:
10
2
20
21
3
5

wenn ich in dieser spalte sortieren will, hänge ich ja die nullen dran - so weit, so gut! Wenn ich aber nicht weiß, ob die spalte nur zahlen enthält, dann weiß ich ja auch nich, ob ich die nullen dranhängen kann, oder nicht?

Deshalb muss ich ja irgendwie wissen, ob es sich um Zahlen oder Text handelt.

Also den Text in der linken Spalte? Das müsste mit GetItemText() gehen. Subitem dafür ist vermutlich 0.
Bekommt man damit nicht den Text des ersten Items raus? Ich meinte eigentlich den ColumnHeader, die Spaltenüberschrift. Oder geht das echt mit GetItemText() ?

mfG

MAN
 

Kachelator

Peter Jerz
wenn ich in dieser spalte sortieren will, hänge ich ja die nullen dran - so weit, so gut! Wenn ich aber nicht weiß, ob die spalte nur zahlen enthält, dann weiß ich ja auch nich, ob ich die nullen dranhängen kann, oder nicht?
Ja, jetzt habe ich es begriffen.
Ich meinte eigentlich den ColumnHeader, die Spaltenüberschrift.
Dann musst du das auch sagen. ;)
Oder geht das echt mit GetItemText() ?
Nein. Nimm BOOL GetColumn( int nCol, LVCOLUMN* pColumn ) const;. Den Text bekommst du in der LVCOLUMN-Struktur. Ist ein bischen trickreich.
Beispiel:
Code:
LVCOLUMN spalteninfo;
char text[80];
spalteninfo.mask = LVCF_TEXT;
spalteninfo.pszText = text;
spalteninfo.cchTextMax = 80;
int spalte = 1;
MyListCtrl.GetColumn( spalte, &spalteninfo );
TRACE( "%s\n", spalteninfo.pszText );
// unkompiliert und ohne Gewähr! Bitte in MSDN nachschlagen
 

MAN

Erfahrenes Mitglied
"Da Wahnsinn" :)

Ich hab irgendwie ewig rumprobiert, bin auch auf GetColumn gekommen, aber bei mir hatte er immer n Speicherfehler gebracht.... Jetzt gehts!

Wie du das immer wieder hinbekommst - respekt :)

Vielen Dank nochmals!


mfG

MAN
 

Kachelator

Peter Jerz
Ich hab irgendwie ewig rumprobiert, bin auch auf GetColumn gekommen, aber bei mir hatte er immer n Speicherfehler gebracht.... Jetzt gehts!
ja, der trickreiche Teil ist das mit dem Textbuffer, dessen Pointer man in das LVCOLUMN-struct eintragen muss. Das hat bei mir auch immer erst böse Abstürze gegeben, bis ich es begriffen habe.


Wie du das immer wieder hinbekommst - respekt

Vielen Dank nochmals!
Herzlichen Dank zurück, und gern geschehen!