Sign in Join
Wiki copytemporary

ListBox with separators: what changed

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

OldNewLine
11The 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.
22
3-<figure>
4-<img src="listbox_dividers.png" title="listbox_dividers.png" />
5-<figcaption>listbox_dividers.png</figcaption>
6-</figure>
3+![](/wiki-images/7/7a/Listbox_dividers.png)
74
85``` pascal
96unit Unit1;
107
118{$mode objfpc}{$H+}
129
1310interface
1411
1512uses
1613 Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Types;
1714
1815type
1916
2017 { TForm1 }
2118
2219 TForm1 = class(TForm)
2320 ListBox1: TListBox;
2421 procedure FormCreate(Sender: TObject);
2522 procedure ListBox1DrawItem(Control: TWinControl; Index: Integer;
2623 ARect: TRect; State: TOwnerDrawState);
2724 procedure ListBox1MeasureItem(Control: TWinControl; Index: Integer;
2825 var AHeight: Integer);
2926 private
3027
3128 public
3229
3330 end;
3431
3532var
3633 Form1: TForm1;
3734
3835implementation
3936
4037{$R *.lfm}
4138
4239uses
4340 LCLType;
4441
4542{ TForm1 }
4643
4744procedure TForm1.FormCreate(Sender: TObject);
4845begin
4946 with ListBox1.Items do begin
5047 Add('Paris');
5148 Add('Rome');
5249 Add('London');
5350 Add('Berlin');
5451 Add('-Casablanca');
5552 Add('Cairo');
5653 Add('Khartoum');
5754 Add('Pretoria');
5855 Add('-Tokyo');
5956 Add('Beijing');
6057 Add('Manila');
6158 Add('-New York');
6259 Add('Chicago');
6360 Add('Rio de Janeiro');
6461 Add('Lima');
6562 Add('-');
6663 end;
6764end;
6865
6966const
7067 MARGIN_LINE = 2;
7168 MARGIN_TEXT = 12;
7269 MARGIN_VERT = 2;
7370 HLINE = 1;
7471
7572procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
7673 ARect: TRect; State: TOwnerDrawState);
7774var
7875 lb: TListbox;
7976 s: String;
8077 hasLine: Boolean;
8178 dy: Integer;
8279begin
8380 lb := Control as TListbox;
8481 s := lb.Items[Index];
8582 hasLine := (s <> '') and (s[1] = '-');
8683 if hasLine then dy := HLINE else dy := 0;
8784 lb.Canvas.Brush.Style := bsSolid;
8885 lb.Canvas.Font.Assign(lb.Font);
8986 if odSelected in State then
9087 begin
9188 if hasLine then
9289 begin
9390 lb.Canvas.Brush.Color := lb.Color;
9491 lb.Canvas.FillRect(ARect.Left, ARect.Top, ARect.Right, ARect.Top+dy);
9592 inc(ARect.Top, HLINE + 2);
9693 end;
9794 if lb.Focused then
9895 lb.Canvas.Brush.Color := clHighlight
9996 else
10097 lb.Canvas.Brush.Color := clGray;
10198 lb.Canvas.Font.Color := clHighlightText;
10299 end else
103100 begin
104101 lb.Canvas.Brush.Color := lb.Color;
105102 lb.Canvas.Font.Color := clWindowText;
106103 dy := 0;
107104 end;
108105
109106 lb.Canvas.FillRect(ARect);
110107
111108 if hasLine then
112109 begin
113110 if not (odSelected in State) then
114111 begin
115112 lb.Canvas.Pen.Style := psSolid;
116113 lb.Canvas.Pen.Color := clWindowText;
117114 lb.Canvas.Line(
118115 ARect.Left + MARGIN_LINE,
119116 ARect.Top + HLINE,
120117 ARect.Right - MARGIN_LINE,
121118 ARect.Top + HLINE
122119 );
123120 end;
124121 Delete(s, 1, 1);
125122 end;
126123
127124 lb.Canvas.Brush.Style := bsClear;
128125 lb.Canvas.TextOut(
129126 ARect.Left + MARGIN_TEXT,
130127 (ARect.Top + dy + ARect.Bottom - lb.Canvas.TextHeight('Tg')) div 2,
131128 s
132129 );
133130end;
134131
135132procedure TForm1.ListBox1MeasureItem(Control: TWinControl; Index: Integer;
136133 var AHeight: Integer);
137134var
138135 lb: TListbox;
139136 h: Integer;
140137 s: String;
141138begin
142139 lb := Control as TListBox;
143140 lb.Canvas.Font.Assign(lb.Font);
144141 h := lb.Canvas.TextHeight('Tg') + MARGIN_VERT * 2;
145142 s := lb.Items[Index];
146143 if (s <> '') and (s[1] = '-') then
147144 inc(h, HLine);
148145 AHeight := h;
149146end;
150147
151148end.
152149```
153150
154151---
155152*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).*
156153Category: Code Snippets

Back to history