如何以编程方式确定 TMemo 中文本行的高度?

发布于 2024-11-25 17:42:16 字数 193 浏览 0 评论 0原文

我有一个 TMemo,并且我希望始终将其设置得足够高以显示它包含的行数。不幸的是,我不太知道如何计算。我无法将其基于 .Font.Size 属性,因为这会根据 DPI 的不同而有所不同。而且我无法使用 TCanvas.TextHeight 因为 TMemo 似乎没有画布。

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

I've got a TMemo, and I want to always make it exactly high enough to display the number of lines it contains. Unfortunately, I don't quite know how to calculate that. I can't base it off the .Font.Size property, because that will vary based on DPI. And I can't use TCanvas.TextHeight because TMemo doesn't seem to have a canvas.

Anyone know how to do this right?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

葬花如无物 2024-12-02 17:42:16

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

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

因此,解决方案可能会执行类似 Memo.Lines.Count*LineHeight 的操作

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

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

所以我建议执行接下来的步骤(已测试):

  • 在 OnCreate 事件或任何您想要的地方为 Memo.Font.Height 指定一个正值,这样 TMemo 的行高将是您指定的
  • Total 值现在可以通过 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);

希望这可以帮助任何人。

I see a problem, i think all lines on a TMemo are equal on height, but some can be empty...

So getting Height of empty ones will give zero while they are not zero height on the TMemo.

So the solution maybe doing something like Memo.Lines.Count*LineHeight

Beware that the Lineheight may not be getted by Canvas.TextHeight since Canvas.TextHeight will give more or less exact height of minimal height for a text... i mean it will not give same height for text 'ABC' than for 'ABCp', etc...

I would recomend (if not want to call Windows API) to use Font.Height, but if it is negative the internal leading of each line is not measured...

So i would recomend to do the next steps (tested):

  • Asign a positive value for Memo.Font.Height on the OnCreate event or anywhere you want, with this the lineheight ot the TMemo will be such value you asigned
  • Total height now can be obtained directly by Memo.Lines.Count*LineHeight, since you have asigned a positive value to Memo.Font.Height (remember that would make Memo.Font.Size to be negative)

Personally i do this on the TForm OnCreate event (to ensure it is done only once), just to ensure visual font size is not changed and MyMemo.Font.Height includes internal leading of each line:

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

Ensure the previous to be done only once, otherwise the text size will be visaully bigger and bigger, as much as times you run it... it is caused because not allways MyMemo.Font.PixelsPerInch is equal to Screen.PixelsPerInch... in my case they are 80 and 96 respectively.

Then, when i need to know line height i just use:

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

That gives exact height of one TMemo line, since all lines have the same height, the total height would be:

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

So, to make TMemo height as big as its contained text i do this (read the comment of each line, they are very important):

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

I you do not want to play with Screen.PixelsPerInch you can just do this (read the comment of each line, they are very important):

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);

Hope this can help anyone.

两仪 2024-12-02 17:42:16

为此,您需要使用 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;

You need to use a TCanvas for this. You can either create a TBitMap in the background and use its TCanvas (after assigning the Memo's Font property to the Bitmap.Canvas' one), or use a TCanvas from another component. Somthing like this:

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;

Edit:

Or perhaps this one:

BMP:=TBitMap.Create;
TRY
  BMP.Canvas.Font.Assign(Memo.Font);
  LineHeight:=BMP.Canvas.TextHeight('Wq');
  TotalHeight:=Memo.Lines.Count*LineHeight
FINALLY
  FreeAndNIL(BMP)
END;
仅冇旳回忆 2024-12-02 17:42:16

您可以为 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;

You can write your own implementation of TCanvas.TextHeight for TMemo:

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;
美人骨 2024-12-02 17:42:16

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

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

'希望有帮助..PS

I originally suggested looing at the "Lines" TStrings list member in TMemo.

Instead, please look at the "Font" member in the parent class, TCustomEdit.

'Hope that helps .. PS

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文