Windows Programmierung: List View |
Einführende Informationen über die Programmierung von Kontrollelementen werden hier vorausgesetzt.
Ein ListView unterscheidet sich von der bisher bekannten Listbox in diversen Details. Während die Listbox typischerweise eine Liste von Textzeilen repräsentiert, ist das ListView eher die Darstellung von Objekten. Beide Elemente können mehrere Spalten darstellen. Das ListView ermöglicht eine Überschrift und die Verwendung dieser als Schaltleiste.
LVS_ALIGNLEFT | Linksbündig (ICON und SMALLICON) |
LVS_ALIGNTOP | Obenbündig (ICON und SMALLICON) |
LVS_AUTOARRANGE | Elemente richten sich automatisch selbst aus (ICON und SMALLICON) |
LVS_EDITLABELS | Die Labels sind direkt editierbar. |
LVS_NOCOLUMNHEADER | Spaltenüberschriften sind nicht sichtbar (REPORT) |
LVS_NOLABELWRAP | Das Label bricht bei langen Zeilen nicht um. (ICON) |
LVS_NOSCROLL | Das Scrollen ist abgeschaltet. Alle Elemente müssen innerhalb der Clientfläche dargestellt werden. (ICON und SMALLICON) |
LVS_NOSORTHEADER | Die Spaltenüberschriften arbeiten nicht als Schaltflächen. Sinnvoll, wenn Sortierung o. ä. nicht unterstützt wird. |
LVS_OWNERDATA | Version 4.70. Specifiziert ein virtuelles ListView. |
LVS_OWNERDRAWFIXED | Die Anwendung zeichnet die Elemente. Sie erhält dazu die WM_DRAWITEM-Nachricht. (REPORT) |
LVS_SHAREIMAGELISTS | Die Imageliste wird nicht gelöscht, wenn das ListView zerstört wird. |
LVS_SHOWSELALWAYS | Die Selektion bleibt auch erhalten, wenn das Element den Fokus verliert. |
LVS_SINGLESEL | Es kann nur ein Element gleichzeitig selektiert werden. Standard ist die Multiselektierbarkeit. |
LVS_SORTASCENDING | Die Item Indizes werden in aufsteigender Folge anhand ihrer Texte sortiert. |
LVS_SORTDESCENDING | Die Item Indizes werden in absteigender Folge anhand ihrer Texte sortiert. |
LVS_SORTASCENDING und LVS_SORTDESCENDING werden bei LIST und REPORT sofort sichtbar, da sie nach der Reihenfolge ihrer Indizes angezeigt werden. Dagegen ist die Position der Icons bei ICON und SMALLICON vom Index unabhängig.
Maske | Maskierte Stile |
---|---|
LVS_TYPEMASK | LVS_ICON, LVS_LIST, LVS_REPORT und LVS_SMALLICON |
LVS_ALIGNMASK | LVS_ALIGNLEFT und LVS_ALIGNTOP |
LVS_TYPESTYLEMASK | LVS_ALIGNLEFT und LVS_ALIGNTOP aber auch LVS_NOCOLUMNHEADER und LVS_NOSORTHEADER |
Bei der folgenden Sequenz enthält dwView den Stil, in den gewechselt werden soll, beispielsweise LVS_REPORT oder LVS_ICON.
DWORD dwStyle = GetWindowLong(hwndLV, GWL_STYLE); // hole aktuellen Stil if ((dwStyle & LVS_TYPEMASK) != dwView) // nur bei Aenderung SetWindowLong(hwndLV, GWL_STYLE, (dwStyle & ~LVS_TYPEMASK) | dwView); } |
#include "commctrl.h" InitCommonControls(); hwndList = CreateWindow(WC_LISTVIEW, "", WS_VISIBLE|WS_BORDER|WS_CHILD | LVS_REPORT | LVS_EDITLABELS, 10, 10, 300, 100, hWnd, (HMENU)ID_LIST, hInst, 0); |
Im Dialog wird sie einfach in der Ressource definiert.
Kommt es zu nicht aufgelösten Externals, sollte man prüfen, ob die Library für die Common Controls (comctl32.lib) eingebunden wird.
int CreateColumn(HWND hwndLV, int iCol, char *Text, int iBreite) { LVCOLUMN lvc; lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; lvc.fmt = LVCFMT_LEFT; lvc.cx = iBreite; lvc.pszText = Text; lvc.iSubItem = iCol; return ListView_InsertColumn(hwndLV, iCol, &lvc); } |
Die Spalten können per Nachricht an das ListView geädert werden oder durch Aufruf von Makros, die letztlich ein SendMessage ausführen.
Nachricht | Makro-Aufruf | Funktion |
---|---|---|
LVM_INSERTCOLUMN | ListView_InsertColumn(HWND, int, LVCOLUMN *) | Spalte einfügen |
LVM_DELETECOLUMN | ListView_DeleteColumn(HWND, int) | Spalte löschen |
LVM_GETCOLUMN | ListView_GetColumn(HWND, int, LVCOLUMN *) | Eigenschaften der Spalte holen |
LVM_SETCOLUMN | ListView_SetColumn(HWND, int, LVCOLUMN *) | Eigenschaften der Spalte ändern |
LVM_GETCOLUMNWIDTH | ListView_GetColumnWidth(HWND, int) | Ermittle Spaltenbreite |
LVM_SETCOLUMNWIDTH | ListView_SetColumnWidth(HWND, int, int) | Setze Spaltenbreite |
int CreateItem(HWND hwndList, char *Text) { LVITEM lvi = {0}; lvi.mask = LVIF_TEXT; lvi.pszText = Text; return ListView_InsertItem(hwndList, &lvi); } |
Das Feld mask bestimmt, welche Elemente der LVITEM-Struktur wirklich verwendet werden. Da es oft sinnvoll ist, einen Zeiger auf das Speicherobjekt mitzuführen, das die Daten hält, die hinter dem Objekt stehen, bietet sich das lParam-Feld an. Damit dies aber auch verwendet wird, muss LVIF_TEXT|LVIF_PARAM als Maske gesetzt werden.
Die Konstanten von mask und die Felder, die sie aktivieren:
LVIF_IMAGE | iImage |
LVIF_INDENT | iIndent |
LVIF_PARAM | lParam |
LVIF_STATE | state |
LVIF_TEXT | pszText |
int Create2ColItem(HWND hwndList, char *Text1, char *Text2) { LVITEM lvi = {0}; int Ret; // Initialize LVITEM members that are common to all items. lvi.mask = LVIF_TEXT; lvi.pszText = Text1; Ret = ListView_InsertItem(hwndList, &lvi); if (Ret>=0) { ListView_SetItemText(hwndList, Ret, 1, Text2); } return Ret; } |
typedef struct _LVITEM { UINT mask; int iItem; int iSubItem; UINT state; UINT stateMask; LPTSTR pszText; int cchTextMax; int iImage; LPARAM lParam; #if (_WIN32_IE >= 0x0300) int iIndent; #endif } LVITEM, FAR *LPLVITEM; |
Mit den Nachrichten LVM_GETITEM und LVM_SETITEM werden die Attribute eines Elements geändert. Sie erhalten als Parameter neben dem HWND des ListViews einen Zeiger auf eine LVITEM-Struktur, die vorher zu besetzen ist.
Die Strukturelemente im Einzelnen:
LVIF_IMAGE | iImage |
LVIF_INDENT | iIndent |
LVIF_PARAM | lParam |
LVIF_STATE | state |
LVIF_TEXT | pszText |
pszText darf nicht auf LPSTR_TEXTCALLBACK gesetzt werden, wenn das ListView den Stil LVS_SORTASCENDING oder LVS_SORTDESCENDING hat.
LVM_INSERTITEM | Einfügung eines Elementes |
LVM_DELETEITEM | Löschen eines Elementes |
LVM_DELETEALLITEMS | Löschen aller Elemente |
LVM_GETITEM | Eigenschaften des Elementes lesen |
LVM_GETITEMTEXT | Text des Elementes lesen |
LVM_SETITEM | Änderung |
LVM_SETITEMTEXT | Änderung am Text |
Vor dem Einfügen mehrerer Items wird dem ListView eine LVM_SETITEMCOUNT Nachricht gesendet werden, die angibt, wieviele Elemente letztlich enthalten wird. Dies ermöglicht es dem ListView seine Speicherreservierung und -freigabe zu optimieren. Wieviele Elemente ein ListView enthält, ist mit LVM_GETITEMCOUNT zu ermitteln.
int Pos = -1; LVITEM Item; Pos = ListView_GetNextItem(hwndList, Pos, LVNI_SELECTED); while (Pos>=0) { Item.iItem = Pos; Item.iSubItem = 0; ListView_GetItem(hwndList, &Item); TuWasMitElement((ElementType*)Item.lParam); Pos = ListView_GetNextItem(hwndList, Pos, LVNI_SELECTED); } |
Nachricht | Beschreibung |
---|---|
LVN_BEGINDRAG | Start einer Drag-And-Drop Aktion |
LVN_BEGINRDRAG | Start einer Drag-And-Drop Aktion über rechte Maustaste |
LVN_BEGINLABELEDIT | Start Editieren eines Labels |
LVN_ENDLABELEDIT | Ende Editieren eines Labels |
LVN_DELETEITEM | Meldet, daß das Item gelöscht wird |
LVN_DELETEALLITEMS | Meldet, daß alle Items gelöscht werden |
LVN_COLUMNCLICK | Zeigt an, daß der Anwendet in den Header einer Reportdarstellung klickte |
LVN_GETDISPINFO | Das Kontrollelement erfragt Informationen zur Darstellung vom Elternfenster |
LVN_SETDISPINFO | Die Information des Elternfensters für das Item muß erneuert werden |
LVN_INSERTITEM | Zeigt das Einfügen eines Items an |
LVN_ITEMCHANGED | Zeigt an, daß ein Item geändert wurde |
LVN_ITEMCHANGING | Zeigt die beabsichtigte Änderung eines Items an |
LVN_KEYDOWN | Taste wurde gedrückt |
case WM_NOTIFY: switch (((LPNMHDR) lParam)->code) { case LVN_ENDLABELEDIT: pItem = (NMLVDISPINFO) lParam; MessageBox(hWnd, pItem->item.pszText, "entry", MB_OK); return TRUE; |
Wurde das Editieren abgebrochen, wird das pszText-Element 0 sein.
Soll das Editieren verhindert werden, wird die Nachricht LVN_BEGINLABELEDIT gefangen und TRUE zurückgegeben. Auch hier kann über lParam in gleicher Weise auf das Item zugegriffen werden und so beispielsweise eine bestimmte Itemgruppe ausgegrenzt werden.
case WM_NOTIFY: switch (((LPNMHDR) lParam)->code) { case LVN_COLUMNCLICK: SpalteNr = ((LPNMLISTVIEW) lParam)->iSubItem; |
case WM_NOTIFY: switch (((LPNMHDR) lParam)->code) { case LVN_ITEMACTIVATE: HWND hwndFrom = (HWND)((LPNMHDR) lParam)->hwndFrom; MarkedItemIndex = ListView_GetNextItem(hwndFrom,-1,LVNI_SELECTED); |
Mit Hilfe der LVM_GETSELECTEDCOUNT-Nachricht kann ermittelt werden, wieviele Items aktiviert wurden. Die LVM_GETNEXTITEM Nachricht wird mit dem Attribut LVNI_SELECTED gesendet bist alle Items bearbeitet wurden.
Homepage - Windows-API-Programmierung | (C) Copyright 1999, 2001 Arnold Willemer |