t j
t j

Reputation: 413

Resizing Label Does Not Change Label Height

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

Answers (3)

Fred
Fred

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

ndori
ndori

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

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

Related Questions