voorbeeldbestand
ListView


1. Wat is een ListView ?
1.2 Waarvoor ListView ?
1.3 ListView achtergrond

2. ListView maken
2.1 Userform
2.1.1 Ontwerpmodus
2.1.2 Geopend Userform
2.1.3 Voorbeeldbestand
2.2 In werkblad
2.2.1 ListView opruimen
2.2.2 ListView weergeven
2.2.3 ListView positie
2.2.4 Voorbeeldbestand
2.3 In werkgeheugen

3. Kolomkoppen aanmaken
3.1 Real-time
3.2 Ontwerpmodus
3.3 VBA ontwerp

4. ListItems
4.1 toevoegen
4.2 ListSubItems toevoegen
4.3 Vullen met Array
4.4 Vullen met Listobject
4.5 ListView omvang

5 ListItem lezen en wijzigen
5.1 ListItem lezen
5.2 ListItem wijzigen
5.3 ListSubItem lezen
5.4 ListSubItem wijzigen
5.5 ListSubItem rechtstreeks
5.6 ListSubItem rechtstreeks wijzigen

6 Elementen verwijderen
6.1 ListItem
6.2 Alle ListItems
6.3 ListSubItem
6.4 Alle ListSubItems

7. Afbeeldingen in de ListView
7.1 kolomkop
7.2 ListItem
7.2.1 Verwijderen uit ListItem
7.3 ListSubItem
7.3.1 Verwijderen uit ListSubItem

8 ListView weergeven
8.1 Iconen
8.2 kleine Iconen
8.3 lijst
8.4 rapport

9. Sorteren
9.1 Op datum
9.2 Op getal
9.3 Interaktief sorteren
9.4 Interaktief op datum
9.5 Interaktief op getal

10 ListView gegevens opslaan

1. Wat is een ListView ?

Een ListView in VBA is een verzamelobject: je kunt er teksten in opbergen.
De Listbox bevat 'records' (rijen) met 'velden' (kolommen).
De bestandenlijst in de Verkenner is zo'n ListView.
VBA heeft verschillende andere mogelijkheden om gegevens op te slaan:
- een dictionary
- een collection
- een array variabele
- een ActiveX ComboBox
- een ActiveX ListBox
- een ListBox in een Userform
- een sortedlist

De keuze voor een van deze methoden is afhankelijk van het te bereiken doel.
In deze pagina wordt geen poging gedaan al deze methoden met elkaar te vergelijken.
We beperken ons tot een bespreking van de mogelijkheden van de ListView.
Zo'n ListView kan deel uitmaken van een userform, van een werkblad als ActiveX-object of volledig in het werkgeheugen.

De ListView heeft 4 onderscheidende kenmerken.
In de ListView kun je gegevens per record sorteren op iedere gewenste eigenschap.
In de ListView kun je gegevens op 4 verschillende manieren zichtbaar maken.
In de ListView kun je grafische elementen aan elementen in de ListView toevoegen.
Ieder element in de ListView kan direkt benaderd worden met een sleutel (key).

1.2 Waarvoor kun je een ListView gebruiken ?

Je kunt de ListView gebruiken om gegevens bij elkaar te zetten en snel te bewerken.
Via de ListView zijn ze nl. in het werkgeheugen geladen.
In plaats van gegevens te bewerken in een Excel-werkblad, een Word Document, een Powerpointpresentatie, doe je dat in het werkgeheugen.
Daarvoor hoeft bijv. geen scherm ververst te worden, hoeven geen berekeningen uitgevoerd te worden.

1.3 Waar komt de ListView vandaan ?

De ListView maakt geen deel uit de VBA-bibliotheek (Visual Basic for Applications), de Excel-VBA-bibliotheek (Microsoft Excel x.0 Object Library) of de 'Userform'-bibliotheek (Microsoft Forms 2.0 Object Library).
De ListView bevindt zich in de Windows controls bibliotheek (Miocrosoft Windows Common Controls 6.0 (SP6)).
Deze bibliotheek is niet standaard geladen.
Je kunt de bibliotheek laden in de VBEditor, tabblad 'Extrs' ('Tools'), optie 'references'.
In de lijst met bibliotheken tref je deze bibliotheek alfabetisch aan.
Vink de de bibliotheek aan om hem te laden.
In VBA kun je de bibliotheek op 2 verschillende manieren laden: als GUID en als bestand.
GUID
ThisWorkbook.VBProject.References.AddFromGuid "{831FDD16-0C5C-11D2-A9FC-0000F8754DA1}", 0, 2
Bestand
ThisWorkbook.VBProject.References.AddFromFile Replace(Environ("comspec"), "cmd.exe", "MSCOMCTL.OCX")
Als het bestand niet op jouw systeem aanwezig is kun je het hier laden.

2. Maak een ListView

Je kunt een ListView plaatsen in een userform.
Dat kan in de ontwerpmodus of wanneer het Userform geladen wordt/is.
Ook in een werkblad kun je een ListView opnemen.
Wanneer je een ListView alleen maar wil gebruiken als hulpmiddel voor opslag/manipulatie van gegevens in het werkgeheugen kan dat ook, volledig onzichtbaar voor de gebruiker.

2.1 ListView in Userform

Een ListView in een Userform is altijd leeg en bevat geen gegevens.
Daarin komt de ListView overeen met de ComboBox en ListBox in een Userform.
Alle eigenschappen van de Userformcontrol die je in ontwerpmodus instelt worden met het Userform bewaard.
De gegevens echter niet.

2.1.1 ListView in Ontwerpmodus

In de ontwerpmodus van een Userform kun je met behulp van de 'Toolbox' een ListView invoegen.
Als de listview niet in de toolbox staat kun je hem toevoegen:
- zet de cursor in de toolbox
- klik rechter muisknop
- klik additional controls ..
- vink aan: Microsoft ListView Control, version 6.0
Nadat je de ListView aan het Userform hebt toegevoegd kun je meteen ook een groot aantal eigenschappen instellen.
Dat is handig als je vooraf weet welke gegevens je in de ListView wil opnemen.
Met de ColumnHeaders kun je bijv. de omvang (het aantal kolommen) van de ListView en eventueel de kolomnamen tevoren vastleggen.
Alle eigenschappen kunnen vooraf vastgelegd worden.
Het vullen van de ListView met gegevens kan alleen maar bij opening/geopend Userform.

2.1.2 ListView in geopend Userform

Om een ListView te kunnen invoegen hoeft de referentie naar de Bibliotheek van de ListView niet geladen te zijn.
Deze code is voldoende:
Private Sub Userform_Initialize()
Controls.Add "MSComctlLib.ListViewCtrl.2", "snb"
End Sub
De ListView komt dan in de linkerbovenhoek van het Userform te staan.
Het is handiger meteen de plaats te bepalen voor de ListView:
Private Sub Userform_Initialize()
With Controls.Add("MSComctlLib.ListViewCtrl.2", "snb")
.Top = 70
.Left = 20
.Height = 90
.Width = 120
End With
End Sub

