delphi - ¿Cómo puedo determinar la altura de una línea de texto en un TMemo mediante programación?
(4)
Tengo un TMemo, y quiero hacerlo siempre lo suficientemente alto como para mostrar el número de líneas que contiene. Lamentablemente, no sé cómo calcular eso. No puedo basarlo en la propiedad .Font.Size
, porque eso variará según DPI. Y no puedo usar TCanvas.TextHeight
porque TMemo no parece tener un lienzo.
Alguien sabe cómo hacer esto ¿verdad?
Necesitas usar un TCanvas para esto. Puede crear un TBitMap en segundo plano y usar sus TCanvas (después de asignar la propiedad de Fuente del Memo al de Bitmap.Canvas), o usar un TCanvas de otro componente. Algo así:
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;
Editar:
O tal vez este:
BMP:=TBitMap.Create;
TRY
BMP.Canvas.Font.Assign(Memo.Font);
LineHeight:=BMP.Canvas.TextHeight(''Wq'');
TotalHeight:=Memo.Lines.Count*LineHeight
FINALLY
FreeAndNIL(BMP)
END;
Originalmente, sugerí visitar el miembro de la lista TStrings de "Líneas" en TMemo.
En su lugar, mire el miembro "Fuente" en la clase principal, TCustomEdit.
''Espero que ayude .. PD
Puede escribir su propia implementación de TCanvas.TextHeight para 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;
Veo un problema, creo que todas las líneas en un TMemo son iguales en altura, pero algunas pueden estar vacías ...
Por lo tanto, al obtener la Altura de los vacíos dará cero, mientras que no tienen una altura cero en el TMemo.
Entonces la solución tal vez haga algo como Memo.Lines.Count * LineHeight
Tenga en cuenta que Lineheight no puede obtener Lineheight ya que Canvas.TextHeight dará una altura más o menos exacta de la altura mínima para un texto ... quiero decir que no dará la misma altura para el texto ''ABC'' que para ''ABCp'' , etc ...
Yo recomendaría (si no quiero llamar a la API de Windows) que use Font.Height, pero si es negativo, no se mide el límite interno de cada línea ...
Entonces recomiendo hacer los siguientes pasos (probado):
- Asignar un valor positivo para Memo.Font.Height en el evento OnCreate o en cualquier lugar que desee, con esto la altura del TMemo será tal valor que haya asignado
- La altura total ahora puede obtenerse directamente en Memo.Lines.Count * LineHeight, ya que ha asignado un valor positivo a Memo.Font.Height (recuerde que Memo.Font.Size sería negativo)
Personalmente hago esto en el evento TForm OnCreate (para asegurarme de que se realice solo una vez), solo para garantizar que el tamaño de fuente visual no se modifique y MyMemo.Font.Height incluye el avance interno de cada línea:
MyMemo.Font.Height:=Abs(MyMemo.Font.Size*MyMemo.Font.PixelsPerInch div Screen.PixelsPerInch);
Asegúrate de hacer lo anterior solo una vez, de lo contrario el tamaño del texto será mayor y más grande, tanto como lo ejecutes ... es causado porque no siempre MyMemo.Font.PixelsPerInch es igual a Screen.PixelsPerInch ... en mi caso son 80 y 96 respectivamente.
Entonces, cuando necesito saber la altura de la línea, simplemente uso:
Abs(MyMemo.Font.Height*Screen.PixelsPerInch div 72)
Eso da la altura exacta de una línea TMemo, ya que todas las líneas tienen la misma altura, la altura total sería:
MyMemo.Lines.Count*Abs(MyMemo.Font.Height*Screen.PixelsPerInch div 72)
Entonces, para hacer que la altura de TMemo sea tan grande como su texto contenido, hago esto (lea el comentario de cada línea, son muy importantes):
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
Si no quieres jugar con Screen.PixelsPerInch puedes hacer esto (lee el comentario de cada línea, son muy importantes):
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);
Espero que esto pueda ayudar a cualquiera.