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

时间:2011-07-24 04:24:29

标签: delphi tmemo

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

任何人都知道如何做到这一点?

4 个答案:

答案 0 :(得分:7)

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

因此,当TMemo上的高度不为零时,获得空的高度将为零。

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

的操作

请注意Canvas.TextHeight可能无法获取Lineheight,因为Canvas.TextHeight会为文本提供或多或少精确的最小高度...我的意思是它不会为文本'ABC'提供相同的高度而不是'ABCp'等......

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

所以我建议你做下一步(测试):

  • 在OnCreate事件或任何您想要的任何地方为Memo.Font.Height设置一个正值,这样,TMemo的直线高度将是您签署的值
  • 现在总高度可以通过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);

希望这可以帮助任何人。

答案 1 :(得分: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;

答案 2 :(得分: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;

答案 3 :(得分:0)

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

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

'希望有所帮助.. PS