Ir al contenido


Foto

Ventana Child semitransparente


  • Por favor identifícate para responder
8 respuestas en este tema

#1 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 05 abril 2013 - 05:32

A raíz de una pregunta en el foro amigo CD, a la cual he contestado tarde por estar últimamente un poco ausente de los foros, me ha parecido buena idea publicar aquí el truco de mi respuesta.

El problema es crear una ventana child semitransparente de otra que no lo es. Este problema aparentemente simple se complica pues Windows no lo admite:

Windows 8: The WS_EX_LAYERED style is supported for top-level windows and child windows. Previous Windows versions support WS_EX_LAYERED only for top-level windows.


El truco usado va a ser simular que la ventana "hija" es child cuando en realidad es una con estilo top-level y para ello basta con gestionar el mensaje WM_MOVING en la ventana padre y en la hija. En la ventana padre conseguiremos que al mover ésta lo hagan, también y simultáneamente, las hijas. En la ventana hija conseguiremos que su movimiento no traspase los límites de la ventana padre. De esta forma simulamos el efecto child y nuestra ventana hija podrá ser semitransparente.

El código es el siguiente:


delphi
  1. procedure WMMoving(var Message: TWMMOVING); message WM_MOVING;



Para la ventana Padre:


delphi
  1. procedure TForm1.WMMoving(var Message: TWMMOVING);
  2. var
  3.   i: integer;
  4. begin
  5.   inherited;
  6.   for i:= 0 to ComponentCount-1 do
  7.   begin
  8.     if Components[i].ClassName <> 'TForm2' then continue;
  9.     with Components[i] as TForm do
  10.       SetWindowPos(Handle, HWND_TOPMOST, Message.DragRect.Left + Left - self.Left, Message.DragRect.Top + Top - self.Top, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOZORDER);
  11.   end;
  12. end;



Para la ventana hija:


delphi
  1. procedure TForm2.WMMoving(var Message: TWMMOVING);
  2. var
  3.   Right, Bottom: integer;
  4. begin
  5.   inherited;
  6.   with Application.MainForm do
  7.   begin
  8.     Right:=  Left + Width;
  9.     Bottom:= Top + Height;
  10.     if Message.DragRect.Left < Left then
  11.     begin
  12.       Message.DragRect.Left:= Left;
  13.       Message.DragRect.Right:= Left + self.Width;
  14.     end;
  15.     if Message.DragRect.Top < Top then
  16.     begin
  17.       Message.DragRect.Top:= Top;
  18.       Message.DragRect.Bottom:= Top + self.Height;
  19.     end;
  20.     if Message.DragRect.Left > Right - self.Width then
  21.     begin
  22.       Message.DragRect.Left:= Right - self.Width;
  23.       Message.DragRect.Right:= Right - self.Width + self.Width;
  24.     end;
  25.     if Message.DragRect.Bottom > Bottom then
  26.     begin
  27.       Message.DragRect.Top:= Bottom - self.Height;
  28.       Message.DragRect.Bottom:= Bottom - self.Height + self.Height;
  29.     end;
  30.   end;
  31. end;



Y con esto basta para conseguir el efecto.

Coloco el código completo de un sencillo ejemplo (por si se corrompen los archivos adjuntos...) y subo el proyecto completo:

Ventana Padre:


delphi
  1. unit Unit1;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7.   Dialogs, StdCtrls;
  8.  
  9. type
  10.   TForm1 = class(TForm)
  11.     Button1: TButton;
  12.     procedure Button1Click(Sender: TObject);
  13.   private
  14.     procedure WMMoving(var Message: TWMMOVING); message WM_MOVING;
  15.   public
  16.     { Public declarations }
  17.   end;
  18.  
  19. var
  20.   Form1: TForm1;
  21.  
  22. implementation
  23.  
  24. uses Unit2;
  25.  
  26. {$R *.dfm}
  27.  
  28. procedure TForm1.Button1Click(Sender: TObject);
  29. begin
  30.   with TForm2.Create(self) do
  31.   begin
  32.     AlphaBlend:= true;
  33.     AlphaBlendValue:= 80;
  34.     Show;
  35.     SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOMOVE);
  36.   end;
  37. end;
  38.  
  39. procedure TForm1.WMMoving(var Message: TWMMOVING);
  40. var
  41.   i: integer;
  42. begin
  43.   inherited;
  44.   for i:= 0 to ComponentCount-1 do
  45.   begin
  46.     if Components[i].ClassName <> 'TForm2' then continue;
  47.     with Components[i] as TForm do
  48.       SetWindowPos(Handle, HWND_TOPMOST, Message.DragRect.Left + Left - self.Left, Message.DragRect.Top + Top - self.Top, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOZORDER);
  49.   end;
  50. end;
  51.  
  52. end.



Ventana Hija:


