Reputation: 413
How do you get the label height to automatically adjust when resizing the form? All of the properties are set. Align is top. Autosize is true. Word wrap is true.
When I change the form size the label adjust the caption fine. However, the actual label will not resize its height.
This leaves a gap when the form width is increasing or it leaves the bottom part of the caption unreadable. Makes it ugly when you have controls below the label that should move up or down depending on the label's height.
I would hate to do this using the form's resize event. Too bad there is no form "resize end" event.
Any help? Thanks.
Upvotes: 1
Views: 3152
Reputation: 25
I've spent quite some time to get both the wordwrap and the height of a series of labels right. The previous answer (thanks ndori), using the pointless-looking solution of first making Autosize false, followed by setting it to true is the solution! Below my code for publishing a (long) series of labels, where the caption text is generated somewhere else and can be as short as one character up to several lines of text. So, I need a fixed label width, active wordwrap and a constant white space between all different labels. When resizing the form the label.width (arbitrary set to 560 below) may be adjusted to fit the new form when resizing. I think the real problem is getting the label heights correctly displayed.
{ AL[] = global variable: array of TLabel
{ AL[].caption (the text) is delivered elsewhere, and can be short or long (= multiline text)
{ N_ActiveLabels = global integer variable: # of active labels to publish }
procedure PublishListOfLabels;
var
i : integer;
begin
AL[0].Top := 15; // or whatever
AL[0].Visible := true;
AL[0].Width := 560; // (re)set this here as otherwise the wordwrap makes
// the label text a long narrow column!
AL[0].AutoSize := false; // THIS IS REQUIRED!
AL[0].AutoSize := true; // THIS IS REQUIRED!
if N_ActiveLabels > 1 then begin
for i := 1 to N_ActiveLabels -1 do begin
AL[i].Visible := true;
AL[i].Width := 560;
AL[i].AutoSize := false;
AL[i].AutoSize := true;
AL[i].Top := AL[i-1].Top + AL[i-1].Height + 18;
// 18 was chosen as vertical white space between any two labels
end;
end;
end;
I found repainting (or refreshing) of the labels not needed. I also encountered solutions like:
H := AL[i].Canvas.TextHeight(AL[i].caption);
where H is supposed to contain the real height of AL[i] (after filling its caption with text and calling PublishListOfLabels. it is NOT working. I mention this as this solution has been proposed at several other places dealing with the same issue (getting a correct TLabel height). [I use Berlin 10.1 - perhaps later versions have solved the Autosize.false /.true aberation]
Upvotes: 0
Reputation: 1994
I've solved by inheriting from tlabel. there is a bug with the autosize in this case (autosize, wordwrap and alTop)
to make it recalculate it size you need to:
AutoSize := false;
AutoSize := true;
so you can override the resize procedure like that:
procedure TResizableLabel.Resize;
begin
AutoSize := false;
AutoSize := true;
end;
however if you will do it on every resize it will shrink the width also, so you will lose the width of the parent from alTop, in case it is just aligned left it will probably be ok, but if you want center or right alignment you will need a better solution.
this is the full solution, it will call the autosize only when needed:
TResizableLaber = class(TLabel)
protected
FTextHeight, FTextWidth : integer;
function GetCaption : TCaption;
procedure SetCaption(ACaption : TCaption);
function GetFont : TFont;
procedure SetFont(AFont : TFont);
public
procedure Resize; override;
property Caption : TCaption read GetCaption write SetCaption;
property Font : TFont read GetFont write SetFont;
end;
implementation
procedure TResizableLaber.Resize;
var
num : double;
begin
inherited;
if AutoSize then
begin
if (FTextHeight = 0) or (FTextWidth = 0) then
begin
//lazy evaluation, we re evaluate every time the caption or font changes
FTextWidth := Utills.GetTextWidth(Caption, Font);
FTextHeight := Utills.GetTextHeight(Caption,Font);
end;
//TODO: there is still one bug here, set alCenter and make the last word long enough so it cant always wrapped to the line before, even though there is globally enough space
num := ( Height / FTextHeight) - (FTextWidth /Width );
//if num is greater then 1 it means we need an extra line, if it is lower then zero it means there is an extra line
if (num > 1) or (num < 0) then
begin
//just doing this all the time will cause it to really resize and will break alTop matching the whole space
AutoSize := false;
AutoSize := true;
end;
end;
end;
function TResizableLaber.GetCaption : TCaption;
begin
Result := inherited Caption;
end;
procedure TResizableLaber.SetCaption(ACaption : TCaption);
begin
FTextWidth := Utills.GetTextWidth(ACaption, Self.Font);
FTextHeight := Utills.GetTextHeight(ACaption,Self.Font);
inherited Caption := ACaption;
end;
function TResizableLaber.GetFont : TFont;
begin
Result := inherited Font;
end;
procedure TResizableLaber.SetFont(AFont : TFont);
begin
FTextWidth := Utills.GetTextWidth(Caption, AFont);
FTextHeight := Utills.GetTextHeight(Caption,AFont);
inherited Font := AFont;
end;
class function Utills.GetTextHeight(const Text:String; Font:TFont) : Integer;
var
bitmap: TBitmap;
begin
bitmap := TBitmap.Create;
try
bitmap.Canvas.Font := Font;
Result := bitmap.Canvas.TextHeight(Text);
finally
bitmap.Free;
end;
end;
class function Utills.GetTextWidth(const Text:String; Font:TFont) : Integer;
var
bitmap: TBitmap;
begin
bitmap := TBitmap.Create;
try
bitmap.Canvas.Font := Font;
Result := bitmap.Canvas.TextWidth(Text);
finally
bitmap.Free;
end;
end;
Upvotes: 2
Reputation: 28839
If I recall correctly, with Autosize
set to true
, the height of the label is automatically set to the actual height of the text in Caption
.
You might try setting Autosize
to false
and see how that works for you.
Upvotes: 1