VCL Delphi

Title: TListBox with WordWrap
Question: TListBox gives no possibility to wrap lines. If there is a long line it is invisible since scrolling is enabled. With the help of two events of TListBox it is possible to display wrapped lines without changing the number of total lines.
Answer:
TListBox gives the possibility to draw items yourself. There also the possibility to set a custom height for every single item. For doing so Style has to be set to lbOwnerDrawVariable. Then there are two events that can be used. OnMeasureItem is for telling Delphi the height of the item and OnDrawItem for drawing the item. Now wrapped text can be displayed: First it is necessary to obtain the actual size of wrapped then. Second the text has to be drawn on the canvas of the ListBox. Neither the item itself nor the number of items in the TListBox has to be changed with means that the rest of the source needs not to be changed.
Here is the code:
type
TWrapRecord=record
Height:Integer;
Lines: array of string;
end;
function WrapText(Canvas:TCanvas; Text:string;
const MaxWidth:integer):TWrapRecord;
var S:string;
CurrWidth:integer;
begin
SetLength(Result.Lines,0);
Result.Height:=0;
CurrWidth:=MaxWidth;
Text:=Text+' ';
repeat
S:=copy(Text,1,pos(' ',Text)-1);
Delete(Text,1,pos(' ',Text));
if (Canvas.TextWidth(S+' ')+CurrWidth)then
begin
with Result do Lines[High(Lines)]:=Lines[High(Lines)] + ' ' +S;
Inc(CurrWidth, Canvas.TextWidth(S+' '));
end
else with Result do
begin
if length(Lines)0 then Inc(Height,Canvas.TextHeight(Lines[High(Lines)]));
SetLength(Lines,length(Lines)+1);
Lines[High(Lines)]:=S;
CurrWidth:=Canvas.TextWidth(S);
end;
until length(TrimRight(Text))=0;
with Result do Inc(Height,Canvas.TextHeight(Lines[High(Lines)]));
end;
procedure TForm1.ListBoxMeasureItem(Control: TWinControl; Index: Integer;
var Height: Integer);
var WrapRecord:TWrapRecord;
begin
with Control as TListBox do
begin
Canvas.Font.Assign(Font);
WrapRecord:=WrapText(Canvas,Items[Index],ClientWidth);
if WrapRecord.Heightthen WrapRecord.Height:=ItemHeight;
end;
Height:=WrapRecord.Height;
end;
procedure TForm1.ListBoxDrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
var WrapRecord:TWrapRecord;
i,y:integer;
begin
with Control as TListBox do
begin
Canvas.Font.Assign(Font);
Canvas.FillRect(Rect);
WrapRecord:=WrapText(Canvas,Items[Index],ClientWidth);
y:=Rect.Top;
for i:=Low(WrapRecord.Lines) to High(WrapRecord.Lines) do
begin
Canvas.TextOut(Rect.Left,y,WrapRecord.Lines[i]);
Inc(y,Canvas.TextHeight(WrapRecord.Lines[i]));
end;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ListBox.OnMeasureItem:=ListBoxMeasureItem;
ListBox.OnDrawItem:=ListBoxDrawItem;
ListBox.Style:=lbOwnerDrawVariable;
end;