Sign in Join
Wiki copytemporary

ListBox with separators: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: ListBox with separators

OldNewLine
1+The following sample code illustrates how dividing lines (separators) can be inserted between items in order to better group them. The text of items following a separator line must begin with a `'-'` character to define the divider. The listbox `Style` must be set to `lbOwnerDrawVariable` in order to activate owner-drawing with variable line heights: The `OnMeasureItem` event handler is responsible for the line height calculation; it must add a few pixels to the line height of the `'-'` carrying items to reserve space for the separators. And the `OnDrawItem` event handler must paint the separator line and remove the `'-'` from the separator-defining item text.
2+
3+<figure>
4+<img src="listbox_dividers.png" title="listbox_dividers.png" />
5+<figcaption>listbox_dividers.png</figcaption>
6+</figure>
7+
8+``` pascal
9+unit Unit1;
10+
11+{$mode objfpc}{$H+}
12+
13+interface
14+
15+uses
16+ Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Types;
17+
18+type
19+
20+ { TForm1 }
21+
22+ TForm1 = class(TForm)
23+ ListBox1: TListBox;
24+ procedure FormCreate(Sender: TObject);
25+ procedure ListBox1DrawItem(Control: TWinControl; Index: Integer;
26+ ARect: TRect; State: TOwnerDrawState);
27+ procedure ListBox1MeasureItem(Control: TWinControl; Index: Integer;
28+ var AHeight: Integer);
29+ private
30+
31+ public
32+
33+ end;
34+
35+var
36+ Form1: TForm1;
37+
38+implementation
39+
40+{$R *.lfm}
41+
42+uses
43+ LCLType;
44+
45+{ TForm1 }
46+
47+procedure TForm1.FormCreate(Sender: TObject);
48+begin
49+ with ListBox1.Items do begin
50+ Add('Paris');
51+ Add('Rome');
52+ Add('London');
53+ Add('Berlin');
54+ Add('-Casablanca');
55+ Add('Cairo');
56+ Add('Khartoum');
57+ Add('Pretoria');
58+ Add('-Tokyo');
59+ Add('Beijing');
60+ Add('Manila');
61+ Add('-New York');
62+ Add('Chicago');
63+ Add('Rio de Janeiro');
64+ Add('Lima');
65+ Add('-');
66+ end;
67+end;
68+
69+const
70+ MARGIN_LINE = 2;
71+ MARGIN_TEXT = 12;
72+ MARGIN_VERT = 2;
73+ HLINE = 1;
74+
75+procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
76+ ARect: TRect; State: TOwnerDrawState);
77+var
78+ lb: TListbox;
79+ s: String;
80+ hasLine: Boolean;
81+ dy: Integer;
82+begin
83+ lb := Control as TListbox;
84+ s := lb.Items[Index];
85+ hasLine := (s <> '') and (s[1] = '-');
86+ if hasLine then dy := HLINE else dy := 0;
87+ lb.Canvas.Brush.Style := bsSolid;
88+ lb.Canvas.Font.Assign(lb.Font);
89+ if odSelected in State then
90+ begin
91+ if hasLine then
92+ begin
93+ lb.Canvas.Brush.Color := lb.Color;
94+ lb.Canvas.FillRect(ARect.Left, ARect.Top, ARect.Right, ARect.Top+dy);
95+ inc(ARect.Top, HLINE + 2);
96+ end;
97+ if lb.Focused then
98+ lb.Canvas.Brush.Color := clHighlight
99+ else
100+ lb.Canvas.Brush.Color := clGray;
101+ lb.Canvas.Font.Color := clHighlightText;
102+ end else
103+ begin
104+ lb.Canvas.Brush.Color := lb.Color;
105+ lb.Canvas.Font.Color := clWindowText;
106+ dy := 0;
107+ end;
108+
109+ lb.Canvas.FillRect(ARect);
110+
111+ if hasLine then
112+ begin
113+ if not (odSelected in State) then
114+ begin
115+ lb.Canvas.Pen.Style := psSolid;
116+ lb.Canvas.Pen.Color := clWindowText;
117+ lb.Canvas.Line(
118+ ARect.Left + MARGIN_LINE,
119+ ARect.Top + HLINE,
120+ ARect.Right - MARGIN_LINE,
121+ ARect.Top + HLINE
122+ );
123+ end;
124+ Delete(s, 1, 1);
125+ end;
126+
127+ lb.Canvas.Brush.Style := bsClear;
128+ lb.Canvas.TextOut(
129+ ARect.Left + MARGIN_TEXT,
130+ (ARect.Top + dy + ARect.Bottom - lb.Canvas.TextHeight('Tg')) div 2,
131+ s
132+ );
133+end;
134+
135+procedure TForm1.ListBox1MeasureItem(Control: TWinControl; Index: Integer;
136+ var AHeight: Integer);
137+var
138+ lb: TListbox;
139+ h: Integer;
140+ s: String;
141+begin
142+ lb := Control as TListBox;
143+ lb.Canvas.Font.Assign(lb.Font);
144+ h := lb.Canvas.TextHeight('Tg') + MARGIN_VERT * 2;
145+ s := lb.Items[Index];
146+ if (s <> '') and (s[1] = '-') then
147+ inc(h, HLine);
148+ AHeight := h;
149+end;
150+
151+end.
152+```
153+
154+---
155+*From the Free Pascal wiki, page "ListBox with separators", as it stood on 2023-08-19 after a change by Wp, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
156+Category: Code Snippets

Back to history