Как программно определить высоту строки текста в TMemo? - PullRequest
1 голос
/ 24 июля 2011

У меня есть TMemo, и я хочу всегда делать его достаточно точным, чтобы отображать количество строк в нем.К сожалению, я не совсем знаю, как рассчитать это.Я не могу основать его на свойстве .Font.Size, потому что оно будет зависеть от DPI.И я не могу использовать TCanvas.TextHeight, потому что у TMemo, похоже, нет холста.

Кто-нибудь знает, как это сделать правильно?

Ответы [ 4 ]

7 голосов
/ 12 ноября 2012

Я вижу проблему, я думаю, что все строки в TMemo равны по высоте, но некоторые могут быть пустыми ...

Таким образом, получение высоты пустых даст ноль, в то время как они не равны нулевой высоте наTMemo.

Так что решение, возможно, делает что-то вроде Memo.Lines.Count * LineHeight

Остерегайтесь того, что Lineheight не может быть получен Canvas.TextHeight, поскольку Canvas.TextHeight даст более или менееточная высота минимальной высоты для текста ... я имею в виду, что он не даст такую ​​же высоту для текста 'ABC', как для 'ABCp' и т. д. *

Я бы рекомендовал (если не хотите вызывать WindowsAPI), чтобы использовать Font.Height, но если он отрицательный, внутреннее начало каждой строки не измеряется ...

Поэтому я бы рекомендовал сделать следующие шаги (проверено):

  • Назначьте положительное значение для Memo.Font.Height в событии OnCreate или в любом месте, где вы хотите, с этой линией высотой 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

I, вы делаетене хочу Чтобы поиграть с 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);

Надеюсь, это может кому-нибудь помочь.

4 голосов
/ 24 июля 2011

Вы можете написать свою собственную реализацию TCanvas.TextHeight для 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;
3 голосов
/ 24 июля 2011

Для этого вам нужно использовать TCanvas. Вы можете либо создать TBitMap в фоновом режиме и использовать его TCanvas (после назначения свойства Font Memo для объекта 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;

Edit:

Или, может быть, это:

BMP:=TBitMap.Create;
TRY
  BMP.Canvas.Font.Assign(Memo.Font);
  LineHeight:=BMP.Canvas.TextHeight('Wq');
  TotalHeight:=Memo.Lines.Count*LineHeight
FINALLY
  FreeAndNIL(BMP)
END;
0 голосов
/ 24 июля 2011

Первоначально я предлагал зацикливаться на элементе списка «Линии» TStrings в TMemo.

Вместо этого, пожалуйста, посмотрите на элемент «Шрифт» в родительском классе TCustomEdit.

'Надеюсь, чтопомогает .. PS

...