2.1.3 ListView in voorbeeldbestand

Het voorbeeldbetand bevat een Userform.
Ter illustratie bevat de Userform_Inititialize gebeurtenis alle code die nodig is om de Listvoiw correct te tonen.
Alle eigenschappen kunnen echter beter in de Ontwerpmodus ingesteld worden.
Het vullen van de ListView, inclusief de toekenning van iconen, dient altijd met code te gebeuren.
Het voorbeeld toont het gebruik van iconen en smallicons voor kolomkoppen, ListItems en ListSubitems.
Het voorbeeld bevat ook code om te schakelen tussen de verschillende weergave-opties.
Daarvoor hoef je slechts in het getoonde userform te klikken.
De _ColumnClick gebeurtenis soreert de kolommen op-/aflopend.

2.2 ListView in werkblad

Je kunt een ListView als ActiveX-control in een werkblad plaatsen.
Daarvoor moet je het 1e argument (Class Type) van de methode 'Add' instellen als "MSComctlLib.ListViewCtrl.2".
De overige argumenten zijn niet verplicht.
Sheet1.OLEObjects.Add "MSComctlLib.ListViewCtrl.2"
De laatste 4 argumenten bepalen de positie en omvang van de ListView: Left, Top, Width, Height.
Om de lokatie en het formaat van de ListView te bepalen:
Sheet1.OLEObjects.Add("MSComctlLib.ListViewCtrl.2", , , , , , , columns(6).left, rows(1).top, 300, 300).name = "snb"

2.2.1 ListView in werkblad opruimen

Bij het opslaan van het werkboek blijft de ListView niet behouden.
Wil je een ListView gebruiken in een werkblad, dan zul je dat iedere keer bij opening van het werkboek moeten maken.
De OLEobject-container van de ListView blijft behouden, het ListView-object in het OLEobject niet.
Die OLEobject-container moet je opruimen voordat je een nieuwe ListView kunt maken.
Als de naam van de ListView niet bekend is:
On Error Resume Next
For Each it In Sheet1.OLEObjects
x3 = TypeName(it.Object) = "ListView"
If Err.Number <> 0 Then it.Delete
Err.Clear
Next
Als de naam van de ListView bekend is:
Private Sub Workbook_Open()
On Error Resume Next
Sheet1.OLEObjects("LV_00").Delete
End Sub

2.2.2 ListView in werkblad weergeven

Er gebeurt bij de aanmaak van een ListView in een werkblad iets vreemds: het OLEobject wordt getoond, maar de ListView niet.
Je kunt dit oplossen door eerst van werkblad te wisselen en vervolgens met PgUp en PgDn te scrollen.
Je hebt hiervoor dus een werkboek met 2 werkbladen nodig.
In VBA
Sheet1.OLEObjects.Add("MSComctlLib.ListViewCtrl.2", , , , , , , columns(6).left, rows(1).top, 300, 300).name = "snb"

Sheet2.Activate
Sheet1.Activate
ActiveWindow.LargeScroll 1
ActiveWindow.LargeScroll , 1

2.2.3 ListView in werkblad positie

Een ListView maakt deel uit van een OLE-object.
Die maakt op zijn beurt weer deel uit van de verzameling afbeeldingen (Shapes) van een werkblad.
Een 'Shape' wordt automatisch gekoppeld aan een cel-positie en cel-omvang.
Een ListView die voor positie en grootte afhankelijk is van een gekoppelde cel is niet handig.
Met de eigenschap .placement = 3 kun je de ListView als een onafhankelijk object in een werkblad zetten.
With Sheet1.OLEObjects.Add("MSComctlLib.ListViewCtrl.2", , , , , , , columns(6).left, rows(1).top, 300, 300)
.Name = "snb"
.Placement=3
End With

Sheet2.Activate
Sheet1.Activate
ActiveWindow.LargeScroll 1
ActiveWindow.LargeScroll , 1

2.2.4 ListView in voorbeeldbestand

In het voorbeeldbestand bij deze pagina staat in de gebeurteniscode Workbook_Open de code om een Listview in een werkblad te zetten.
Alle elementen die ook in het Userform getoond worden zijn in het werkblad zichtbaar.
Voor de sorteerroutine zet de macro in Workbook_open de code voor de gebeurtenis _ColumnClick in de macromodule van werkblad Sheet1.

2.3 ListView in werkgeheugen

In dit geval werk je met de CLSID (ClassIdentification).
Je kunt een virtuele ListView aanmaken in het werkgeheugen met de code.
With GetObject("New:{996BF5E0-8044-4650-ADEB-0B013914E99C}")
.....
End With

3. Kolomkoppen

De inhoud van een ListView bestaat uit 'records' met 'velden'.
Kolomkoppen kun je aan de ListView toevoegen om de 'velden' te benoemen.
Kolomkoppen zijn onafhankelijk van het aantal velden van records.
- een ListView kan meer kolomkoppen bevatten dan enig record velden heeft.
- een ListView kan minder kolomkoppen bevatten dan het aantal velden van een record.

Je hebt kolomkoppen nodig:
- om de rapportweergave van de ListView te tonen
- om de gegevens in de ListView te kunnen sorteren
- om de eigenschap .Subitems van een ListItem (= record) te kunnen gebruiken

Afzonderlijke kolommen tonen/verbergen

Het object 'ColumnHeader' van de ListView heeft geen eigenschap .Visible.
Met de eigenschap .Width kun je een kolom afzonderlijk zichtbaar/onzichtbaar maken.
Als de eigenschap .Width 0 is, is de kolom niet zichtbaar in de rapportweergave (.View = 3)

Alle kolomkoppen tonen

De ListView bevat de mogelijkheid in de rapprtweergave wel/geen kolomkoppen te tonen.
Of de koppen getoond worden heeft verder geen invloed op het sorteergedrag van de ListView.

Toon alle kolomkoppen
.HideColumnHeaders =False
Verberg alle kolomkoppen
.HideColumnHeaders =True

3.1 Kolomkoppen aanmaken real-time

De methode om kolomkoppen aan te maken bevat 4 argumenten
- de index; hiermee kun je de volgorde (van links naar rechts) van de kolom aangeven
- de sleutel (key); hiermee kun je met VBA-code rechtstreeks verwijzen naar deze kolom
- de koptekst: dit is de tekst die in de ListView als kolomkoptekst wordt getoond
- de breedte: hiermee kun je de breedte van de kolom instellen.
als je het breedte-argument leeg laat, berekent VBA zelf de kolombreedte op basis van de breedte van de ListView en het aantal kolommen
alleen als je daarvan afwijkende breedtes wil hanteren is het gebruik van het breedte-argument zinvol.
het effekt van de breedte-instelling is alleen zichtbaar in de weergave van de ListView als 'rappport' (.View = 3)

