我有一个 TMemo,我希望它总是足够高以显示它包含的行数。不幸的是,我不太清楚如何计算。我不能基于.Font.Size
属性,因为这会因 DPI 而异。而且我不能使用TCanvas.TextHeight
,因为 TMemo 似乎没有画布。
有人知道如何正确执行此操作吗?
我看到一个问题,我认为 TMemo 上的所有行的高度都相等,但有些可能是空的......
因此,当它们在 TMemo 上的高度不是零时,获取空的高度将给出零。
所以解决方案可能会做类似 Memo.Lines.Count*LineHeight
请注意,Canvas.TextHeight 可能无法获取 Lineheight,因为 Canvas.TextHeight 会或多或少地为文本提供最小高度的准确高度......我的意思是它不会为文本“ABC”提供与“ABCp”相同的高度, ETC...
我建议(如果不想调用 Windows API)使用 Font.Height,但如果它是负数,则不测量每行的内部前导......
所以我建议做接下来的步骤(经过测试):
我个人在 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);
希望这可以帮助任何人。
您可以为 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;
您需要为此使用 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;
我最初建议查看 TMemo 中的“Lines”TStrings 列表成员。
相反,请查看父类 TCustomEdit 中的“Font”成员。
'希望有帮助.. PS