Club Builder - Foros de discusión Club Builder
Foro de C++Builder en español
 
 FAQFAQ   BuscarBuscar   MiembrosMiembros   Grupos de UsuariosGrupos de Usuarios   RegistrarseRegistrarse 
 PerfilPerfil   Entra para ver tus mensajes privadosEntra para ver tus mensajes privados   EntrarEntrar 

"Imagen de fondo en un formulario MDI. "

 
Publicar nuevo tema   Responder al tema    Foros de discusión -> Tips & Tricks
Ver tema anterior :: Ver tema siguiente  
Autor Mensaje
Mensaje    Asunto: "Imagen de fondo en un formulario MDI. " Responder citando

Este codigo, se encuentra en la red, el autor (Mario Rodríguez)
lo ha puesto para establecer un fondo en una ventana MDI

Código:

Imagen de fondo en un formulario MDI.
(Autor : Mario Rodríguez)

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:

class TForm1 : public TForm
{
__published: // IDE-managed Components
    void __fastcall FormCreate(TObject *Sender);
    void __fastcall FormShow(TObject *Sender);
    void __fastcall FormDestroy(TObject *Sender);

public:  // User declarations
    __fastcall TForm1(TComponent* Owner);

private:
    // Campo para almacenar el gráfico a dibujar
    Graphics::TBitmap* fBMP;
    // Campo para almacenar el procedimiento de ventana original
    Windows::TFarProc fClienteWndAntes;
    // Nuestro procedimiento de ventana para el área cliente
    void __fastcall ClienteWindowProc(Messages::TMessage &Message);
};
 

Ahora definimos los métodos del formulario:

//-----------------------------------------------------------------------------
// EVENTO : FormCreate
//
// ACCIÓN : Crea e inicializa los objetos que utiliza el formulario.
//-----------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
 fBMP = new Graphics::TBitmap();
 fBMP->LoadFromFile("c:\\dibujo1.bmp");
}

//-----------------------------------------------------------------------------
// EVENTO : FormShow
//
// ACCIÓN : Sobrescritura del procedimiento de ventana original.
//-----------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
    // Obtener la dirección de nuestro procedimiento de ventana
    Windows::TFarProc Proc_Cliente = Forms::MakeObjectInstance(ClienteWindowProc);
    if (Proc_Cliente)
    {   // Obtener el procedimiento de ventana original del área cliente
        LONG lValor = ::GetWindowLong(this->ClientHandle, GWL_WNDPROC);
        if (0 < lValor)
        {   // Sobrescribir el procedimiento de ventana original con el nuestro
            if (0 < ::SetWindowLong(this->ClientHandle,
                                    GWL_WNDPROC,
                                    reinterpret_cast< long >(Proc_Cliente)))
            {   // Guardar el procedimiento de ventana
                fClienteWndAntes = reinterpret_cast< Windows::TFarProc >(lValor);
            }
        }
    }
}

//-----------------------------------------------------------------------------
// EVENTO : FormDestroy
//
// ACCIÓN : Destrucción de los objetos.
//-----------------------------------------------------------------------------
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
 delete fBMP; fBMP = 0;
}

//-----------------------------------------------------------------------------
// RUTINA : ClienteWindowProc(Messages::TMessage &Message)
//
// ACCIÓN : Sub-clasifica el procedimiento de mensajes del área cliente con
//          el objeto de pintar en el mismo (mensaje 'WM_ERASEBKGND').
//-----------------------------------------------------------------------------
void __fastcall TForm1::ClienteWindowProc(Messages::TMessage &Message)
{
    // 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 = ::CallWindowProc
    (
       reinterpret_cast< int (__stdcall *)() >(fClienteWndAntes),
        ClientHandle,
        Message.Msg,
        Message.WParam,
        Message.LParam
    );
    switch (Message.Msg)
    {
        case WM_ERASEBKGND:
        {
           if (fBMP)// Sólo si hay algo que dibujar
           {
               // Obtener las dimensiones del área cliente
                RECT Rect;
               ::GetClientRect(ClientHandle,&Rect);

                // Redimensionar el área de dibujo.
                // Vamos a pintar el gráfico centrado
                Rect.left = (Rect.right - Rect.left - fBMP->Width)/ 2;
                Rect.top = (Rect.bottom - Rect.top - fBMP->Height)/ 2;

               // Dibujar gráfico
               ::BitBlt
               (
                   reinterpret_cast< 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
               );
           }
           break;
        }
        case WM_NCCALCSIZE: // Cambio de tamaño
        case WM_HSCROLL:    // Desplazamiento Horizontal
        case WM_VSCROLL:    // Desplazamiento Vertical
        {
           ::InvalidateRect(ClientHandle, NULL, TRUE);
           break;
        }
    }
}
 

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.



Creo que es importante para los que requieran un fondo en una ventana MDI, lo pongo tal y cual, ya que el autor se merece el esfuerzo dedicado...

gracias. Mario Rodríguez, donde quiera que te encuentres..

pd: Bajado de Internet, aun cuando la direccion. no la sepa.. me lo han pasado y lo comparto con el foro...
_________________
Cool
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email MSN Messenger
Mensaje    Asunto: Responder citando

Hola cesar, he probado este codigo y me produce un error (Win Xp y Builder 6) en:

Cita:

void __fastcall TForm1::FormShow(TObject *Sender)
{
...
Windows::TFarProc Proc_Cliente = Forms::MakeObjectInstance(ClienteWindowProc);
...
}


[C++ Error] main.cpp(30): E2316 'MakeObjectInstance' is not a member of 'Forms'.

???? alguna idea.
Volver arriba
Ver perfil de usuario Enviar mensaje privado Enviar email
Mostrar mensajes de anteriores:   
Cambiar a:  
No puedes publicar temas nuevos en este foro
No puedes responder a temas en este foro
No puedes editar tus mensajes en este foro
No puedes borrar tus mensajes en este foro
No puedes votar en las encuestas de este foro


Hosting WordPress Indedmedia desde 3,99 €
© 2002–2026 Club Builder · Funciona con phpBB.