Arrastre un formulario Delphi sin la barra de subtítulos

La forma más común de mover una ventana es arrastrarla por su barra de título. Siga leyendo para descubrir cómo puede proporcionar capacidades de arrastre para formularios Delphi sin una barra de título, para que el usuario pueda mover un formulario haciendo clic en cualquier parte del área del cliente.

Por ejemplo, considere el caso de una aplicación de Windows que no tiene una barra de título, ¿cómo podemos mover esa ventana? De hecho, es posible crear ventanas con una barra de título no estándar e incluso formas no rectangulares. En este caso, ¿cómo podría saber Windows dónde están los bordes y las esquinas de la ventana??

El mensaje de Windows WM_NCHitTest

El sistema operativo Windows se basa en gran medida en el manejo de mensajes. Por ejemplo, cuando hace clic en una ventana o un control, Windows le envía un mensaje wm_LButtonDown, con información adicional sobre dónde está el cursor del mouse y qué teclas de control están presionadas actualmente. ¿Suena familiar? Sí, esto no es más que un evento OnMouseDown en Delphi.

Del mismo modo, Windows envía un mensaje wm_NCHitTest cada vez que se produce un evento del mouse, es decir, cuando se mueve el cursor o cuando se presiona o suelta un botón del mouse.

Código de entrada

Si podemos hacer que Windows piense que el usuario está arrastrando (ha hecho clic) la barra de título en lugar del área del cliente, entonces el usuario podría arrastrar la ventana haciendo clic en el área del cliente. La forma más fácil de hacer esto es "engañar" a Windows para que piense que realmente está haciendo clic en la barra de título de un formulario. Esto es lo que tienes que hacer:

1. Inserte la siguiente línea en la sección "Declaraciones privadas" de su formulario (declaración del procedimiento de manejo de mensajes):

 procedimiento WMNCHitTest (var Msg: TWMNCHitTest); mensaje WM_NCHitTest; 

2. Agregue el siguiente código en la sección "implementación" de la unidad de su formulario (donde Form1 es el nombre del formulario asumido):

 procedimiento TForm1.WMNCHitTest (var Msg: TWMNCHitTest);

empezar

    heredado;

  
Si Msg.Result = htClient luego Msg.Result: = htCaption;

final; 

La primera línea de código en el controlador de mensajes llama al método heredado para obtener el manejo predeterminado para el mensaje wm_NCHitTest. La parte If del procedimiento intercepta y cambia el comportamiento de su ventana. Esto es lo que realmente sucede: cuando el sistema operativo envía un mensaje wm_NCHitTest a la ventana, junto con las coordenadas del mouse, la ventana devuelve un código que indica qué parte de sí mismo ha sido golpeada. La información importante, para nuestra tarea, está en el valor del campo Msg.Result. En este punto, tenemos la oportunidad de modificar el resultado del mensaje.

Esto es lo que hacemos: si el usuario ha hecho clic en el área del cliente del formulario, hacemos que Windows piense que el usuario hizo clic en la barra de título. En "palabras" de Object Pascal: si el valor de retorno del mensaje es HTCLIENT, simplemente lo cambiamos a HTCAPTION.

No más eventos de mouse

Al cambiar el comportamiento predeterminado de nuestros formularios, eliminamos la capacidad de Windows de notificarle cuando el mouse se encuentra sobre el área del cliente. Un efecto secundario de este truco es que su formulario ya no generará eventos para mensajes del mouse.

Ventana sin subtítulos sin bordes

Si desea una ventana sin bordes sin título similar a una barra de herramientas flotante, establezca el Título del formulario en una cadena vacía, desactive todos los BorderIcons y establezca BorderStyle en bsNone.

Un formulario se puede cambiar de varias maneras aplicando código personalizado en el método CreateParams.

Más trucos de WM_NCHitTest

Si observa más detenidamente el mensaje wm_NCHitTest verá que el valor de retorno de la función indica la posición del punto caliente del cursor. Esto nos permite jugar un poco más con el mensaje para crear resultados extraños..

El siguiente fragmento de código evitará que los usuarios cierren sus formularios haciendo clic en el botón Cerrar.

 Si Msg.Result = htClose luego Msg.Result: = htNowhere; 

Si el usuario intenta mover el formulario haciendo clic en la barra de título y arrastrando, el código reemplaza el resultado del mensaje con un resultado que indica que el usuario hizo clic en el área del cliente. Esto evita que el usuario mueva la ventana con el mouse (opuesto a lo que estábamos haciendo al principio del artículo).

 Si Msg.Result = htCaption luego Resultado de mensaje: = htClient; 

Tener componentes en un formulario

En la mayoría de los casos, tendremos algunos componentes en un formulario. Digamos, por ejemplo, que un objeto Panel está en un formulario. Si la propiedad Alinear de un panel se establece en alClient, el Panel llena el área completa del cliente, de modo que es imposible seleccionar el formulario principal haciendo clic en él. El código anterior no funcionará, ¿por qué? Es porque el mouse siempre se mueve sobre el componente Panel, no sobre el formulario.

Para mover nuestro formulario arrastrando un panel en el formulario, debemos agregar algunas líneas de código en el procedimiento de evento OnMouseDown para el componente Panel:

 procedimiento TForm1.Panel1MouseDown

   (Remitente: TObject; Botón: TMouseButton;
   Shift: TShiftState; X, Y: entero);
empezar

    ReleaseCapture;

    SendMessage (Form1.Handle, WM_SYSCOMMAND, 61458, 0);

 final; 

Nota: Este código no funcionará con controles que no sean de ventana, como los componentes de TLabel.