delphi
  1. unit Unit2;
  2.  
  3. interface
  4.  
  5. uses
  6.   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  7.   Dialogs;
  8.  
  9. type
  10.   TForm2 = class(TForm)
  11.     procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
  12.       Shift: TShiftState; X, Y: Integer);
  13.   private
  14.     procedure WMMoving(var Message: TWMMOVING); message WM_MOVING;
  15.   public
  16.     { Public declarations }
  17.   end;
  18.  
  19. var
  20.   Form2: TForm2;
  21.  
  22. implementation
  23.  
  24. {$R *.dfm}
  25.  
  26. procedure TForm2.WMMoving(var Message: TWMMOVING);
  27. var
  28.   Right, Bottom: integer;
  29. begin
  30.   inherited;
  31.   with Application.MainForm do
  32.   begin
  33.     Right:=  Left + Width;
  34.     Bottom:= Top + Height;
  35.     if Message.DragRect.Left < Left then
  36.     begin
  37.       Message.DragRect.Left:= Left;
  38.       Message.DragRect.Right:= Left + self.Width;
  39.     end;
  40.     if Message.DragRect.Top < Top then
  41.     begin
  42.       Message.DragRect.Top:= Top;
  43.       Message.DragRect.Bottom:= Top + self.Height;
  44.     end;
  45.     if Message.DragRect.Left > Right - self.Width then
  46.     begin
  47.       Message.DragRect.Left:= Right - self.Width;
  48.       Message.DragRect.Right:= Right - self.Width + self.Width;
  49.     end;
  50.     if Message.DragRect.Bottom > Bottom then
  51.     begin
  52.       Message.DragRect.Top:= Bottom - self.Height;
  53.       Message.DragRect.Bottom:= Bottom - self.Height + self.Height;
  54.     end;
  55.   end;
  56. end;
  57.  
  58. procedure TForm2.FormMouseDown(Sender: TObject; Button: TMouseButton;
  59.   Shift: TShiftState; X, Y: Integer);
  60. begin
  61.   if Button = mbLeft then
  62.   begin
  63.     ReleaseCapture;
  64.     Perform(WM_SYSCOMMAND, $F012, 0);
  65.   end;
  66. end;
  67.  
  68. end.



Espero que sirva de ayuda o inspiración.


Saludos.

  • 0

#2 enecumene

enecumene

    Webmaster

  • Administrador
  • 7.419 mensajes
  • LocationRepública Dominicana

Escrito 05 abril 2013 - 05:49

Ya hacían falta tus trucos :D (y)
  • 0

#3 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 05 abril 2013 - 06:00

Bueno, es cierto que llevo un tiempo un poco "parado". Si me apetecía escribir algún truquillo... :)


Saludos.
  • 0

#4 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.945 mensajes
  • LocationMéxico

Escrito 05 abril 2013 - 08:25

Vaya¡¡¡ Si no es por el Blog de Nuestro amigo ene no me entero del truco¡¡¡ Gracias amigo resulta muy interesante.  Se me ocurre a bote pronto que puede usarse para realzar pantallas, es decir hacer transparentes aquellas que no están en uso y opaca la que si está en uso. :D ya veremos que se puede hacer con este excelente truco.

Un abrazo amigo y gracias por compartirlo.
  • 0

#5 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 05 abril 2013 - 09:36

.......El problema es crear una ventana child semitransparente de otra que no lo es. Este problema aparentemente simple se complica pues Windows no lo admite:.....


Que Windows no admite queeeeeee ???? :D :D :D

Para Delphi y asumo que C++ no hay impedimentos, bueno siempre y cuando el código venga de compañeros como escafandra ;)

Saludos
  • 0

#6 poliburro

poliburro

    Advanced Member

  • Administrador
  • 4.945 mensajes
  • LocationMéxico

Escrito 05 abril 2013 - 09:39


.......El problema es crear una ventana child semitransparente de otra que no lo es. Este problema aparentemente simple se complica pues Windows no lo admite:.....


Que Windows no admite queeeeeee ???? :D :D :D

Para Delphi y asumo que C++ no hay impedimentos, bueno siempre y cuando el código venga de compañeros como escafandra ;)

Saludos


Amen
  • 0

#7 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 05 abril 2013 - 09:46

Gracias, amigos. Pero como decía hasta Win8 no se admiten ventanas child semitransparentes. Yo solo hice, una vez mas,  "trampas"  *-)

Saludos.
  • 0

#8 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 14.448 mensajes
  • LocationMéxico

Escrito 05 abril 2013 - 09:50

Gracias, amigos. Pero como decía hasta Win8 no se admiten ventanas child semitransparentes. Yo solo hice, una vez mas,  "trampas"  *-)

Saludos.


Eso lo sabemos mi estimado amigo, pero esas "trampas" no cualquiera se las ingenia :)

Lo dicho, Que windows no admite queeeee ????? :D :D :D

Saludos
  • 0

#9 escafandra

escafandra

    Advanced Member

  • Administrador
  • 4.107 mensajes
  • LocationMadrid - España

Escrito 05 abril 2013 - 11:32

He visto un molesto efecto cuando las ventanas hijas tienen borde y Caption, son mas de una y movemos la ventana padre. Se trata de un cambio rápido se foco de una a otra. La solución es sencilla y basta con añadir SWP_NOACTIVATE y SWP_NOZORDER en SetWindowPos en el procedimiento TForm1.WMMoving:



delphi
  1. SetWindowPos(Handle, HWND_TOPMOST, Message.DragRect.Left + Left - self.Left, Message.DragRect.Top + Top - self.Top, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOZORDER);



Saludos.
  • 0




IP.Board spam blocked by CleanTalk.