La mejor manera de decirle programación si Leyenda de un TLabel se recorta (es decir dibujado usando puntos suspensivos)?

StackOverflow https://stackoverflow.com/questions/4313607

Pregunta

Tengo un TLabel con juego EllipsisPosition a epEndEllipsis y tengo que ser capaz de decir si el texto se recorta o no actualmente. Además de calcular el área requerida para visualizar el texto mismo y su comparación con las dimensiones reales de la etiqueta, nadie ha llegado con una forma más fácil / más elegante de hacer esto?

En realidad, el cálculo de la superficie necesaria de una manera a prueba de fallos también no parece ser tan sencillo como suena ... Por ejemplo TCanvas.GetTextHeight no toma en cuenta los saltos de línea.

TCustomLabel.DoDrawText utiliza internamente o bien DrawTextW o DrawThemeTextExwith la bandera DT_CALCRECT para determinar si se debe utilizar la elipsis o no. Hay una gran cantidad de código que participan allí, todos los cuales se declara private. Simplemente duplicar todo ese código no calificaría exactamente como "elegante" en mi libro ...

¿Alguna idea?

(estoy usando Delphi 2010, en caso de que alguien se le ocurre una solución de Delphi-versión específica)

Actualización 1: ahora descubrió que sólo puedo llamar TCustomLabel.DoDrawText(lRect, DT_CALCRECT) directamente (que se limitó a declarar protected) para permitir que la etiqueta realice el cálculo del tamaño requerido sin tener que duplicar su código. Sólo tengo que asegurarse de que sea temporal conjunto EllipsisPosition a epNone o utilizar una instancia de etiqueta temporal por completo. Esto no es realmente tan malo y que sólo podría ir con él si nadie puede pensar en una solución aún más simple.

Actualización 2: Ahora he añadido mi solución como una respuesta por separado. Que resultó ser bastante más recta de avance de lo que esperaba por lo que probablemente hay mejor manera más fácil / para hacerlo, pero voy a dejar esta pregunta abierta por un tiempo más largo de todos modos por si acaso.

¿Fue útil?

Solución

Fwiw, esto es lo que se me ocurrió (este es un método de un TLabel-descendiente personalizado):

function TMyLabel.IsTextClipped: Boolean;
const
  EllipsisStr = '...';
var
  lEllipBup: TEllipsisPosition;
  lRect: TRect;
begin
  lRect := ClientRect;
  Dec(lRect.Right, Canvas.TextWidth(EllipsisStr));

  lEllipBup := EllipsisPosition;
  EllipsisPosition := epNone;
  try
    DoDrawText(lRect, DT_CALCRECT or IfThen(WordWrap, DT_WORDBREAK));
  finally
    EllipsisPosition := lEllipBup;
  end;
  Result := ((lRect.Right - lRect.Left) > ClientWidth)
         or ((lRect.Bottom - lRect.Top) > ClientHeight);
end;

Como esta ahora utiliza exactamente la misma lógica que TCustomLabel.DoDrawText (especialmente el relleno artificial y el ajuste correcto WordWrap) también se ocupa correctamente con varias líneas y textos de entrada de palabras envueltas. Tenga en cuenta que "correctamente" en este caso significa "siempre devuelve True cuando el TLabel se dibuja con un pie de foto recortada y False lo contrario".

Mientras que el código anterior hace lo que le pedía originalmente para probablemente no vuelva a usarlo de esta manera - pero esto es más debido a las deficiencias de TLabel sí: Especialmente con texto de varias líneas que a menudo no se comporta de la manera que yo hubiera querido a, por ejemplo, cuando no hay suficiente espacio para múltiples líneas, siempre se truncará la última palabra de la primera línea, incluso si toda esa línea, más los puntos suspensivos se han instalado.

Otros consejos

Como punto de partida, se puede usar

function DrawStringEllipsis(const DC: HDC; const ARect: TRect; const AStr: string): boolean;
var
  r: TRect;
  s: PChar;
begin
  r := ARect;
  GetMem(s, length(AStr)*sizeof(char) + 8);
  StrCopy(s, PChar(AStr));
  DrawText(DC, PChar(s), length(AStr), r, DT_LEFT or DT_END_ELLIPSIS or DT_MODIFYSTRING);
  result := not SameStr(AStr, s);
  FreeMem(s);
end;

Ejemplo de uso:

procedure TForm1.FormClick(Sender: TObject);
begin
  Caption := 'Clipped ' + BoolToStr(DrawStringEllipsis(Canvas.Handle, Rect(10, 100, 50, 50), 'This is a text.'), true);
end;

No sería difícil escribir un componente TExtLabel que tiene una propiedad WasClipped usando esta técnica. De hecho, el componente TLabel es uno de los componentes más simples del VCL -. Simplemente dibuja una cadena

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top