1

我有一个 TMemo,我希望它总是足够高以显示它包含的行数。不幸的是,我不太清楚如何计算。我不能基于.Font.Size属性,因为这会因 DPI 而异。而且我不能使用TCanvas.TextHeight,因为 TMemo 似乎没有画布

有人知道如何正确执行此操作吗?

4

4 回答 4

8

我看到一个问题,我认为 TMemo 上的所有行的高度都相等,但有些可能是空的......

因此,当它们在 TMemo 上的高度不是零时,获取空的高度将给出零。

所以解决方案可能会做类似 Memo.Lines.Count*LineHeight

请注意,Canvas.TextHeight 可能无法获取 Lineheight,因为 Canvas.TextHeight 会或多或少地为文本提供最小高度的准确高度......我的意思是它不会为文本“ABC”提供与“ABCp”相同的高度, ETC...

我建议(如果不想调用 Windows API)使用 Font.Height,但如果它是负数,则不测量每行的内部前导......

所以我建议做接下来的步骤(经过测试):

  • 在 OnCreate 事件或您想要的任何地方为 Memo.Font.Height 分配一个正值,这样 TMemo 的 lineheight 将是您分配的值
  • 现在可以通过 Memo.Lines.Count*LineHeight 直接获得总高度,因为您已为 Memo.Font.Height 分配了一个正值(请记住,这会使 Memo.Font.Size 为负)

我个人在 TForm OnCreate 事件上执行此操作(以确保它只执行一次),只是为了确保不更改视觉字体大小并且 MyMemo.Font.Height 包括每行的内部前导:

MyMemo.Font.Height:=Abs(MyMemo.Font.Size*MyMemo.Font.PixelsPerInch div Screen.PixelsPerInch);

确保上一个只执行一次,否则文本大小会越来越大,就像你运行它的次数一样...这是因为并非总是 MyMemo.Font.PixelsPerInch 等于 Screen.PixelsPerInch...在我的情况下,它们分别是 80 和 96。

然后,当我需要知道行高时,我只需使用:

Abs(MyMemo.Font.Height*Screen.PixelsPerInch div 72)

这给出了一个 TMemo 行的精确高度,因为所有行都具有相同的高度,所以总高度将是:

MyMemo.Lines.Count*Abs(MyMemo.Font.Height*Screen.PixelsPerInch div 72)

因此,为了使 TMemo 高度与其包含的文本一样大,我这样做(阅读每一行的注释,它们非常重要):

MyMemo.Font.Height:=Abs(MyMemo.Font.Size*MyMemo.Font.PixelsPerInch div Screen.PixelsPerInch); // I do this on the Tform OnCreate event, to ensure only done once
MyMemo.Height:=1+MyMemo.Lines.Count*Abs(MyMemo.Font.Height*Screen.PixelsPerInch div 72); // I do this anywhere after adding the text and/or after editing it

我你不想玩 Screen.PixelsPerInch 你可以这样做(阅读每一行的注释,它们非常重要):

MyMemo.Font.Height:=Abs(MyMemo.Font.Height); // This may make text size to visually change, that was why i use the corrector by using MyMemo.Font.PixelsPerInch and Screen.PixelsPerInch
MyMemo.Height:=1+MyMemo.Lines.Count*Abs(MyMemo.Font.Height*MyMemo.Font.PixelsPerInch div 72);

希望这可以帮助任何人。

于 2012-11-12T10:41:07.613 回答
4

您可以为 TMemo 编写自己的 TCanvas.TextHeight 实现:

function CountMemoLineHeights(Memo: TMemo): Integer;
var
  DC: HDC;
  SaveFont: HFont;
  Size: TSize;
  I: Integer;

begin
  DC:= GetDC(Memo.Handle);
  SaveFont:= SelectObject(DC, Memo.Font.Handle);
  Size.cX := 0;
  Size.cY := 0;
//  I have not noticed difference in actual line heights for TMemo,
//    so the next line should work OK
  Windows.GetTextExtentPoint32(DC, 'W', 1, Size);
//  BTW next (commented) line returns Size.cY = 0 for empty line (Memo.Lines[I] = '') 
//    Windows.GetTextExtentPoint32(DC, Memo.Lines[I], Length(Memo.Lines[I]), Size);
  Result:= Memo.Lines.Count * Size.cY;
  SelectObject(DC, SaveFont);
  ReleaseDC(Memo.Handle, DC);
end;
于 2011-07-24T05:41:30.153 回答
3

您需要为此使用 TCanvas。您可以在后台创建一个 TBitMap 并使用它的 TCanvas(在将 Memo 的 Font 属性分配给 Bitmap.Canvas 之后),或者使用来自另一个组件的 TCanvas。像这样的东西:

BMP:=TBitMap.Create;
TRY
  BMP.Canvas.Font.Assign(Memo.Font);
  TotalHeight:=0;
  FOR LineNo:=1 TO Memo.Lines.Count DO INC(TotalHeight,BMP.Canvas.TextHeight(Memo.Lines[PRED(I)]))
FINALLY
  FreeAndNIL(BMP)
END;

编辑:

或者也许这个:

BMP:=TBitMap.Create;
TRY
  BMP.Canvas.Font.Assign(Memo.Font);
  LineHeight:=BMP.Canvas.TextHeight('Wq');
  TotalHeight:=Memo.Lines.Count*LineHeight
FINALLY
  FreeAndNIL(BMP)
END;
于 2011-07-24T05:08:59.340 回答
0

我最初建议查看 TMemo 中的“Lines”TStrings 列表成员。

相反,请查看父类 TCustomEdit 中的“Font”成员。

'希望有帮助.. PS

于 2011-07-24T04:30:26.227 回答