Rubrik: Controls · ListView | VB-Versionen: VB6 | 06.08.01 |
Numerische Sortierung im ListView-Control Dieses Beispiel zeigt, wie man in einem ListView-Control eine korrekte numerische Sortierung realisieren kann. | ||
Autor: Michael Hartmann | Bewertung: | Views: 28.596 |
ohne Homepage | System: Win9x, WinNT, Win2k, WinXP, Win7, Win8, Win10, Win11 | Beispielprojekt auf CD |
Ein großer Nachteil des ListView-Controls ist die fehlende Möglichkeit, eine Spalte des Controls numerisch zu sortieren. Hat man z.B. in einer Spalte die Werte 1, 2, 3 und 20, so sortiert VB diese Werte alphanumerisch in 1, 2, 20, 3. Das ist natürlich nicht besonders schön und macht keinen professionellen Eindruck beim Enduser.
Aber es gibt eine Möglichkeit das ListView-Control mit der Fähigkeit der numerischen Sortierung auszustatten. Dazu kann man die folgende Sortierroutine einsetzen:
Private Declare Function LockWindowUpdate Lib "user32.dll" ( _ ByVal hWnd As Long) As Long Public Sub SortListViewColumn(ByVal Index As Integer, _ ByVal CurrentListView As ListView) Dim I As Integer Dim strFormat As String Dim strData() As String Dim lRet As Long On Error GoTo ErrorHandler ' Benutzerdefinierter Formatstring für die ' Format-Funktion strFormat = String(30, "0") & "." & String(30, "0") ' Automatische Aktualisierung des Fensters sperren lRet = LockWindowUpdate(CurrentListView.Parent.hWnd) If lRet = 0& Then Call MsgBox("Can't lock window " & _ CurrentListView.Parent.hWnd, _ vbOKOnly + vbCritical) Exit Sub End If With CurrentListView With .ListItems If (Index > 0) Then ' Sortierung nach Subitems For I = 1 To .Count With .Item(I).ListSubItems(Index) ' Sichern des aktuellen Wertes der ' Text-Eigenschaft in der Tag-Eigenschaft, ' ohne einen evtl. Inhalt der Tag-Eigenschaft ' zu überschreiben .Tag = .Text & vbNullChar & .Tag ' Falls die Text-Eigenschaft der SubItems ' eine Zahl ist, so formatiere mit dem oben ' definierten Formatstring. If IsNumeric(.Text) Then .Text = Format$(CDbl(.Text), strFormat) End If End With Next I Else ' Sortierung nach Mainitem For I = 1 To .Count With .Item(I) ' Sichern des aktuellen Wertes der ' Text-Eigenschaft in der Tag-Eigenschaft, ' ohne einen evtl. Inhalt der Tag-Eigenschaft ' zu überschreiben .Tag = .Text & vbNullChar & .Tag ' Falls die Text-Eigenschaft der SubItems ' eine Zahl ist, so formatiere mit dem oben ' definierten Formatstring. If IsNumeric(.Text) Then .Text = Format$(CDbl(.Text), strFormat) End If End With Next I End If End With ' Sortiere die umformatierten Spalten neu .SortKey = Index .Sorted = True .SortOrder = 1 - .SortOrder With .ListItems If (Index > 0) Then ' Sortierung nach SubItem For I = 1 To .Count With .Item(I).ListSubItems(Index) ' Extrahiere den ursprünglichen Inhalt des ' Subitems aus der Tag Eingeschaft und ' stelle ihn wieder in die Text-Eigenschaft ' ein. strData = Split(.Tag, vbNullChar) .Text = strData(0) .Tag = strData(1) End With Next I Else ' Sortierung nach MainItem For I = 1 To .Count With .Item(I) ' Extrahiere den ursprünglichen Inhalt des ' Subitems aus der Tag Eingeschaft und ' stelle ihn wieder in die Text-Eigenschaft ' ein. strData = Split(.Tag, vbNullChar) .Text = strData(0) .Tag = strData(1) End With Next I End If End With End With ' Aufheben der Aktualisierungssperre für das Fenster lRet = LockWindowUpdate(0&) Exit Sub ErrorHandler: lRet = LockWindowUpdate(0&) Call MsgBox("Runtime error " & Err.Number & ": " & _ vbCrLf & Err.Description, vbOKOnly + vbCritical) End Sub
Die Funktion bekommt die Spalte, nach der sortiert werden soll, sowie einen Verweis auf das ListView-Control, das sortiert werden soll, übergeben, so dass die Funktion universell einsetzbar ist. Der eigentliche Trick ist, die Texte der einzelnen Items so umzuformatieren (führende Nullen einfügen), dass eine alphanumerische Sortierung zum gewünschten Ergebnis führt. Um die führenden Nullen nachher wieder leicht entfernen zu können, wird der ursprüngliche Inhalt der Text-Eigenschaft in der Tag-Eigenschaft zwischengespeichert und nach erfolgter Sortierung daraus wieder hergestellt. Damit der Benutzer vom Einfügen der führenden Nullen nichts mitbekommt, wird mit Hilfe der API-Funktion LockWindowUpdate die Aktualisierung des Fensters, in dem sich das zu sortierende ListView-Control befindet, gesperrt und erst nach erfolgter Sortierung wieder frei gegeben.
Die Funktion kann z.B. in der ColumnHeader_Click Event-Prozedur folgendermaßen aufgerufen werden:
Private Sub ListView1_ColumnClick(ByVal ColumnHeader As _ MSComctlLib.ColumnHeader) ' ListView1.Sorted = True ' ListView1.SortKey = ColumnHeader.Index - 1 ' ListView1.SortOrder = 1 - ListView1.SortOrder Call SortListViewColumn(ColumnHeader.Index - 1, _ Me.ListView1) End Sub
Um den Unterschied zur normalen Sortierung des ListView-Controls und der hier beschriebenen Funktion zu verdeutlichen, habe ich mal die Aufrufe zur normalen Sortierung auskommentiert dazu geschrieben. Auch eine Sortierung nach einem Datumswert ist durch leichte Anpassungen der Sortierroutine realisierbar. Man braucht nur das Datum in den entsprechenden Zahlenwert zu wandeln, die numerische Sortierung einsetzen und den Zahlenwert zum Schluß wieder in ein Datum umzuwandeln. Auch für frühere VB Versionen muss die Sortierfunktion etwas angepasst werden, da die Split-Funktion erst mit VB6 eingeführt wurde.
22.05.07 - Ergänzung von Dirk Siebert, Dieter Otter
Damit das Ganze auch mit Vorzeichen (negative Zahlen) korrekt funktioniert, sind die beiden Vorkommnisse:
If IsNumeric(.Text) Then .Text = Format$(CDbl(.Text), strFormat) End If
durch nachfolgende Codezeilen zu ersetzen:
If IsNumeric(.Text) Then .Text = Format$(CDbl("1" & String$(14, "0")) + CDbl(.Text), strFormat) End If