Página principal
Artículos y trucos
Catálogo de productos
Ejemplos y descargas
Mis libros
Cursos de formación
Investigación y desarrollo
Libros recomendados
Mis páginas favoritas
Acerca del autor
 
En colaboración con Amazon
 
Intuitive Sight

Escribir en la barra de título

Hace poco me han preguntado cómo se puede dibujar en la barra de título (caption bar) de una ventana. Personalmente, estas son técnicas que no recomiendo. Sí, demuestran habilidad en el manejo del API de Windows, pero una barra de título es una barra de título, y si uno se pone a maquillarla mucho, puede que no la reconozca ni su madre.

De todos modos, la técnica es sencilla. Hay que interceptar un par de mensajes de Windows: WM_NCPAINT y WM_NCACTIVATE. Las iniciales NC en estos mensajes corresponden a Non-Client, es decir, el área que precisamente no está dedicada al dibujo... Ambos mensajes son similares a WM_PAINT y a WM_NCACTIVATE, con la diferencia de que WM_NCACTIVATE no va seguido de un mensaje de dibujo. Por lo tanto, también hay que dibujar en respuesta al mensaje de activación.

Para mayor claridad, voy a definir un método auxiliar, en el formulario que queremos "desfigurar", que será llamado posteriormente desde los dos manejadores de mensajes:

procedure TForm1.Titulo(wParam: Integer);
var
  DC: THandle;
  R1, R2: TRect;
begin
  DC := GetWindowDC(Handle);
  try
    SetWindowText(Handle, nil);
    GetWindowRect(Handle, R2);
    R1.Left := GetSystemMetrics(SM_CXSIZE)
      + GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXFRAME);
    R1.Top := GetSystemMetrics(SM_CYFRAME);
    R1.Right := R2.Right - R2.Left - R1.Left
      - 2 * GetSystemMetrics(SM_CXSIZE);
    R1.Bottom := R1.Top + GetSystemMetrics(SM_CYSIZE);
    if wParam = 1 then
      SetBkColor(DC, GetSysColor(COLOR_ACTIVECAPTION))
    else
      SetBkColor(DC, GetSysColor(COLOR_INACTIVECAPTION));
    SetTextColor(DC, GetSysColor(COLOR_CAPTIONTEXT));
    DrawText(DC, 'A la izquierda', -1, R1, DT_LEFT or DT_VCENTER);
    DrawText(DC, 'A la derecha', -1, R1, DT_RIGHT or DT_VCENTER);
  finally
    ReleaseDC(Handle, DC);
  end;
end;

El método Titulo se llamará con un parámetro de tipo entero. Cuando sea igual a 1, nos indicará que tenemos que dibujar sobre una barra de título activa; en caso contrario, la barra estará inactiva. Observe, como punto interesante, que llamamos al procedimiento SetWindowText. Esto se hace para evitar que se muestre el texto del título en la ventana. Usted se preguntará, ¿por qué no asignar sencillamente la cadena vacía en la propiedad Caption del formulario? Bueno, puede comprobar que aunque hagamos eso mismo, Delphi se encargará de utilizar el nombre del formulario en el título. Sospecho que se puede eliminar el título también en algún sitio más conveniente, por ejemplo, redefiniendo CreateWindow, pero son la una de la madrugada, hora local, y no tengo ganas de probarlo.

¿Dónde está el código que debe dibujar los botones de la barra, el borde de la ventana y el resto de la parafernalia? ¡Ah!, voy a dejar que Windows los dibuje por mí. Esta es la implementación de los manejadores de mensajes antes mencionados.

type
  TForm1 = class(TForm)
    // ...
  private
    procedure WMNCActivate(var M: TMessage); message WM_NCACTIVATE;
    procedure WMNCPaint(var M: TMessage); message WM_NCPAINT;
    // ...
  end;

procedure TForm1.WMNCActivate(var M: TMessage);
begin
  DefWindowProc(Handle, M.Msg, M.wParam, M.lParam);
  Titulo(M.wParam);
  M.Result := 1;
end;

procedure TForm1.WMNCPaint(var M: TMessage);
begin
  DefWindowProc(Handle, M.Msg, M.wParam, M.lParam);
  Titulo(1);
end;

Eso es todo. Sin embargo, le debo una advertencia: este algoritmo ha sido probado con Windows 95. Si utiliza Windows 98, posiblemente tenga que variar la llamada a SetBkColor. Lo más probable es que necesite jugar un poco con SetBkMode, para que los mensajes que se dibujen lo hagan transparentemente, sobre el gradiente de fondo de la nueva interfaz. También es conveniente que advierta que se ha asumido una ventana con un icono a la izquierda y tres a la derecha. Si oculta alguno de los mismos, deberá recalcular el tamaño del rectángulo.