Un lugar de encuentro para los programadores de habla hispana

Un lugar de encuentro para los programadores de habla hispana

Buscar

Entrar

Puedes acceder utilizando tu cuenta de usuario del foro.

Si no dispone de cuenta, puede crear una accediendo al formulario de registro del foro.



Imagen de fondo en un formulario MDI Imprimir
Ideas - Delphi

Para colocar una imagen en el área cliente de un formulario MDI (esto es, un formulario que tenga la propiedad 'FormStyle = fsMDIForm') se utiliza una técnica especial que se suele denominar "subclasificación de ventana".

Las ventanas MDI tienen incorporada o incrustada una ventana que, en tiempo de ejecución, ocupa todo el área cliente. Esta ventana es la encargada de manejar a los formularios MDI hijos ('FormStyle = fsMDIChild'). También es esta ventana la causante de que, cualquier cosa que pongamos en tiempo de diseño en el área cliente del formulario MDI (por ejemplo, un 'TPaintBox' donde podríamos dibujar una imagen), quede oculta en tiempo de ejecución. La ventana a la que me refiero sólo es accesible en tiempo de ejecución, razón de más para que haya que utilizar con ella la subclasificación.

Para llevar a efecto la subclasificación de ventana necesitamos declarar una variable que almacene el procedimiento original de la ventana que vamos a subclasificar. El mejor método es declarar esa variable como campo privado del formulario MDI. Como en el ejemplo que sigue vamos a dibujar en el área cliente un gráfico, también declaramos como campo privado una variable que nos permita almacenar el mapa de bits a dibujar.

La declaración del formulario quedaría de la siguiente manera:

 
type 
  TForm1 = class(TForm) 
    procedure FormCreate(Sender: TObject); 
    procedure FormShow(Sender: TObject); 
    procedure FormDestroy(Sender: TObject); 
  private 
    { Private declarations } 
    fBMP: Graphics.TBitmap; 
    fClienteWndAntes: Windows.TFarProc; 
    procedure ClienteWindowProc(var Message: Messages.TMessage); 
  public 
    { Public declarations } 
  end;
 
var 
  Form1: TForm1;
 
implementation
 
{$R *.DFM}
 
//############################################################################- 
// EVENTO : FormCreate 
// 
// ACCIÓN : Crea e inicializa los objetos que utiliza el formulario. 
//############################################################################- 
procedure TForm1.FormCreate(Sender: TObject); 
begin 
   fBMP := Graphics.TBitmap.Create; 
   fBMP.LoadFromFile('c:\dibujo1.bmp'); 
end;
 
//############################################################################- 
// EVENTO : FormShow 
// 
// ACCIÓN : Sobrescritura del procedimiento de ventana original. 
//----------------------------------------------------------------------------- 
procedure TForm1.FormShow(Sender: TObject); 
var 
   Proc_Cliente: Windows.TFarProc; 
   lValor: LongInt; 
begin 
   // Obtener la dirección de nuestro procedimiento de ventana 
   Proc_Cliente := Forms.MakeObjectInstance(ClienteWindowProc); 
   if (nil <> Proc_Cliente) then 
   begin 
      // Obtener el procedimiento de ventana original del área cliente 
      lValor := Windows.GetWindowLong(Self.ClientHandle, GWL_WNDPROC); 
      if (0 < lValor) then 
      begin 
         // Sobrescribir el procedimiento de ventana original con el nuestro 
         if (0 < Windows.SetWindowLong(Self.ClientHandle, 
                                       GWL_WNDPROC, 
                                       LongInt(Proc_Cliente))) 
         then 
         begin 
            // Guardar el procedimiento de ventana 
            fClienteWndAntes := Windows.TFarProc(lValor); 
         end; 
      end; 
   end; 
end;
 
//############################################################################- 
// EVENTO : FormDestroy 
// 
// ACCIÓN : Destrucción de los objetos. 
//############################################################################- 
procedure TForm1.FormDestroy(Sender: TObject); 
begin 
   if (nil <> fBMP) then 
   begin 
      fBMP.Free; 
      fBMP := nil; 
   end; 
end;
 
//############################################################################- 
// RUTINA : ClienteWindowProc(Messages::TMessage &amp;Message) 
// 
// ACCIÓN : Sub-clasifica el procedimiento de mensajes del área cliente con 
//          el objeto de pintar en el mismo (mensaje 'WM_ERASEBKGND'). 
//############################################################################- 
procedure TForm1.ClienteWindowProc(var Message: Messages.TMessage); 
var 
   Rect: Windows.TRect; 
begin 
   // Llamar al procedimiento original de la ventana cliente o no se 
   // se enterará de nada de lo que hagamos con las ventanas hijas. 
   Message.Result := Windows.CallWindowProc(fClienteWndAntes, 
                                            ClientHandle, 
                                            Message.Msg, 
                                            Message.wParam, 
                                            Message.lParam); 
   Case (Message.Msg)of 
      WM_ERASEBKGND: 
      begin 
         if (nil <> fBMP) then  // Sólo si hay algo que dibujar 
         begin 
            // Obtener las dimensiones del área cliente 
            Windows.GetClientRect(ClientHandle, Rect);
 
            // Redimensionar el área de dibujo. 
            // Vamos a pintar el gráfico centrado 
            Rect.Left := System.Round((Rect.Right - Rect.Left - fBMP.Width) /2); 
            Rect.Top := System.Round((Rect.Bottom - Rect.Top - fBMP.Height)/ 2);
 
            // Dibujar gráfico 
            Windows.BitBlt 
            ( 
               HDC(Message.WParam),  // HDC de destino 
               Rect.Left,            // Coordenada X de destino 
               Rect.Top,             // Coordenada Y de destino 
               fBMP.Width,           // Anchura de la zona a dibujar 
               fBMP.Height,          // Altura de la zona a dibujar 
               fBMP.Canvas.Handle,   // HDC de origen 
               0,                    // Coordenada X de origen 
               0,                    // Coordenada Y de origen 
               SRCCOPY               // Modo: copia simple 
            ); 
         end; 
      end; 
      WM_NCCALCSIZE,  // Cambio de tamaño 
      WM_HSCROLL,     // Desplazamiento Horizontal 
      WM_VSCROLL:     // Desplazamiento Vertical 
      begin 
         // Obligar a repintar el área cliente 
         Windows.InvalidateRect(ClientHandle,nil, TRUE); 
      end; 
   end; 
end;
 
 

Hay algún que otro efecto indeseado cuando se pone una imagen en el fondo y el usuario tiene puestos 256 colores o menos, en vez de color verdadero. Si, en ese momento, muestras un formulario que tenga algún gráfico que no coincida con la paleta del gráfico del área cliente, se degrada el fondo quedando echo un churro. Ahora no hay mensaje de Windows que avise de semejante degradación y, aunque lo consiguieses (por ejemplo, con un Timer que pinte cada X segundos el fondo), se degradaría el otro gráfico, el del formulario que digo.

Comentarios (0)
Para escribir un comentario debes estar registrado