Stel een Userform bevat de ListView 'LV_00'.
Je wil kolom 1,2,3 en 4 respektievelijk de breedte 60,30,90 en 60 geven.
With LV_00
for jj = 1 to 4
.ColumnHeaders.Add , "K_" & jj,"Kolom " & jj, choose(jj, 60, 30, 90, 60)
next
.HideColumnHeaders = False
end with

3.2 Kolomkoppen aanmaken in ontwerpmodus

Ook in de ontwermodus (Design Mode) kun je de kolomkoppen van de ListView instellen.
Klik in het subscherm 'Properties' in de 2e optie 'Custom'.
Activeer vervolgens het tabblad 'Column Headers'.

3.3 Kolomkoppen ontwerp vastleggen met VBA

Wil je de eigenschappen van de kolomkoppen met VBA voor de ListView met VBA vastleggen dan kan dat met:
Sub M_snb()
With ThisWorkbook.VBProject.VBComponents("Userform1").Designer
For jj = 1 To 4
.Controls("LV_00").ColumnHeaders.Add , "K_" & jj, "kolom " & jj, choose(jj, 60, 30, 90, 60)
Next
End With
End Sub
Daarna kun je ten alle tijde de eigenschappen van de kolomkoppen wijzigen met bijv.
Private Sub Userform_Initialize()
For jj = 1 To 4
LV_00.ColumnHeaders(jj).Text = "Kamer " & jj
Next
End Sub

4. ListItems


4.1 ListItems toevoegen

In een ListView heten de 'records' ListItems.
De ListView bestaat bestaat dus uit een verzameling (Collection) ListItems.
De 'velden' van de records heten in een ListView 'ListSubItems'.
Ieder record bestaat uit een verzameling (Collection) ListSubItems.
Een record voeg je toe met de opdracht .ListItems.Add
De eerste ListItem krijgt de index 1.

De methode 'ListItems.Add' heeft 5 argumenten
- de positie van het record via het indexnummer
als je dit argument weglaat, komt de index overeen met de volgorde waarin de records aan de ListView zijn toegevoegd.
- de unieke sleutel (key) voor het record; niet verplicht
- de tekst van het record; niet verplicht
- de koppeling aan een afbeelding (icon); niet verplicht
- de koppeling aan een kleine afbeelding (smallicon); niet verplicht
Het gebruik van afbeeldingen komt later aan bod.

Een aantal records invoeren:
Private Sub Userform_Initialize()
For j = 1 To 4
LV_00.ListItems.Add , "Sleutel_" & j , "Tekst " & j
Next
End Sub
Toevoeging van een ListItem met een al bestaande sleutel voor een ListItem leidt tot een foutmelding.
Sleutels moeten voor ieder ListItem uniek zijn.
Als je geen sleutels gebruikt kun je zoveel ListItems met dezelfde tekst toevoegen als je wil.
De Index van het ListItem is nu het onderscheidende kenmerk. Vergelijk de Array (zonder sleutels) en de Dictionary (met sleutels).

De ListView bevat geen methode om de aanwezigheid van een ListItem met een bepaalde sleutel te testen.

4.2 ListSubItems toevoegen

Een veld van een record voeg je toe met de opdracht .ListSubItems.Add
Het eerste ListSubItem krijgt het indexnummer 1.
De methode 'ListSubItems.Add' heeft 5 argumenten
- de positie van het veld via het indexnummer
als je dit argument weglaat, komt de index overeen met de volgorde waarin de velden aan de ListView zijn toegevoegd
- de unieke sleutel (key) voor het veld
- de tekst van het veld
- de koppeling aan een afbeelding (ReportIcon) voor de rapportweergave (.View = 3)
het gebruik van afbeeldingen komt later aan bod.
- een tooltip tekst, die getoond wordt als je met de muis boven het veld staat
Private Sub Userform_Initialize()
With LV_00
For j = 1 To 4
With .ListItems.Add( , "Sleutel_" & j , "Tekst " & j)
For jj=1 to 6
.ListSubItems.Add ,"Sleutels_" & jj),"Tekst " & jj, ,,"tiptekst " & jj
next
Next
End With
End Sub
Toevoeging van een ListSubItem met een al bestaande sleutel binnen hetzelfde record/ListItem leidt tot een foutmelding.
Sleutels moeten binnen ieder ListItem uniek zijn.
Als je geen sleutels gebruikt kun je zoveel ListSubItems met dezelfde tekst toevoegen als je wil.
De Index van het ListSubItem is nu het onderscheidende kenmerk. (Vergelijkbaar met de Array (zonder sleutels) en de Dictionary (met sleutels)).

De ListView bevat geen methode om de aanwezigheid van een ListSubItem met een bepaalde sleutel te testen.

4.3 ListView vullen met een Array

In veel gevallen zul je gegevens uit een Excel werkblad willen invoeren in een ListView.
Als de eerste rij van het werkblad namen voor kolomkoppen bevat kun je deze code gebruiken:
Private Sub Userform_Initialize()
sn = Sheet1.Cells(1).CurrentRegion

With LV_00
For jj = 1 To UBound(sn, 2)
.ColumnHeaders.Add , , sn(1, jj)
Next
.HideColumnHeaders = False

For j = 2 To UBound(sn)
With .ListItems.Add(, , sn(j, 1))
For jj = 2 To UBound(sn, 2)
.ListSubItems.Add , , sn(j, jj)
Next
End With
Next
End With
End Sub

4.4 ListView vullen met een Listobject

Als het werkblad een Listobject ('Tabel') bevat kun je deze code gebruiken:
Private Sub Userform_Initialize()
sp = Sheet1.ListObjects(1).HeaderRowRange
sn = Sheet1.ListObjects(1).DataBodyRange

With LV_00
For jj = 1 To UBound(sp, 2)
.ColumnHeaders.Add , , sp(1, jj)
Next
.HideColumnHeaders = False

For j = 2 To UBound(sn)
With .ListItems.Add(, , sn(j, 1))
For jj = 2 To UBound(sn, 2)
.ListSubItems.Add , , sn(j, jj)
Next
End With
Next
End With
End Sub

4.5 De omvang van een ListView

De ListView heeft geen eigenschap om de omvang van het aantal records weer te geven.
Je gebruikt daarvoor de collectie van ListItems.
Msgbox LV_00.ListItems.count
Het aantal velden per record kan variëren.
Het aantal SubListItems is daarom niet geschikt om het aantal velden weer te geven.
Het aantal kolomkoppen bepaalt in ieder geval het aantal kolommen dat in de rapportweergave getoond kan worden.
Msgbox LV_00.ColumnHeaders.Count

5 ListItem lezen en wijzigen


5.1 ListItem eigenschappen lezen

