PDA

Ver la Versión Completa : Como fijar una ventana?


juliopag1
06-10-2005, 15:09:43
Quiero saber como fijar una ventana, osea que no la puedan mover.

Hay alguna opcion?

Thank's

dec
06-10-2005, 15:51:30
Hola,

Supongo que por ventana quieres referirte a un formulario ("TForm"). Se me ha ocurrido una barbaridad, pero, en fin, allá va... Hemos de capturar el mensaje "WM_MOVE" en el formulario en cuestión; al crear el formulario guardaremos las propiedades "Top" y "Left" en sendas variables de tipo "integer". La declaración del formulario quedaría tal que así:


type
TfrmPrincipal = class(TForm)
procedure FormCreate(Sender: TObject);
private
FTop, FLeft: integer;
procedure WM_MOVE(var Msg: TMessage); message WM_MOVE;
end;

El evento "OnCreate" del formulario de este modo:


procedure TfrmPrincipal.FormCreate(Sender: TObject);
begin
FTop := Top;
FLeft := Left;
end;

Y el procedimiento "WM_MOVE" de este otro:


procedure TfrmPrincipal.WM_MOVE(var Msg: TMessage);
begin
if (FTop <> 0) then
begin
Top := FTop;
Left := FLeft;
end;
end;

Comprobamos antes que "FTop" no sea cero, pues el procedimiento se ejecuta incluso antes del evento "OnCreate" (a lo que parece) de tal modo que de no hacerlo así el formulario se situaría en la esquina superior izquierda de la pantalla y no habría luego quien lo moviera de ahí. ;)

Ahora, por favor, decidme que me calme y que me tranquilize, porque hay alguna propiedad, algún método, en fin, alguna forma mucho más elegante, aparente, práctica y efectiva de hacer lo que se trata de llevar a cabo. ¿Eh? ;)

roman
06-10-2005, 17:32:03
Hola,

El problema con la opción que comenta dec es que el efecto no es muy bueno: si la opción DragFullWindows (en propiedades de la pantalla) está activada, se nota un redibujado conforme se intenta mover la ventana. Si está desactivada entonces el usuario puede ver cómo se mueve la silueta de la ventana mientras la arrastra aun que al final se quede donde estaba.

