TListBox
│
Deutsch (de) │
English (en) │
suomi (fi) │
français (fr) │
日本語 (ja) │
A TListBox
is a component that shows a (scrollable) list of (short) strings where user is to select one. It is available from the Standard tab of the Component Palette.
In the TListBox, the stored strings are stored in the property Items, that is of type TStrings. Thus you can assign or remove strings in the ListBox, as in a TStringList or its parent TStrings.
Here are a few examples of how to use a TListBox ListBox1 on a form Form1:
Fill ListBox
by the Object Inspector
- Select the ListBox on your form with one click.
- Go in the Object Inspector in the Properties tab on the property Items.
- Click on the button with the three dots. The String Editor opens.
- Enter your text and confirm your work with OK.
by code in button click
Add your form a TButton with the name btnFill and caption fill ListBox. In the event handler OnClick of the button, you write the following code:
procedure TForm1.btnFillClick(Sender: TObject);
begin
ListBox1.Items.Clear; //Delete all existing strings
ListBox1.Items.Add('First line');
ListBox1.Items.Add('Line with random number '+IntToStr(Random(100)));
ListBox1.Items.Add('Third line');
ListBox1.Items.Add('Even a random number '+IntToStr(Random(100)));
end;
Assignment of a StringList
Add your form a TButton with the name btnFill and caption fill ListBox. In the event handler OnClick of the button, you write the following code:
procedure TForm1.btnFillClick(Sender: TObject);
var
myStringList: TStringList;
begin
myStringList:=TStringList.Create; //Create my StringList
myStringList.Add('This is the first line.'); //This add a row
myStringList.Add('This is the second first line.');
myStringList.Add('This is the third line.');
myStringList.Add('etc.');
ListBox1.Items.Assign(myStringList); //assign the ListBox1 the text content of my StringList
myStringList.Free; //Free my StringList in memory
end;
Add string
- Extend the example Fill ListBox by code in button click to a TEdit and a TButton with the name btnAdd and caption add string. Change of Edit1 the property Text to "" - empty string.
- In the event handler OnClick of the button, you write the following code:
procedure TForm1.btnAddClick(Sender: TObject);
begin
ListBox1.Items.Add(Edit1.Text);
Edit1.Text:='';
end;
Delete string
By default is set that you can select only one row in your list box. Do you want to select several of the lines in your ListBox, you would have the property MultiSelect to make True.
at ItemIndex
- Extend the example Add string to a TButton with the name "btnDel" and caption "delete string".
- In the event handler OnClick of the button, you write the following code:
procedure TForm1.btnDelClick(Sender: TObject);
begin
if ListBox1.ItemIndex > -1 then //Delete only when a string in the listbox is selected
ListBox1.Items.Delete(ListBox1.ItemIndex);
end;
all selected strings
- Extend the example Add string to a TButton with the name "btnDel" and caption "delete string".
- In the event handler OnClick of the button, you write the following code:
procedure TForm1.btnDelClick(Sender: TObject);
var
i: Integer;
begin
if ListBox1.SelCount > 0 then //Delete only if at least one string in the list box is selected
for i:=ListBox1.Items.Count - 1 downto 0 do //Iterate through all the items
if ListBox1.Selected[i] then //If selected...
ListBox1.Items.Delete(i); //...delete the item (String)
end;
Owner-drawn ListBox
In general, it is advantageous to let the ListBox follow the theme set by the user. In some cases (for example, to program a game with a colorful surface), you can deviate from this standard and draw the control according to your own choice. You can try this now:
- You can modify the previous sample or create a new application with a TListBox ListBox1.
- In the Object Inspector, change ListBox1 property Style to lbOwnerDrawFixed.
- With the Object Inspector, tab events, create the event handler for the event OnDrawItem, by clicking on the button [...].
- You add the following code to the handler:
procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
ARect: TRect; State: TOwnerDrawState);
var
aColor: TColor; //Background color
begin
if (Index mod 2 = 0) //Index tells which item it is
then aColor:=$FFFFFF //every second item gets white as the background color
else aColor:=$EEEEFF; //every second item gets pink background color
if odSelected in State then aColor:=$0000FF; //If item is selected, then red as background color
ListBox1.Canvas.Brush.Color:=aColor; //Set background color
ListBox1.Canvas.FillRect(ARect); //Draw a filled rectangle
ListBox1.Canvas.Font.Bold:=True; //Set the font to "bold"
ListBox1.Canvas.TextRect(ARect, 2, ARect.Top+2, ListBox1.Items[Index]); //Draw Itemtext
end;
Note: Parameters of ListBoxDrawItem:
If multiple controls (E.g. multiple ListBoxes) access this event handle, you know which threw this event. You could in our example, instead of
ListBox1.Canvas.FillRect(ARect)
TListBox(Control).Canvas.FillRect(ARect)
if Control is TListBox then
TListBox(Control).Canvas.FillRect(ARect);
Index:
Specifies the item location, so you have access to the string<ListBox>.Items[Index]
ARect:
Describes the rectangle, which is necessary for drawing the background.
State:
Status of the items, whether normal, focused, selected etc.
- Your example could look like:
Virtual mode
While a "normal" listbox as discussed so far stores its strings inside the listbox itself (or, to be more precise, inside the widgetset), a "virtual" listbox can have its strings in any data structure, such as an array or a TList. There is no need to "add" the strings to the Items of the listbox, and therefore, a virtual listbox can be must faster.
Setting up a virtual listbox
These are the steps to use a listbox in virtual mode:
- Set the Style of the listbox to lbVirtual.
- Set the Listbox.Count to the number of strings that the listbox will contain. Note that writing to Listbox.Count in a non-virtual style raises an exception.
- Provide a handler for the event OnData which tells the listbox where it will find the string at a given index in the external data structure. Assuming that the strings are held in an array of strings named MyStringData then the OnData handler should return in the Data argument the string at the specified index:
procedure TForm1.ListBox1Data(AControl: TWinControl; Index: Integer;
var Data: String);
begin
Data := MyStringData[Index];
end;
- If the Listbox needs objects assigned to the strings (like those added by Listbox.Items.AddObject('SampleString', SampleObject) in the "normal" listbox) you can provide another event handler for the OnGetDataObject event which has the parameter signature (AControl: TWinControl; Index: Integer; var DataObject: TObject).
- A third event handler, OnDataFind, is available to return the index of a given FindString in the external string storage. While this is essential in Delphi to access the individual strings from the Listbox this behaviour is built into the Lazarus virtual Listbox, and it is not required to use this event - it is just kept for Delphi compatibility.
An owner-drawn virtual listbox
In Delphi there is another listbox Style besides lbVirtual, lbVirtualOwnerDraw, which allows you to draw the virtual listbox items in your own code. In Lazarus, this Style is not implemented because this feature is built into the standard virtual Style, lbVirtual. When a handler for the event OnDrawItem is available the code written here is used to draw the specified listbox item, otherwise the default drawing code is used.
In the following example we are owner-drawing the rows of a virtual listbox in alternating colors, and each item gets a consecutive icon from a provided imagelist:
procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
ARect: TRect; State: TOwnerDrawState);
var
bmp: TBitmap;
idx: Integer;
bkClr: TColor;
begin
// Setup background and text color
Listbox1.Canvas.Font.Assign(Listbox1.Font);
if odd(Index) then
bkClr := $F8F8F8
else
bkClr := Color;
if [odSelected, odFocused] * State <> [] then
begin
bkClr := clHighlight;
Listbox1.Canvas.Font.Color := clHighlightText;
end;
Listbox1.Canvas.Brush.Color := bkClr;
// Draw the background
Listbox1.Canvas.FillRect(ARect);
// Extract the image from the image list
bmp := TBitmap.Create;
idx := Index mod ImageList1.Count;
ImageList1.GetBitmap(idx, bmp);
// ... and draw it
Listbox1.Canvas.Draw(
ARect.Left,
(ARect.Top + ARect.Bottom - bmp.Height) div 2,
bmp
);
// Draw the item text
Listbox1.Canvas.TextOut(
ARect.Left + bmp.Width,
(ARect.Top + ARect.Bottom - ListBox1.canvas.TextHeight('Tg')) div 2,
Listbox1.Items[Index]
);
bmp.Free;
end;
Note that, for simplicity, drawing of the imagelist bitmaps is not high-dpi-aware here.
See also


