问题 我可以根据它包含的文本制作TMemo大小吗?


在表单设计器中编辑TLabel的标题时,它会为您调整TLabel的大小。有没有办法在运行时让TMemo做到这一点?

我希望能够接受一个TMemo,为它的.lines.text属性赋值,然后告诉它自己调整大小并且不超过一定宽度,尽管它可以达到它想要的高度。谁知道怎么做?


4169
2018-06-01 17:38


起源



答案:


设置 WordWrap 的财产 TMemo 为true,将文本转储到其中,计算线条,并将高度设置为行数和行高的乘积,但您需要知道行高。

TMemo 不显示行高属性,但如果您不在运行时更改字体或字体大小,则可以在设计时通过实验确定行高。

这是我用来设置高度的代码 TMemo 行高为13像素。我还发现我需要一个小常数来解释 TMemo的顶部和底部边界。我将高度限制为30行(396像素)以保持在表格上。

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

如果绝对必须在运行时从对象中提取行高,那么您可以使用 有人回答。或者,你可以使用 TRichEdit哪个有 SelAttributes 属性包含 Height 给出线高的属性。

-Al。


6
2018-06-01 18:44



我应该想到这一点。我太习惯使用在CRLF上进行换行的TStringLists,我从未想到WordWrap属性实际上会将包装线放在不同的.Lines字符串上。谢谢! - Mason Wheeler
Font.Height包含一个负数,用于计算文本行中的像素数。您也可以调用Canvas.TextExtent来计算文本高度。 - Stijn Sanders


答案:


设置 WordWrap 的财产 TMemo 为true,将文本转储到其中,计算线条,并将高度设置为行数和行高的乘积,但您需要知道行高。

TMemo 不显示行高属性,但如果您不在运行时更改字体或字体大小,则可以在设计时通过实验确定行高。

这是我用来设置高度的代码 TMemo 行高为13像素。我还发现我需要一个小常数来解释 TMemo的顶部和底部边界。我将高度限制为30行(396像素)以保持在表格上。

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

如果绝对必须在运行时从对象中提取行高,那么您可以使用 有人回答。或者,你可以使用 TRichEdit哪个有 SelAttributes 属性包含 Height 给出线高的属性。

-Al。


6
2018-06-01 18:44



我应该想到这一点。我太习惯使用在CRLF上进行换行的TStringLists,我从未想到WordWrap属性实际上会将包装线放在不同的.Lines字符串上。谢谢! - Mason Wheeler
Font.Height包含一个负数,用于计算文本行中的像素数。您也可以调用Canvas.TextExtent来计算文本高度。 - Stijn Sanders


这对我来说很好。添加的常数(8)可能会因您使用边框和/或斜角而有所不同,请尝试使用它。

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;

7
2018-06-01 18:28



很好的答案。我选择了另一个,因为它更简单,但这很好用。顺便说一句,你不需要担心+8;你可以只分配ClientHeight并让系统处理边界。 - Mason Wheeler
我知道这已经过时了,但我尝试了@MasonWheeler的建议并且它从未正常工作过。我相信因为ClientHeight包含Memo具有的内部填充。因此,即使设置ClientHeight,您也需要调用EM_GETRECT来真正计算大小调整。 - Tony


我已经实现了一个自我增长的TMemo作为LiveBindings的一个很好的例子(我可以在VCL中为LiveBindings提供的几个有用的例子之一)。

引自我的Delphi XE2开发基础课程手册:

“要构建此示例,请将TMemo组件放在VCL表单上,打开LiveBindings属性,然后选择”New LiveBinding“选项。选择TBindExpression选项。在Object Inspector中打开BindExpressionMemo11并将SourceComponent设置为Memo1,将SourceExpression设置为Lines。数* 22。 要在运行时获得更好的结果,请将SourceExpression设置为更精确的表达式

Font.Size - 4 +(Lines.Count + 1)* -1 *(Font.Height - 3)

最后,在TMemo的OnChange事件处理程序中,编写一行代码:

BindingsList1.Notify(Sender,'');

而已。编译并运行以查看正在增长的备忘录。

[屏幕快照]

最初,TMemo控件将是两行高(包含内容的行和下一行),每当我们按下enter或自动换行将我们推进到下一行时,TMemo控件的高度会增加(实际上,因此,请确保在表单上留出足够的空间,以便TMemo自行扩展。“

Groetjes,Bob Swart


2
2017-11-04 14:49



我对这个答案感到非常兴奋,但它似乎不再是柏林XE10的选择。 - Tony


procedure TTmpMessage.edMsgChange (Sender: TObject);
var
    LineHeight : Integer;
    DC         : HDC;
    SaveFont   : HFont;
    Metrics    : TTextMetric;
begin
    DC := GetDC ( TRxRichEdit (Sender).Handle );
    SaveFont := SelectObject ( DC, TRxRichEdit (Sender).Font.Handle );
    GetTextMetrics (DC, Metrics);
    SelectObject (DC, SaveFont);
    ReleaseDC ( TRxRichEdit (Sender).Handle, DC );
    LineHeight := Metrics.tmHeight;
    Height := TRxRichEdit (Sender).Lines.Count * LineHeight + 32;
end;

1
2017-11-04 13:51





为什么不呢:

Memo1.Height := Memo1.ContentBounds.Height + 5;

0
2018-04-16 08:51



因为它不是fmx - Sertac Akyuz