Recomiendo revisar el hilo Como hacer que un usuario no mueva la form? (http://www.clubdelphi.com/foros/showthread.php?t=5289)

// Saludos

Lepe
06-10-2005, 17:46:22
Lo mismo pero de otra forma.

private
{ Private declarations }
//
procedure noMove(var Msg:Twmwindowposchanging);message wm_windowposchanging;
end;


procedure TForm1.noMove(var Msg: Twmwindowposchanging);
begin

Msg.WindowPos.x := 100; // left
Msg.WindowPos.y:= 200; // top
Msg.WindowPos.cx:= 500; // ancho
Msg.WindowPos.cy:= 600 // alto
end;


Cuando se cambie de posición, nosotros ponemos los valores

Saludos

Lepe
06-10-2005, 17:51:26
En mi caso no ocurre, ya que antes de mover la ventana, es cuando le cambio los valores, así que no hay redibujado de pantalla.

En el ejemplo de Roman ¿hay que deshabilitar el maximizado? ... jamás quisiera empezar una contienda con roman.... bueno, tomando cervezas a lo mejor, pero en el resto de temas... paso :D


Edito: Retiro todo lo dicho, con este método tambien pasa lo mencionado por roman :D

yusnerqui
06-10-2005, 18:05:52
Bueno pues me había construido este ejemplito:


type
TForm1 = class(TForm)
private
{ Private declarations }
procedure WMNCMOUSEDOWN(var Message: TMessage);
message WM_NCLBUTTONDOWN;
....

implementation
...

procedure TForm1.WMNCMOUSEDOWN(var Message: TMessage);
begin
if Message.wParam <> HTCAPTION then
inherited;
end;



pero después de haber visto el hilo recomendad por roman....

mejor voy a estudiar:confused: :confused: :confused:

Saludos:D

roman
06-10-2005, 18:21:01
Retiro todo lo dicho, con este método tambien pasa lo mencionado por roman


Así es. No sucede si DragFullWindows está activo pero sí en el otro caso. Quizá podrías corregir un poco lidiando también con WM_MOVING, que es el que se encarga del dibujado de la silueta, pero entonces ya la cuestión se complica más de la cuenta.

A final de cuentas, para mover una ventana hay muchos pasos involucrados:

WM_NCHITTEST, WM_ENTERSIZEMOVE, WM_MOVING, WM_EXITSIZEMOVE, WM_MOVE, WM_WINDOWPOSCHANGING, WM_WINDOWPOSCHANGED

y uno puede intentar frenar los necesarios. Pero al quitar el comando SC_MOVE te evitas todo esto, simplemente le dices: está prohibido mover.

En cuanto a lo de maximizar la ventana pues esto lo puedes evitar quitando biMaximize de la propiedad BorderIcons.

Si además se desea evitar que se cambie el tamaño de la ventana, se puede añadir:

DeleteMenu(GetSystemMenu(Handle, false), SC_SIZE, MF_BYCOMMAND);

aunque en este caso también hay que trabajar WM_NCHITTEST para que el cursor del ratón no cambie de forma cuando se coloca sobre los bordes:


inherited;

if Msg.Result in [HTSIZEFIRST..HTSIZELAST] then
Msg.Result := Windows.HTNOWHERE;


// Saludos

roman
06-10-2005, 18:35:45
El método tiene un problema que antes no había visto:

Si se quitan todos los iconos de la barra de título, entonces la ventana ya se puede mover. Veremos si se puede solucionar esto.

// Saludos

Lepe
06-10-2005, 18:55:37
Nada como quitar la barra de titulo, y como mucho, hacer una con un panel y 3 botones.

Ya no tenemos que atar de pies y manos, simplemente se las cortamos :D :D

Un saludo

yusnerqui
06-10-2005, 19:13:14
Bueno, posteo para insistir en mi método de capturar el mousedown en la zona no cliente(WM_NCLBUTTONDOWN), y no hacer nada en el caso de que esté sobre el caption:


if Message.wParam <> HTCAPTION then
inherited;


creo que esto acompañado de lo propuesto por roman para borrar la opción de mover en el menu:


DeleteMenu(GetSystemMenu(Handle, false), SC_MOVE, MF_BYCOMMAND);


impide cualquier movimiento de la forma, independientemente de que tenga botones o no.

Saludos

roman
06-10-2005, 19:23:51
Bueno, posteo para insistir en mi método de capturar el mousedown en la zona no cliente(WM_NCLBUTTONDOWN), y no hacer nada en el caso de que esté sobre el caption


Sí. Parece ser un buen complemento para cuando no hay ningún botón. Nada más observar que con ello se impide cualquier tipo de actividad en la barra de título. Si se desea tener todavía opciones del menú activas, entonces tu método sería demasiado restrictivo.

// Saludos

yusnerqui
06-10-2005, 19:42:40
Lo probaste??


Nada más observar que con ello se impide cualquier tipo de actividad en la barra de título.
No entiendo, en el ejemplo que tengo me permite accionar sobre los botones de maximizar, cerrar etc.


Si se desea tener todavía opciones del menú activas, entonces tu método sería demasiado restrictivo.
Lo dicho, puedo desplegar también el menu sin ningún tipo de problemas.



Edito:
Ampliando un poco más la respuesta puedo decir que al especificar que la acción sea controlada solo sobre el caption, especificando (HTCAPTION), evito que se inhabiliten otras zonas no cliente como el menú sistema (HTSYSMENU), el botón de maximizar (HTMAXBUTTON), el de minimizar (HTMINBUTTON) entre otros.


Saludos.

roman
06-10-2005, 19:50:31
Tienes razón yusnerqui, disculpa. Me quedé pensando en el ejemplo de Marcos del otro hilo.

// Saludos

yusnerqui
06-10-2005, 20:00:22
Tienes razón yusnerqui, disculpa.

No hay nada que disculpar maestro, en todo caso me corresponde agradecerte a ti y al foro por las cosas que me han enseñado.

un abrazo

dec
12-10-2005, 13:25:36
Hola,

Esto parece funcionar estupendamente:


unit Unit1;

interface

uses
Windows, Forms, Messages;

type
TForm1 = class(TForm)
protected
procedure WndProc(var Message: TMessage); override;
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.WndProc(var Message: TMessage);
begin
if Message.Msg = WM_SYSCOMMAND then
begin
if (Message.WParam and $FFF0) = SC_MOVE then
Message.Result := 0
else
inherited;
end
else
inherited;
end;

end.

roman
12-10-2005, 17:12:08
De hecho, esta forma es la primera (http://www.clubdelphi.com/foros/showpost.php?p=21029&postcount=2) que mencioné en el otro hilo. El único "problema" es que aun cuando el formulario no se mueve, la opción "Mover" sigue apareciendo en el menú del sistema y fue cuando traté de reemplazar el método por la remoción del comando.

Ahora veo que basta dejar ambos para que funcione todo: quitar el menú con

DeleteMenu(GetSystemMenu(Handle, false), SC_MOVE, MF_BYCOMMAND);

e impedir SC_MOVE en el manejador de WM_SYSCOMMAND.

// Saludos

dec
13-10-2005, 00:15:55
Hola,



De hecho, esta forma es la primera (showpost.php?p=21029&postcount=2) que mencioné en el otro hilo. (...)

Vaya. Me ilusioné pensando que serviría estupendamente y no me percaté del problema... ya descrito... lo lamento. :rolleyes:

roman
13-10-2005, 07:00:39
lo lamento

Pues no lo lamentes ya que fue por tu mensaje que me percaté de que mi error estaba en haber reemplazado un método por otro (SC_MOVE por DeleteMenu) cando lo apropiado era usar ambos a la vez.

// Saludos