tags:

views:

620

answers:

2

When you edit a TLabel's caption in the form designer, it resizes the TLabel for you. Is there any way I can get a TMemo to do that, at runtime?

I'd like to be able to take a TMemo, assign something to its .lines.text property, and then tell it to resize itself and not exceed a certain width, though it can get as tall as it wants to. Anyone know how to do that?

+2  A: 

This works just fine for me. The constant added (8) might vary on whether you are using a border and/or bevel, experiment with it.

procedure TForm1.Memo1Change(Sender: TObject);
var
  LineHeight: Integer;
  DC: HDC;
  SaveFont : HFont;
  Metrics : TTextMetric;
  Increase: Integer;
  LC: Integer;
begin
  DC := GetDC(Memo1.Handle);
  SaveFont := SelectObject(DC, Memo1.Font.Handle);
  GetTextMetrics(DC, Metrics);
  SelectObject(DC, SaveFont);
  ReleaseDC(Memo1.Handle, DC);
  LineHeight := Metrics.tmHeight;
  Increase := Memo1.Height;
  LC := Memo1.Lines.Count;
  if LC < 1 then
    LC := 1;
  Memo1.Height := LC * LineHeight + 8;
  Increase := Memo1.Height - Increase;
  Memo1.Parent.Height := Memo1.Parent.Height + Increase;
end;
Nice answer. I picked the other one because it was simpler, but this works pretty well. BTW you don't need to worry about the +8; you can just assign ClientHeight and let the system take care of the border.
Mason Wheeler
+3  A: 

Set the WordWrap property of the memo to true, dump your text into it, count the lines, and set the height to the product of the line count and the line height. But you need to know the line height.

The tMemo object does not expose a line height property, but if you're not changing the font or font size at runtime, you can determine the line height experimentally at design time.

Here's the code I used to set the height of a memo that had a line height of 13 pixels. I also found that I needed a small constant to account for the memo's top and bottom borders. I limited the height to 30 lines (396 pixels) to keep it on the form.

// Memo.WordWrap = true (at design time)
Memo.Text := <ANY AMOUNT OF TEXT>;
Memo.Height := min(19+Memo.Lines.Count*13,396);

If you absolutely must extract the line height from the object at run time, then you must use 'Someone's answer. Or, you can use a tRichEdit object, which has a SelAttributes property containing a Height property giving the line height.

-Al.

A. I. Breveleri
I should have thought of that. I'm too used to working with TStringLists, which do linebreaks at CRLF, that it never occurred to me that the WordWrap property would actually put wrapped lines on different .Lines strings. Thanks!
Mason Wheeler
Font.Height holds a negative number counting the number of pixels in a text line. Also you could call Canvas.TextExtent to have the text height calculated.
Stijn Sanders