¿Cómo mostrar texto rotado?

Texto inclinado

Copyright © 2000 Ernesto De Spirito

SMImport - Componentes VCL nativos para importar datos

Seguramente habrá visto que algunas etiquetas y otros componentes le permiten rotar el texto. Por ejemplo la Librería JfControls le permite rotar los títulos (captions) de etiquetas, botones, casillas de verificación, botones de radio, elementos de lista, elementos de menú, etc. Puede lograr el mismo efecto usando los campos lfEscapement y lfOrientation de la estructura del objeto font (fuente), que guardan el ángulo del texto medido en décimas de grado (por ejemplo un valor de 150 significa 15 grados).

La siguiente función devuelve el manejador de una fuente con las mismas características de la fuente cuyo manejador se pasa como parámetro, pero permite establecer su ángulo y calidad.

interface

uses Windows;

function CreateAngledFont(Fuente: HFont; Angulo: Longint;
  Calidad: byte = PROOF_QUALITY): HFont;

implementation

function CreateAngledFont(Fuente: HFont; Angulo: Longint;
  Calidad: byte): HFont;
var
  FontInfo: TLogFontA;    // Estructura de información de la fuente
begin
  // Obtener la información de la fuente pasada como parámetro
  if GetObject(Fuente, SizeOf(FontInfo), @FontInfo) = 0 then begin
    Result := 0;
    exit;
  end;
  // Establecer el ángulo
  FontInfo.lfEscapement := Angulo;
  FontInfo.lfOrientation := Angulo;
  // Establecer la calidad
  FontInfo.lfQuality := Calidad;
  // Crear una nueva fuente con la información modificada
  // La nueva fuente deberá ser liberada llamando a DeleteObject
  Result := CreateFontIndirect(FontInfo);
end;

Podemos usar esta función en un procedimiento que muestre texto rotado en cualquier lienzo (canvas), incluyendo por ejemplo el de una impresora:

uses Graphics, Windows;

procedure TextOutA(Lienzo: TCanvas; X, Y, Angulo: Integer;
  Texto: string);
var
  FuenteOriginal, FuenteInclinada: HFont;
begin
  // Crea una fuente inclinada a partir de la fuente actual
  FuenteInclinada := CreateAngledFont(Lienzo.Font.Handle, Angulo);
  if FuenteInclinada <> 0 then begin
    // La establemos temporalmente como la fuente actual
    FuenteOriginal := SelectObject(Lienzo.Handle, FuenteInclinada);
    if FuenteOriginal <> 0 then begin
      // Escribimos el texto
      Lienzo.TextOut(X, Y, Texto);
      // Restaura la fuente original
      if SelectObject(Lienzo.Handle, FuenteOriginal) = 0 then begin
        Lienzo.Font.Handle := FuenteInclinada;
        // raise Exception.Create('No se pudo restaurar la fuente');
        exit;
      end;
    end;
    // Libera la fuente inclinada
    DeleteObject(FuenteInclinada)
  end;
end;

He aquí un ejemplo de uso:

procedure TForm1.FormPaint(Sender: TObject);
begin
  Font.Name := 'Arial'; // IMPORTANTE: fuente True Type
  Font.Size := 14;
  Canvas.Brush.Color := Color;
  TextOutA(Canvas, 10, 40, 150, '¡Hola mundo!');
end;

Si queremos podemos asignar el manejador de una fuente inclinada a la propiedad Handle de un objeto TFont. El manejador será eliminado automáticamente cuando dicho objeto sea destruido.

El siguiente ejemplo usa esta técnica para dibujar los elementos de un cuadro de lista:

procedure TForm1.FormCreate(Sender: TObject);
begin
  // Establece la fuente del cuadro de lista para que tenga una
  // inclinación de 10 grados
  with ListBox1.Font do Handle := CreateAngledFont(Handle, 100);
end;

procedure TForm1.ListBox1DrawItem(Control: TWinControl;
  Index: Integer; Rect: TRect; State: TOwnerDrawState);
const
  TopOffset = 16;
begin
  with (Control as TListBox).Canvas do begin
    FillRect(Rect);
    TextOut(Rect.Left + 2, Rect.Top + TopOffset,
      TListBox(Control).Items[Index]);
  end;
end;
JfControls Library - para Delphi y C++ Builder