Ieder ListItem heeft eigenschappen, bijv.:
- de index
- de sleutel
- de tekst
- een gekoppelde afbeelding
- een gekoppelde kleine afbeelding
Die kun je per ListItem uitlezen.
for each it in LV_00.ListItems
MsgBox join(array(it.Index,it.Key, it.Text,it.Icon,it.SmallIcon, vbLf)
next

5.2 ListItem-eigenschappen wijzigen

Ieder ListItem heeft eigenschappen die je kunt wijzigen:
- de sleutel
- de tekst
- een gekoppelde afbeelding
- een gekoppelde kleine afbeelding
With LV_00.ListItems("Rob")
it.Key = "Nieuwe Sleutel"
it.Text = "Nieuwe tekst"
it.Icon = "peer"
it.SmallIcon = "appel"
End With

5.3 ListSubItem-eigenschappen lezen

Ieder ListSubItem heeft eigenschappen, bijv.:
- de index
- de sleutel
- de tekst
- een gekoppelde afbeelding voor in de rapportweergave
- een popup-tekst bij cursorselectie
Die kun je per ListSubItem uitlezen.
for each it in LV_00.ListItems("Rob").ListSubItems
MsgBox join(array(it.Index,it.Key, it.Text,it.ReportIcon,it.Tooltiptext, vbLf)
next

5.4 ListSubItem-eigenschappen wijzigen

Ieder ListSubItem heeft eigenschappen, die je kunt wijzigen bijv.:
- de sleutel
- de tekst
- een gekoppelde afbeelding voor in de rapportweergave
- een popup-tekst bij cursors lectie

Bijvoorbeeld zo:
With LV_00.ListItems("Rob").ListSubItems(1)
it.Key = "Nieuwe Veldsleutel"
it.Text = "Nieuwe veldtekst"
it.ReportIcon = "peer"
it.ToolTipText = "andere tekst"
End With

5.5 ListSubItem-inhoud rechtstreeks lezen

In een ListView kun je aan ieder ListItem ('record') een sleutel toewijzen.
In een ListView kun je aan ieder ListSubItem ('veld') van een record een sleutel toewijzen.

Op die manier kun je met twee sleutels ieder veld in de ListView direkt lezen.
MsgBox LV_00.ListItems("Rob").ListSubItems("Department")
Als de velden geen sleutels hebben kun je de index gebruiken.
Dan kun je gebruik maken van de eigenschap .SubItems of van de verzameling .ListSubItems
For j = 1 To LV_00.ListItems("Rob").ListSubItems.Count
msgbox LV_00.ListItems("Rob").ListSubItems(j)
msgbox LV_00.ListItems("Rob").SubItems(j)
Next
Alleen voor de verzameling .ListSubItems kun je gebruik maken van de For Each ... Next lus.
For each it in LV_00.ListItems("Rob").ListSubItems
msgbox it
Next

5.6 ListSubItem-inhoud rechtstreeks wijzigen

In een ListView kun je aan ieder ListItem ('record') een sleutel toewijzen.
In een ListView kun je aan ieder ListSubItem ('veld') van een ListItem een sleutel toewijzen.
Op die manier kun je met twee sleutels ieder ListSubItem ('veld') in de ListView direkt benaderen en wijzigen.
Een ListSubItem kun je wijzigen door de eigenschap .Text te wijzigen.
LV_00.ListItems("Rob").ListSubItems("Department").Text = "Magazijn"
Als de velden geen sleutels hebben kun je de index gebruiken.
Dan kun je gebruik maken van de verzameling .ListSubItems.
For j = 1 To LV_00.ListItems("Rob").ListSubItems.Count
LV_00.ListItems("Rob").ListSubItems(j).Text = "nieuwe tijd"
Next
Of met gebruik van de For Each ... Next lus.
For each it in LV_00.ListItems("Rob").ListSubItems
it.Text = it.Text & " nieuw"
Next

6 Elementen verwijderen

6.1 ListItem verwijderen

Een ListItem kun je verwijderen met de opdracht .Remove.
Welk item verwijderd moet worden geef je aan met de index van het te verwijderen item.
Het eerste item heeft indexnummer 1

Dat kan op 2 manieren:
- geef direkt het indexnummer door
- roep het indexnummer van het ListItem via de sleutel van het ListItem op
With LV_00.ListItems
.Remove 3
.Remove LV_00.ListItems("Rob").Index
End With

6.2 Alle ListItems uit de ListView verwijderen

Met de opdracht .Clear verwijder je alle ListItems uit de ListView.
With LV_00.ListItems
.Clear
End With

6.3 Een ListSubItem van een record verwijderen

Een ListSubItem kun je verwijderen met de opdracht .Remove.
Welk item verwijderd moet worden geef je aan met de index van het te verwijderen item.
Het eerste item heeft indexnummer 1

Dat kan op 2 manieren:
- geef direkt het indexnummer door
- roep het indexnummer van het ListSubItem via de sleutel van het ListSubItem op
With LV_00. ListItems("Rob").ListSubItems
.Remove 3
.Remove LV_00.ListItems("Rob").ListSubItems("Department").Index
End With

6.4 Alle ListSubItems uit een ListItem verwijderen

Met de opdracht .Clear verwijder je alle ListSubItems uit een ListItem.

With LV_00.ListItems("Rob")
.Clear
End With

7. Afbeeldingen in de ListView

Aan 3 elementen van de ListView kun je afbeeldingen toevoegen:
- de ColumnHeader
- een ListItem
- een ListSubItem

Dat betekent dat je naast de tekst van het element ook een afbeelding te zien krijgt.
Die afbeeldingen maken geen deel uit van de ListView zelf.
Ze bevinden zich in een aparte Control in het Userform of het werkblad.
Voor een virtuele ListView is dit niet van toepassing, omdat die volledig onzichtbaar blijft.

De control die de afbeeldingen bevat is een ImageList control.
Deze control maakt deel uit van dezelfde VBA-bibliotheek als de ListView.

In de ListView heten de afbeeldingen Icons.
De ListView maakt onderscheid tussen Icons, SmallIcons en ReportIcons.
Voor ieder van deze Icons heb je een aparte Imagelist nodig, omdat een Imagelist slechts afbeeldingen van 1 formaat kan bevatten.

Een Imagelist kan deel uitmaken van een Userform of een werkblad.
Om afbeeldingen te gebruiken dient ieder element van de ListView: ColumnHeader, ListItem of ListSubItem aan een Imagelist gekoppeld te zijn.
Het maakt niet uit of die Imagelist zich in een Userform of een werkblad bevindt.

7.1 Afbeeldingen in de kolomkop

Kolomkoppen kunnen alleen maar zichtbaar zijn in de rapport-weergave van de ListView.
Iconen in kolomkoppen hebben dan ook alleen maar zin als
- de rapportweergave wordt gebruikt (.View = 3)
- de kolomkoppen ook daadwerkelijk worden getoond ( .HideColumnHeaders = False )

Om iconen aan een kolomkop te 'hechten', leg je een koppeling met de Imagelist met de iconen.
Als de ListView in het Userform LV_00 heet en de ImageList in het Userform IL_00:
LV_00.ColumnHeaderIcons = IL_00
Vervolgens geef je aan welk icoon uit de Imagelist in een kolomkop moet verschijnen.
Dat gebeurt met de eigenschap .Icon van .ColumnHeader.
Dat kan voor iedere kolomkop een ander icoon zijn, inclusief geen icoon.

Je kunt de naam van het icoon in de Imagelist gebruiken.

Bij de aanmaak van een kolomkop
LV_00.ColumnHeaders.Add , "sleutel 1", "Tekst 1", 120, "appel"
Bij een bestaande kolomkop
LV_00.ColumnHeaders("sleutel 1").Icon ="appel"
Of je kunt het indexnummer van het icoon in de Imagelist gebruiken

Bij de aanmaak van een kolomkop
LV_00.ColumnHeaders.Add , "sleutel 1", "Tekst 1", 120, 2
Bij een bestaande kolomkop
LV_00.ColumnHeaders("sleutel 1").Icon = 2
De hoogte van de kolomkop past zich automatisch aan aan de grootte van de afbeeldingen in de gekoppelde IamgeList.

7.2 Afbeeldingen in een ListItem

ListItems kunnen grote en kleine iconen bevatten.
De ListView kent nl. een weergave met iconen: .View = 0.
De ListView heeft ook een weergave met kleiene iconen: .View = 1.

Als je van dat onderscheid gebruik wil maken heb je twee afzonderlijke Imagelists nodig met iconen van verschillende afmetingen.
Om iconen aan een kolomkop te 'hechten', leg je een koppeling met de Imagelist met de iconen.

Als de ListView LV_00 heet en de ImageList met 'grote' iconen IL_00:
LV_00.Icons = IL_00
Als de ListView LV_00 heet en de ImageList met 'kleine' iconen IL_01:
LV_00.SmallIcons = IL_01
Vervolgens geef je aan welk icoon uit de Imagelist in een ListItem moet verschijnen.
Dat gebeurt met de eigenschap .Icon van .ListItem en/of de eigenschap .SmallIcon.
Dat kan voor ieder ListItem een ander icoon zijn, inclusief geen icoon.
De afbeeldingen van .Icon en .SmallIcon kunnen eenzelfde afbeelding in een ander formaat zijn, maar het kunnen ook totaal verschillende afbeeldingen zijn.

Een Imagelist bevat iconen met een indexnummer en een unieke sleutel.
De tekst in de eigenschap .Icon verwijst naar de sleutels van de iconen in de gekoppelde Imagelist.
De tekst in de eigenschap .SmallIcon verwijst naar de sleutels van de iconen in de gekoppelde Imagelist.

Je kunt de sleutel van het icoon in de Imagelist gebruiken.

Bij de aanmaak van het ListItem
LV_00.ListItems.Add , "sleutel 1", "tekst 1", "aardbei_groot", "aardbei_klein"
Bij een bestaand ListItem
LV_00.ListItems("sleutel 1").Icon ="aardbei_groot"
LV_00.ListItems("sleutel 1").SmallIcon = "aardbei_klein"
Of je kunt het indexnummer van het icoon in de Imagelist gebruiken.

Een Imagelist bevat iconen met een indexnummer en een unieke sleutel.
Een nummer in de eigenschap .Icon verwijst naar de indexnummers van de iconen in de gekoppelde Imagelist.
Een nummer in de eigenschap .SmallIcon verwijst naar de indexnummers van de iconen in de gekoppelde Imagelist.

Bij de aanmaak van het ListItem
LV_00.ListItems.Add, "sleutel 1", "tekst 1", 3, 7
Bij een bestaand ListItem
LV_00.ListItems("sleutel 1").Icon = 3
LV_00.ListItems("sleutel 1").SmallIcon = 7

7.2.1 Afbeelding uit een ListItem verwijderen

Je kunt de verwijzing naar een icoon in de eigenschap .Icon verwijderen door aan de eigenschap .Icon de waarde Empty toe te wijzen.
LV_00.ListItems("sleutel 1").Icon = Empty
Je kunt de verwijzing naar een icoon in de eigenschap .SmallIcon verwijderen door aan de eigenschap .SmallIcon de waarde Empty toe te wijzen.
LV_00.ListItems("sleutel 1").SmallIcon = Empty
Als je aan een Listitem met de IIf-methode op voorwaarde een icoon wil toekennen heb je de waarde Empty ook nodig.

Voor de .Icon eigenschap:
LV_00.ListItems.Add , "sleutel 1", "tekst 1", iif(LV_00.ListItems.Count mod 2 =0,"aardbei_groot",Empty)
Als je aan een Listitem met de IIf-methode op voorwaarde een klein icoon wil toekennen heb je de waarde Empty ook nodig.

Voor de .SmallIcon eigenschap:
LV_00.ListItems.Add , "sleutel 1", "tekst 1", , iif(LV_00.ListItems.Count <5,"aardbei_klein",Empty)

7.3 Afbeeldingen in een ListSubItem

ListSubItems ('velden' van een ListItem kunnen iconen bevatten.
Die zijn, net zoals kolomkoppen, alleen zichtbaar in de rapport-weergave van de ListView.
Een ListSubItem maakt geen onderscheid tussen Icons en SmallIcons.
Het ListSubItem maakt gebruik van de Imagelist die aan de eigenschap .SmallIcons van de ListView is toegekend.
Daarmee bepaal je zelf hoe groot de te tonen iconen zijn.

LV_00.SmallIcons = IL_01
De eigenschap .Reportitem bevat de sleutel of het indexnummer van een icoon in de gekoppelde ImageList.
Je kunt de naam van de icoon opgeven.

Bij de aanmaak van een ListSubItem
LV_00.ListItems("Rob").ListSubItems.Add , "sleutel 1", "tekst 1", "appel", "tooltiptekst 1"
Bij een bestaand ListSubItem
LV_00.ListItems("Rob").ListSubItems.ReportIcon = "appel"
Je kunt het indexnummer van de icoon opgeven.
Bij de aanmaak van het ListSubItem:

LV_00.ListItems("Rob").ListSubItems.Add , "sleutel 1", "tekst 1", 3, "tooltiptekst 1"
Bij een bestaand ListSubItem
LV_00.ListItems("Rob").ListSubItems.ReportIcon = 3

7.3.1 Afbeelding uit een ListSubItem verwijderen

Je kunt de verwijzing naar een icoon in de eigenschap .ReportIcon verwijderen door aan de eigenschap .ReportIcon de waarde Empty toe te wijzen.
LV_00.ListItems("sleutel 1").ListSubItems(1).ReportIcon = Empty
Als je aan een ListSubItem met de IIf-methode op voorwaarde een icoon wil toekennen heb je de waarde Empty ook nodig.

Voor de .ReportIcon eigenschap:
LV_00.ListItems("Rob").ListSubItems.Add , "sleutel 1", "tekst 1", IIf(LV_00.ListItems.Count>4, 3, Empty), "tooltiptekst 1"

8 ListView weergeven

De ListView heeft 4 weergave-opties.
In alle weergaven zijn de ListItems zichtbaar.
In de rapport-weergave kunnen ook alle ListSubItems ('velden') en kolomkoppen zichtbaar zijn.

De eigenschap ListView.View bepaalt de weergave van de ListItems.

8.1 ListView weergave: Iconen

De ListView.View eigenschap kan de waarde lvwIcon of 0 bevatten voor deze weergave-optie.

De teksten van de ListItems verschijnen van linksboven naar rechtsonder.
De iconen van de ListItems zie je als:
- als de Listview gekoppeld is aan een ImageList via de eigenschap ListView.Icons
- en ieder ListItem een sleutel of indexnummer in de eigenschap .ListItem(j).Icon bevat
De ListView eigenschap .Icons legt een koppeling naar een ImageList.
Die koppeling is uitsluitend van belang voor déze weergave-optie lvwIcon van de ListView.
In alle andere gevallen is de Imagelist van .SmallIcons bepalend.

8.2 ListView weergave: kleine Iconen

De ListView.View eigenschap kan de waarde lvwSmallIcon of 1 bevatten voor deze weergave-optie.

De teksten van de ListItems verschijnen van linksboven naar rechtsonder.
De kleine iconen van de ListItems zie je als:
- als de Listview gekoppeld is aan een ImageList via de eigenschap ListView.SmallIcons
- en ieder ListItem een sleutel of indexnummer in de eigenschap .ListItem(j).SmallIcon bevat

8.3 ListView weergave: lijst

De ListView.View eigenschap kan de waarde lvwList of 2 bevatten voor deze weergave-optie.

De teksten van de ListItems verschijnen van boven naar beneden.
Vervolgens van boven naar beneden in kolommen van links naar rechts.

De kleine iconen van de ListItems zie je als:
- als de Listview gekoppeld is aan een ImageList via de eigenschap ListView.SmallIcons
- en ieder ListItem een sleutel of indexnummer in de eigenschap .ListItem(j).SmallIcon bevat

8.4 ListView weergave: rapport

De ListView.View eigenschap kan de waarde lvwReport of 3 bevatten voor deze weergave-optie.

De weergave is die van een tabel.

kolomkoppen
- alle teksten kunnen zichtbaar zijn.
- alle iconen kunnen zichtbaar zijn.

ListItems
- alle teksten kunnen zichtbaar zijn.
- alle iconen kunnen zichtbaar zijn.

ListSubItems
- alle teksten kunnen zichtbaar zijn.
- alle iconen kunnen zichtbaar zijn.


Welke elementen zichtbaar zijn is afhankelijk van:

Kolom:
- als de breedte-eigenschap .Width van de kolomkop groter is dan 0

Kolomkop:
- als de eigenschap ListView.HideColumnHeaders de waarde False heeft

Kolomkop icoon:
- als de eigenschap ListView.ColumnHeaderIcons gekoppeld is een aan geldige ImageList
- als de eigenschap .Icon van de ColumnHeader een geldige Index of sleutel uit de Imagelist heeft

Listitem tekst:
- als de corresponderende ColumnHeader zichtbaar is

ListItem icoon:
- als de corresponderende ColumnHeader zichtbaar is
- als de eigenschap ListView.SmallIcons gekoppeld is aan een geldige Imagelist
- als de eigenschap .SmallIcon van het ListItem een geldige Index of sleutel uit de Imagelist heeft

ListSubItem tekst:
- als de corresponderende ColumnHeader zichtbaar is

ListSubItem icoon:
- als de corresponderende ColumnHeader zichtbaar is
- als de eigenschap ListView.SmallIcons gekoppeld is aan een geldige Imagelist
- als de eigenschap .ReportIcon van het ListSubItem een geldige Index of sleutel uit de Imagelist heeft

9. Sorteren

De ListView heeft een eigen sorteermethode.
De ListView wordt altijd per ListItem ('record') gesorteerd.
De sortering maakt gebruik van de indices van de kolomkoppen.
Zonder kolomkoppen kun je de ListView niet sorteren.

Drie eigenschappen van de ListView bepalen de sortering.
- ListView.Sorted de ListView wel/niet sorteren: waarden 0 of 1.
- ListView.SortKey geeft de sorteeerkolom aan: indexnummer van een kolom.
De eerste kolom van de ListView (met de ListItems) heeft de index 0.
- ListView.SortOrder oplopende of aflopende sortering: waarden 0 of 1.


Alle 'velden' in de ListView bevatten tekst.
De sortering benut de eigenschap .Text van ListItems en ListSubItems.
Een sortering is dan ook altijd een tekstsortering.
Hoe getallen en datums gesorteerd kunnen worden komt in 9.1 aan bod.

Een ListView op ListItem sorteren
With LV_00
For jj = 1 To 4
.ColumnHeaders.Add , "Sleutel " & jj, "Tekst " & jj, 80
Next

' . . . voeg gegevens in

.Sorted = 1
.SortKey = 0
.SortOrder = 0
.SorOrder = lvwascending
.SortOrder = 1
.Sortorder = lvwdescending
End With
Een ListView op een ListSubItem sorteren
With LV_00
For jj = 1 To 4
.ColumnHeaders.Add , "Sleutel " & jj, "Tekst " & jj, 80
Next

' . . . voeg gegevens in

.Sorted = 1
.SortKey = 3
.SortOrder = 1
End With

9.1 Sorteren op datum

Er zijn verschillende manieren om datums als tekst te sorteren.
Als je een datum weergeeft in de ISO-notatie yyyy-mm-dd (de 'small-endian' weergave) kun je iedere datum correct sorteren.
De tekstsortering sorteert nl. van links naar rechts.

In VBA zijn datums getallen.
Het getal 1 staat voor 01-01-1900.
Getallen kun je alleen maar correct als tekst sorteren als ze evenveel posities hebben.
Van links naar rechts sorterend is 61 nl. groter dan 567.
Alle data tussen 18-05-1927 (10000) en 13-10-2137 (99999) hebben als getal 5 posities; tekstsortering geeft dan hetzelfde resultaat als getalsortering.

Wil je in de rapportweergave datums in de vorm dd-mm-yyyy tonen, dan zul je voor de sortering een extra 'kolom' moeten aanmaken.
Het is voor de hand liggend om die sorteerkolom te verbergen in de rapportweergave.
De sortering vindt dan in de datumsorteerkolom plaats, de weergave is de 'gewone' datumkolom.

Sorteren op format

De ListView krijgt 3 zichtbare kolommen en 2 niet zichtbare.
De eerste kolom bevat het ListItem met een tekst.
De tweede, verborgen, datumsorteerkolom bevat de datum uit kolom 4 in de opmaak yyyymmdd.
De derde, verborgen, kolom is een sorteerkolom voor getallen.
De vierde kolom bevat de datum met de datumopmaak: dd-mm-yyyy.
De vijfde kolom is de tekst van het departement.

Gegevens worden
- gesorteerd, vanwege .Sorted = 1,
- oplopend gesorteerd, vanwege .Sortorder = 0
- gesorteerd op de kolom met indexnummer 2, vanwege .SortKey = 2
Private Sub UserForm_Initialize()
sn = Split("naam sorteerdatum sorteergetal datum departement")

With LV_00
for jj = 0 to 4
.ColumnHeaders.Add , sn(jj), sn(jj), iif(jj<2, 0, 60)
Next
For j = 0 To 4
With .ListItems.Add(, , "Naam " & j)
For jj = 1 To 3
.ListSubItems.Add , , Choose(jj, Format(Date - j, "yyyymmdd"),"",Date - j, sn(jj) & " " & j,)
Next
End With
Next

.Sorted = 1
.SortKey = 2
.SortOrder = 0
.View = 3
End With
End Sub
Sorteren op getal

De ListView krijgt 3 zichtbare kolommen en 2 niet zichtbare.
De eerste kolom bevat het ListItem met een tekst.
De tweede, verborgen datumsorteerkolom met de datum uit kolom 4 als getal: CLng(Date –j)
De derde, verborgen getalsorteerkolom blijft leeg.
De vierde kolom is een datum in gewone datumopmaak: dd-mm-yyyy.
De vijfde kolom is de tekst van het departement.

Gegevens worden
- gesorteerd, vanwege .Sorted = 1,
- oplopend gesorteerd, vanwege .Sortorder = 0
- gesorteerd op de kolom met indexnummer 2, vanwege .SortKey = 2
Private Sub UserForm_Initialize()
sn = Split("naam sorteerdatum sorteergetal datum departement")

With LV_00
For jj = 0 To 4
.ColumnHeaders.Add , sn(jj), sn(jj), iif(jj<2, 0, 60)
Next
For j = 0 To 4
With .ListItems.Add(, , "Naam " & j)
For jj = 1 To 4
.ListSubItems.Add , , Choose(jj, CLng(Date - j),"",Date - j, sn(jj) & " " & j)
Next
End With
Next

.Sorted = 1
.SortKey = 2
.SortOrder = 0
.View = 3
End With
End Sub

9.2 Sorteren op getal

De sorteermethode van de ListView is een tekstsorteermethode.
Die beschouwt 61 als een groter getal dan 287.
Alleen als alle te sorteren getallen hetzelfde aantal posities hebben komt de tekstsortering overeen met numerieke sortering.
Om te zorgen dat tekstsortering van getallen toch de gewenste uitkomst heeeft kunnen we gebruik maken van format.
Met format kunnen we nl. alle getallen een gelijk aantal posities geven.
Format(61,"000") leidt tot '061" en format(287,"000") tot "287".
De tekstsorteermethode beschouwt nu "287" als een groter getal dan "061".

Wil je in de rapportweergave getallen als getallen tonen, dan zul je voor de sortering een extra 'kolom' moeten aanmaken.
Het is voor de hand liggend om die sorteerkolom te verbergen in de rapportweergave.
De sortering vindt dan in de getalsorteerkolom plaats, de weergave is de 'gewone' getalkolom.

Sorteren op format

De ListView krijgt 3 zichtbare kolommen en 2 niet zichtbare.
De eerste kolom bevat het ListItem met een tekst.
De tweede, verborgen datumsorteerkolom blijft leeg.
De derde, verborgen getalsorteerkolom bevat het getal uit kolom 5 in de opmaak "00000".
De vierde kolom is een datum in gewone datumopmaak: dd-mm-yyyy.
De vijfde kolom is het nummer van het departement.

Gegevens worden
- gesorteerd, vanwege .Sorted = 1,
- aflopend gesorteerd, vanwege .Sortorder = 1
- gesorteerd op de kolom met indexnummer 3, vanwege .SortKey = 3
Private Sub UserForm_Initialize()
sn = Split("naam sorteerdatum sorteergetal datum departement")

With LV_00
For jj = 0 To 5
.ColumnHeaders.Add , sn(jj), sn(jj), iif(jj<2,0,60)
Next
For j = 0 To 4
With .ListItems.Add(, , "Naam " & j)
For jj = 1 To 4
.ListSubItems.Add , , Choose(jj, "", Format(12^j, string(15,"0")),format(Date –j,"dd-mm-yyyy"), 12^j)
Next
End With
Next

.Sorted = 1
.SortKey = 2
.SortOrder = 1
.View = 3
End With
End Sub

9.3 Interaktief sorteren

We kennen allemaal de mogelijkheid om in de Verkenner of het 'Openen'-hulpscherm en het 'Opslaan als'-hulpscherm in Excel via de kolomkoppen de kolommen oplopend of aflopend te sorteren.
Dat is ook in de ListView eenvoudig te realiseren.

De ListView bevat de gebeurtenis _ColumnClick
Private Sub ListView_ColumnClick(ByVal ColumnHeader As MSComctlLib.ColumnHeader)
Het argument ColumnHeader van de gebeurenis ListView_ColumnClick is de kolomkop ( = kolomknop) waarop door de gebruiker geklikt is.
Iedere kolomkop heeft de eigenschap .SubItemIndex.
De eigenschap .SubItemIndex geeft aan ann welke ListSubItem (kolom) de kolomkop gekoppeld is.
Als je de kolomkop als schakelknop wil gebruiken voor oplopend en aflopend sorteren, is deze code voldoende:
Private Sub LV_00_ColumnClick(ByVal ColumnHeader As MSComctlLib.ColumnHeader)
With LV_00
.SortKey = ColumnHeader.SubItemIndex
.SortOrder = Abs(.SortOrder = 0)
End With
End Sub

9.4 Interaktief sorteren op datum

Voor een datumsortering hebben we een extra sorteerkolom nodig.
Ieder record/ListItem komt in de eerste kolom van de ListView te staan.
Voor een consistente systematiek gebruiken we het eerste 'veld'/ListSubItem van het 'record'/ListItem als datumsorteerkolom.
Vervolgens gebruiken we het tweede 'veld'/ListSubItem van het 'record'/ListItem als getalsorteerkolom.
Als er geen datum en/of getalsortering nodig is blijven deze kolommen leeg.
Dat vormt geen belemmering voor het funktioneren van de ListView.
Als er meer dan 1 datum of getalkolom gesorteerd moet worden heb je voor elk een aparte sorteerkolom nodig.

In de gebeurteniscode ListView_ColumnClick krijgt de eigenschap .Sortkey door welke kolom gesorteerd moet worden.
Gebruik daarvoor de eigenschap .SubItemIndex van iedere kolomkop.
Bij datumsortering is niet de aangeklikte kolom de sorteerkolom.
De kolomkop moet informatie over het indexnummer van de gekoppelde sorteerkolom krijgen.
De .Tag-eigenschap van de kolomkop is daarvoor geschikt.
De .Tag-eigenschap krijgt het indexnummer van de gekoppelde sorteerkolom.

De datumgegevens komen in het ListSubItem.
Daarnaast moeten ze geformateerd in het ListSubItem van de sorteerkolom terechtkomen.
Voor datumgegevens kan dat met format(datum,"yyyymmdd") of Clng(datum).
Private Sub UserForm_Initialize()
sn = Sheet1.Cells(1).CurrentRegion

With LV_00
For jj = 1 To UBound(sn, 2)
.ColumnHeaders.Add(, sn(1, jj), sn(1, jj), Choose(jj, 60, 60, 120, 60)).Tag = IIf(IsDate(sn(2, jj)), 1, IIf(IsNumeric(sn(2, jj)), 2, ""))
If jj = 1 Then
.ColumnHeaders.Add , "datum_", , 0
.ColumnHeaders.Add , "getal_", , 0
End If
Next

.HideColumnHeaders = False

For j = 2 To UBound(sn)
With .ListItems.Add(, sn(j, 1), sn(j, 1))
.ListSubItems.Add , LV_00.ColumnHeaders(2).Key .ListSubItems.Add , LV_00.ColumnHeaders(3).Key
For jj = 2 To UBound(sn, 2)
.ListSubItems.Add , sn(1, jj), sn(j, jj), , "tooltiptekst" & jj
If IsDate(sn(j, jj)) Then .ListSubItems(1).Text = CLng(sn(j, jj))
If IsNumeric(sn(j, jj)) Then .ListSubItems(2).Text = Format(sn(j, jj), String(15, "0"))
Next
End With
Next

.Sorted = 1
.View = 3
end with
End Sub
De gebeurteniscode
Private Sub LV_00_ColumnClick(ByVal ColumnHeader As MSComctlLib.ColumnHeader)
With LV_00
.SortKey = IIf(ColumnHeader.Tag = "", ColumnHeader.SubItemIndex, ColumnHeader.Tag)
.SortOrder = Abs(.SortOrder = 0)
End With
End Sub

9.5 Interaktief sorteren op getal

Voor de getalsortering hebben we een extra sorteerkolom nodig.
Ieder record/ListItem komt in de eerste kolom van de ListView te staan.
Voor een consistente systematiek gebruiken we het eerste 'veld'/ListSubItem van het 'record'/ListItem als datumsorteerkolom.
Vervolgens gebruiken we het tweede 'veld'/ListSubItem van het 'record'/ListItem als getalsorteerkolom.
Als er geen datum en/of getalsortering nodig is blijven deze kolommen leeg.
Dat vormt geen belemmering voor het funktioneren van de ListView.
Als er meer dan 1 datum of getalkolom gesorteerd moet worden heb je voor elk een aparte sorteerkolom nodig.

In de gebeurteniscode ListView_ColumnClick krijgt de eigenschap .Sortkey door welke kolom gesorteerd moet worden.
Gebruik daarvoor de eigenschap .SubItemIndex van iedere kolomkop.
Bij getalsortering is niet de aangeklikte kolom de sorteerkolom.
De kolomkop moet daarom informatie krijgen over het indexnummer van de gekoppelde sorteerkolom.
De .Tag eigenschap van de kolomkop is daarvoor geschikt.
De .Tag-eigenschap krijgt het indexnummer van de gekoppelde sorteerkolom.

De getallen moeten ingevoerd worden in het ListSubItem.
Daarnaast moeten ze geformateerd in het ListSubItem van de sorteerkolom terechtkomen.
Voor getallen kan dat met format(getal,string(15,"0")).
Private Sub UserForm_Initialize()
sn = Sheet1.Cells(1).CurrentRegion

With LV_00
For jj = 1 To UBound(sn, 2)
.ColumnHeaders.Add(, sn(1, jj), sn(1, jj), Choose(jj, 60, 60, 120, 60)).Tag = IIf(IsDate(sn(2, jj)), 1, IIf(IsNumeric(sn(2, jj)), 2, ""))
If jj = 1 Then
.ColumnHeaders.Add , "datum_", , 0
.ColumnHeaders.Add , "getal_", , 0
End If
Next

.HideColumnHeaders = False

For j = 2 To UBound(sn)
With .ListItems.Add(, sn(j, 1), sn(j, 1))
.ListSubItems.Add , LV_00.ColumnHeaders(2).Key .ListSubItems.Add , LV_00.ColumnHeaders(3).Key
For jj = 2 To UBound(sn, 2)
.ListSubItems.Add , sn(1, jj), sn(j, jj)
If IsDate(sn(j, jj)) Then .ListSubItems(1).Text = CLng(sn(j, jj))
If IsNumeric(sn(j, jj)) Then .ListSubItems(2).Text = Format(sn(j, jj), String(15, "0"))
Next
End With
Next

.Sorted = 1
.View = 3
end with
End Sub
Private Sub LV_00_ColumnClick(ByVal ColumnHeader As MSComctlLib.ColumnHeader)
With LV_00
.SortKey = IIf(ColumnHeader.Tag = "", ColumnHeader.SubItemIndex, ColumnHeader.Tag)
.SortOrder = Abs(.SortOrder = 0)
End With
End Sub

10 ListView gegevens opslaan

In een ListView kan een gebruiker wijzigingen aanbrengen.
Ook met VBA kan van alles aan een ListView aangepast worden.
Als je de resultaten daarvan wil opslaan moet je de gegevens in de ListView eerst uitlezen.
Dat kan met een tekstreeks of met een Array.
Vervolgens kun je de Array inlezen in een Excel-werklad.
Een tekstreeks kun je bijv. opslaan in een Word, .txt of .csv-bestand.

Via een Array
With LV_00
ReDim sp(.ListItems.Count, .ColumnHeaders.Count)

For jj = 0 To .ColumnHeaders.Count - 1
sp(0, jj) = .ColumnHeaders(jj + 1).Text
Next

For j = 1 To UBound(sp)
sp(j, 0) = .ListItems(j)
For jj = 0 To UBound(sp, 2) - 1
sp(j, jj + 1) = .ListItems(j).ListSubItems(jj + 1)
Next
Next
End With

Sheet2.Cells(1).Resize(UBound(sp), UBound(sp, 2) + 1) = sp
Via een tekstreeks

Als de eerste 2 ListSubItem-kolommen sorteerkolommen zijn:
With LV_00
For jj = 1 To .ColumnHeaders.Count
If .ColumnHeaders(jj).Text <> "" Then c00 = c00 & "," & .ColumnHeaders(jj).Text
Next

For j = 1 To .ListItems.Count
c00 = c00 & vbCrLf & .ListItems(j)
For jj = 3 To .ListItems(j).ListSubItems.Count
c00 = c00 & "," & .ListItems(j).ListSubItems(jj)
Next
Next
End With

MsgBox Mid(c00, 2)
CreateObject("scripting.filesytemobject").createtextfile("G:\OF\ListView.csv").write c00