Windows Programmierung: Listbox
Willemers Informatik-Ecke
Vor der Verwendung von Listboxen müssen die Common Controls eingebunden werden.
#include <CommCtrl.h>

Listbox im Hauptfenster erzeugen

Soll in einem normalen Fenster eine Listbox erscheinen, muss diese in der
Fensterfunktion (diese heißt beispielsweise WndProc oder WindowProcedure) typischerweise nach dem Eintreffen der Nachricht WM_CREATE erzeugt werden.
case WM_CREATE:
    // ...
    hwndListbox = CreateWindow(WC_LISTBOX, szTitle,
                  WS_VISIBLE|WS_CHILD|WS_BORDER|WS_VSCROLL|WS_HSCROLL|LBS_NOTIFY,
                  x, y, breite, hoehe, hWnd, (HMENU)MYID, 0, 0 );
Die Parameter des Funktionsaufrufs CreateWindow bedeuten im Einzelnen:
WC_LISTBOX
Der erste Parameter von CreateWindow ist die Fensterklasse. Für eine Listbox wird hier WC_LISTBOX angegeben.
szTitle
Der Titel einer Listbox wird eh nicht angezeigt. Hier kann ein leerer String übergeben werden.
WS_xxx
Hier werden die Style-Konstanten angegeben. Die Standard-Fensterstile beginnen mit WS_, die für die Listbox typischen Stile wie hier LBS_NOTIFY beginnen mit LBS_.
x, y, breite, hoehe
x, y, breite und hoehe sind int-Werte für die Position der Listbox. Typischerweise wird diese allerdings nach WM_SIZE sowieso nachgefasst, damit sich die Listbox korrekt im Fenster befindet.
(HMENU)MYID
Hier wird eine Integerkonstante übergeben, die die Listbox aus Programmsicht eindeutig identifiziert. Sie wird auf (HMENU) gecastet.
Rückgabewert
Der Rückgabewert ist das Handle (HWND) der Listbox. Über dieses wird die Listbox angesprochen, um beispielsweise Elemente hinzuzufügen oder die Größe zu verändern.
Die Position der Listbox in einem normalen Fenster passt man am besten auf die Nachricht WM_SIZE hin an. Dort liegt dann auch die Breite und Höhe des Clientbereichs des Fensters im Parameter lParam vor.
case WM_SIZE: // Die Groesse wurde veraendert, die Elemente werden positioniert
    {
        int breite = LOWORD(lParam);
        int hoehe  = HIWORD(lParam);
        MoveWindow(hwndListbox,	10, 10, breite/2-20, hoehe-20, true);

Listbox in der Ressource einer Dialogbox erzeugen

In der rc-Datei können diese Formen der Listbox-Definition vorliegen.
LISTBOX id, x, y, breite, hoehe
LISTBOX id, x, y, breite, hoehe, style
id
Die id ist eine Integer-Konstante, die die Listbox vom Programm her eindeutig identifiziert.
x, y, breite, hoehe
Position der Listbox im Dialog. Die Werte sind keine Pixel, sondern Dialog-Einheiten, die sich an der Größe des Standardzeichensatzes orientieren.
style
Hier werden die Windows-Styles der Listbox eingetragen. Ist der Stil nicht definiert, wird WS_BORDER|LBS_NOTIFY vorausgesetzt.

Stile: Eigenschaften einer Listbox

Die Eigenschaftsflags sind im Ressourcen-Editor oder als Parameter bei CreateWindow anzugeben und bestimmen das Erscheinungsbild der Listbox bis zu ihrer Zerstörung.

LBS_MULTIPLESEL: Mehrfachselektion

Die normale Listbox läßt nur eine einfache Selektion zu. Das erleichtert die Programmierung und auch die Logik des Programmes erheblich. An vielen Stellen kann es aber die Benutzbarkeit des Programmes um ein Vielfaches erhöhen, wenn man eine Mehrfachselektion anbietet.

LBS_MULTIPLESEL ermöglicht die Mehrfachselektion. Mit Hilfe der Shift- und der Control-Taste können mehrere Elemente angewählt werden.

LBS_SORT: Sortierung

Durch den Stil LBS_SORT wird die Listbox Neuzugänge alphabetisch einsortieren. Viele Ressource-Editoren geben diesen Stil vor. Die tatsächliche Position des neuen Eintrags erfährt man aus dem Rückgabewert der entsprechenden Funktionen.

LBS_NOINTEGRALHEIGHT: Größenanpassung

Eine normale Listbox wird in ihrer Größe so ausgerichtet, daß es keine halben Zeilen gibt. In manchen Fällen ist das aber erwünscht. Beispielsweise wenn eine Listbox ein Fenster vollständig ausfüllen soll. Hier hilft die Eigenschaft LBS_NOINTEGRALHEIGHT.

LBS_NOTIFY: Ereignisempfang vorbereiten

Damit eine Listbox Nachrichten auslöst, muss der Stil LBS_NOTIFY definiert sein. Nur Listboxen mit dieser Eigenschaft erhalten bestimmte Nachrichten wie LBN_DBLCLK, LBN_SELCANCEL und LBN_SELCHANGE.

Ereignisbehandlung

Auf die meisten Ereignisse im Zusammenhang mit einer Listbox erhält man eine Nachricht WM_COMMAND. Die Listbox-ID steht im Low-Word von wParam, die eigentliche Nachricht im High-Word. Hier ein Ausschnitt aus der Fensterfunktion, die einen Doppelklick und einen Selektionswechsel auswertet:
   case WM_COMMAND:
      switch(LOWORD(wParam)) {
         case ID_LISTBOX:
            switch (HIWORD(wParam)) {
               case LBN_DBLCLK:
                  ListIndex = SendMessage(hListe, LB_GETCURSEL, 0, 0);
                  Person = (tPerson *)SendMessage(hListe, LB_GETITEMDATA, ListIndex, 0);
                  return TRUE;
               case LBN_SELCHANGE:
                  // lParam enthaelt die hwnd der listbox
                  ListIndex = SendMessage((HWND)lParam, LB_GETCURSEL, 0, 0);
LBN_DBLCLKItem wurde doppelt angeklickt (oder Returntaste)
LBN_SELCANCELAnwender hat Selektion abgebrochen
LBN_SELCHANGEDas selektierte Item wurde gewechselt

Aktionen

Die Listbox wird durch das Zusenden von Nachrichten mit der Funktion SendMessage gesteuert. Der allgemeine Aufruf lautet:
rueck = SendMessage(hwnd, nachricht, wParam, lParam);
Der erste Paramter ist das Handle (HWND) der Listbox. Der zweite das Kommando wie beispielsweise LB_ADDSTRING für das Hinzufügen von Elementen. wParam und lParam werden je nach Bedarf des Kommandos gesetzt. Bei Abfragekommandos liefert der Rückgabewert das Ergebnis.

Hinzufügen und Entfernen von Einträgen

NachrichtwParamlParamRückgabe
LB_ADDSTRING 0 Zeiger auf den StringIndex des neuen Items, bei Fehler LB_ERR
LB_INSERTSTRING Zielindex des Items, -1 für hinten Zeiger auf den String bei Fehler LB_ERR
LB_DELETESTRING Index des Items 0 bei Fehler LB_ERR
LB_RESETCONTENT 0 0 bei Fehler LB_ERR

AddString hängt Einträge hinten an, sofern die Listbox nicht den Style LBS_SORT besitzt. ResetContent löscht alle Einträge der Liste.

Daten hinterlegen

Damit man den Listbox-Einträgen Programmdaten eindeutig zuordnen kann, ist es möglich, jedem Eintrag einen 4-Byte-Wert hinzuzufügen: genug für einen Zeiger auch auf größere Datenobjekte.

NachrichtwParamlParamRückgabe
LB_SETITEMDATA Index des Items4-Byte-DataBei Fehler LB_ERR
LB_GETITEMDATA Index des Items NULL 4-Byte-Data

Selektion auslesen

Um das angewählte Element der Liste auszulesen, wird die Nachricht LB_GETCURSEL an die Listbox gesandt. Der Rückgabewert von SendMessage ist entweder LB_ERR, wenn es keine Selektion gibt, oder ein Wert bei 0 beginnend, der die Position des ausgewählten Elements angibt.

ListIndex = SendMessage((HWND)lParam, LB_GETCURSEL, 0, 0);

Bei Multiselektions-Listboxen wird die Nachricht LB_GETSELITEMS an die Box gesandt. Als Ergebnis wird ein Array von Integern zurückgegeben. Den Speicher dazu stellt die Anwendung. Ein typisches Vorgehen sieht so aus:

SelCount = SendMessage(HwndList, LB_GETSELCOUNT, 0, 0);
int *SelIndex = new int(SelCount);
SelCount = SendMessage(HwndList, LB_GETSELITEMS, SelCount, (LPARAM)SelIndex);
for (int i=0; i<SelCount; i++) {
   ....