Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Otros entornos y lenguajes > C++ Builder
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 10-10-2012
chinchan chinchan is offline
Miembro
 
Registrado: abr 2006
Posts: 109
Poder: 19
chinchan Va por buen camino
Form en primer plano

Hola a todos, tengo una aplicación en C++ Builder en la que uno de sus Form (que no es el principal), quiero que esté en primer plano (StayonTop) pero también en primer plano ante cualquier otro programa o aplicación de Windows. ¿Se puede hacer? ¿Cómo?. Muchas Gracias.
Responder Con Cita
  #2  
Antiguo 10-10-2012
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.042
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Mira alguno de los enlaces del final de esta página, abajo del todo, pueden servirte.
Responder Con Cita
  #3  
Antiguo 10-10-2012
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 10.508
Poder: 36
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Hola chinchan.

En el evento OnShow del form que te interese tenga ese comportamiento:
Código:
void __fastcall TfrmSecundario::FormShow(TObject *Sender) {
 SetWindowPos(Handle, HWND_TOPMOST, Left, Top, Width, Height, SWP_SHOWWINDOW);
}
Saludos.
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #4  
Antiguo 10-10-2012
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
La respuesta de ecfisa es correcta , como lo es esta variante:
Código:
__fastcall TForm2::TForm2(TComponent* Owner)
  : TForm(Owner)
{
  SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
}
Esto, directamente desde la VCL, también debería funcionar en fase de diseño o ejecución:
Código:
__fastcall TForm2::TForm2(TComponent* Owner)
  : TForm(Owner)
{
  FormStyle = fsStayOnTop;
}

Saludos.
Responder Con Cita
  #5  
Antiguo 10-10-2012
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Analizando mejor la cuestión me doy cuenta de que se pide en un form que no sea el principal...

En ese caso el mecanismo que propongo es reescribir la función virtual TForm::WndProc():
Código:
class TForm2 : public TForm
{
...........
protected:    
  virtual void __fastcall WndProc(Messages::TMessage &Message);
..........
};
Código:
void  __fastcall TForm2::WndProc(Messages::TMessage& Message)
{
  if(Visible && Message.Msg == WM_KILLFOCUS)
      SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

  TForm::WndProc(Message);
}

Saludos.
Responder Con Cita
  #6  
Antiguo 15-10-2012
chinchan chinchan is offline
Miembro
 
Registrado: abr 2006
Posts: 109
Poder: 19
chinchan Va por buen camino
Gracias por responder. Efectivamente, las soluciones que dáis valen si llamo a este Form como ShowModal, la solución creo que es la que apunta Escafandra al final, lo que ocurre es que me pierdo con eso de reescribir la función virtual TForm::WndProc():
Escfandra: podrías por favor, aclarar un poco esa última solución que has propuesto?.

Muchas Gracias.
Responder Con Cita
  #7  
Antiguo 16-10-2012
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Una función virtual es una función de la clase base que puede ser, o no, redefinida en las clases derivadas y que tras ello puede ser llamada desde un puntero o referencia a su clase base.

WndProc es una función virtual de la clase base TForm que hereda nuestro formulario y que usará a no ser que la reescribamos para nuestro formulario. WndProc se encarga del tratamiento de todos los mensajes de TForm y las clases derivadas (se hereda). Como nos interesa interceptar los mensajes redefino la función, es por ello que puse una fracción de la definición de la clase de nuestro formulario en primer plano:

Código:
class TForm2 : public TForm
{
...........
protected:    
  virtual void __fastcall WndProc(Messages::TMessage &Message);
..........
};
Y luego la implementamos teniendo cuidado de terminar llamando a la función WndProc de la clase base (TForm::WndProc).

Este truco sirve para interceptar cualquier mensaje o crear nuevos eventos o respuestas a mensajes no previstos en la clase base TForm.

También podemos dar respuesta a un mensaje con la macro BEGIN_MESSAGE_MAP / END_MESSAGE_MAP(TForm)...

En definitiva, en este caso, estamos reescribiendo la respuesta al mensaje WM_KILLFOCUS para aprovechar a ponernos en primer plano:
Código:
void  __fastcall TForm2::WndProc(Messages::TMessage& Message)
{
  if(Visible && Message.Msg == WM_KILLFOCUS)
      SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

  TForm::WndProc(Message);
}
Espero haberme explicado bien.


Saludos.
Responder Con Cita
  #8  
Antiguo 16-10-2012
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 10.508
Poder: 36
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Cita:
Empezado por chinchan Ver Mensaje
Gracias por responder. Efectivamente, las soluciones que dáis valen si llamo a este Form como ShowModal
Hola chinchan.

Si, lo que te sugerí en el mensaje #3, funciona siempre que el form se muestre de forma modal. En cambio lo que te sugiere escafandra es una solución completa, ya que funciona para ambos modos.

Pero para que conserve el comportamiento aún despues de una segunda pérdida del foco, creo que habría que pasarle el flag SWP_SHOWWINDOW en lugar de SWP_NOACTIVATE.

Código:
void  __fastcall TForm2::WndProc(Messages::TMessage& Message)
{
  if( Visible && Message.Msg == WM_KILLFOCUS ) {
    SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, 
      SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
  }
  TForm::WndProc(Message);
}
Saludos.
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #9  
Antiguo 16-10-2012
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
El hecho de cambiar SWP_NOACTIVATE por SWP_SHOWWINDOW puede provocar alteraciones al perder el foco pues la ventana se va a "negar" a ello. La única pega que se puede poner es que se debe poner FormStyle = fsStayOnTop; en el momento de diseño, en el constructor, o bien alterar el código de esta forma para obligar el primer plano desde el comienzo:


Código:
void  __fastcall TForm3::WndProc(Messages::TMessage& Message)
{
  if(Visible && Message.Msg == WM_KILLFOCUS || Message.Msg == WM_SHOWWINDOW){
    SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  }
  TForm::WndProc(Message);
}
A mi me funciona correctamente en Win XP.


Saludos.
Responder Con Cita
  #10  
Antiguo 16-10-2012
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 10.508
Poder: 36
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Hola escafandra.

Seguramente el comportamiento difiera por la diferente versión de S.O. ...

En Vista, lo que me sucede es que al mostrar el form por primera vez y realizar foco sobre otra aplicación de fondo, no pierde su condición de estar al frente. Pero al repetir la acción, es decir, darle nuevamente el foco al form y luego hacer click sobre otra aplicación la pierde.

Al agregar SWP_SHOWWINDOW como flag, se comporta como se espera. Y como detalle, del mismo modo lo hace si se agrega una lína con BringToFront(), todo esto habiendo sido mostrado como no modal.

También había probado el condicional de tu último mensaje
Código:
  if(Visible && Message.Msg == WM_KILLFOCUS || Message.Msg == WM_SHOWWINDOW)
ya que la captura me sonaba totalmente lógica, pero sin resultado (al igual que otras pruebas que intenté).


Un saludo.
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #11  
Antiguo 16-10-2012
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Cita:
Empezado por ecfisa Ver Mensaje
Seguramente el comportamiento difiera por la diferente versión de S.O. ...
Muy seguramente...
Cita:
Empezado por ecfisa Ver Mensaje
En Vista, lo que me sucede es que al mostrar el form por primera vez y realizar foco sobre otra aplicación de fondo, no pierde su condición de estar al frente. Pero al repetir la acción, es decir, darle nuevamente el foco al form y luego hacer click sobre otra aplicación la pierde.
¿Has probado así en Vista:?
Código:
  if(Visible && Message.Msg == WM_KILLFOCUS || Message.Msg == WM_SHOWWINDOW)
    SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
Cita:
Empezado por ecfisa Ver Mensaje
Y como detalle, del mismo modo lo hace si se agrega una lína con BringToFront(), todo esto habiendo sido mostrado como no modal..
En WinXp BringToFront(), en la captura de WndProc(), no funciona.

Quizás deba quedar así:
Código:
void  __fastcall TForm2::WndProc(Messages::TMessage& Message)
{
  if(Visible && Message.Msg == WM_KILLFOCUS || Message.Msg == WM_SHOWWINDOW)
    SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
  
  TForm::WndProc(Message);
}
Habría que probar en Vista y en Win7...


Saludos.
Responder Con Cita
  #12  
Antiguo 16-10-2012
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 10.508
Poder: 36
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Cita:
¿Has probado así en Vista:?
Código:
  if(Visible && Message.Msg == WM_KILLFOCUS || Message.Msg == WM_SHOWWINDOW)
    SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
Hola escafandra.

Si, pero al incluir en el condicional "...|| Message.Msg == WM_SHOWWINDOW)" hace que deje de tener el comportamiento, al igual que al agregar "| SWP_NOACTIVATE" como flag.

Hasta ahora el único modo con que he podido lograr el comportamiento es con:
Código:
void  __fastcall TForm2::WndProc(Messages::TMessage& Message)
{
  if( Visible && Message.Msg == WM_KILLFOCUS ) {
    SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0,
      SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW );
  TForm::WndProc(Message);
}
Realmente no sé el motivo, por que evaluar WM_KILLFOCUS y WM_SHOWWINDOW en el condicional pareciera totalmente razonable...

Saludos.
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #13  
Antiguo 17-10-2012
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Es curioso el comportamiento de Vista...

El WM_SHOWWINDOW se puede eliminar del condicional si colocamos el Form como FormStyle = fsStayOnTop en el constructor o en fase de diseño. Quizás esto cambie el comportamiento. Lo digo e insisto porque el hecho de cambiar SWP_NOACTIVATE por SWP_SHOWWINDOW si altera en Win XP haciendo que al perder el foco continue siendo ventana activa confundiendo al usuario.


Saludos.
Responder Con Cita
  #14  
Antiguo 17-10-2012
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Me he dado cuenta de que no sirve WM_KILLFOCUS, si en el formulario tenemos un TEdit, al menos en WinXP (eso pasa por probar en condiciones de laboratorio y no reales ...)

Por lo tanto he probado esto otro que funciona muy bien en WinXP y que includo coloca nuestra ventana sobre cualquiera aún siendo otra también HWND_TOPMOST (por ejemplo el TaskMgr)

Código:
void  __fastcall TForm3::WndProc(Messages::TMessage& Message)
{
  if(Visible && Message.Msg == WM_WINDOWPOSCHANGING)
    SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

  TForm::WndProc(Message);
}
ecfisa, pruébalo en Vista y si puedes en Win7.


Saludos.
Responder Con Cita
  #15  
Antiguo 17-10-2012
Avatar de ecfisa
ecfisa ecfisa is offline
Moderador
 
Registrado: dic 2005
Ubicación: Tres Arroyos, Argentina
Posts: 10.508
Poder: 36
ecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to beholdecfisa is a splendid one to behold
Tuve estos resultados:

Vista: siempre mantiene la posición al frente. Pero el form principal tiene un comportamiento algo extraño luego de que el form secundario pierde el foco y lo recupera nuevamente.
Por ejemplo, puse en el form principal un botón para mostrar el secundario (siendo este mas pequeño que aquel) y al recuperar el foco el form secundario, pareciera que el form principal se transparenta visualizando sólo el botón.

Continuando las pruebas agregué un Edit y de este sólo queda visible el nombre (Edit1), en este caso da la impresión de que hiciera una transparencia dejando los colores clBtnFace y clWindow, visibles sobre la aplicación de fondo.

W7: Aquí funciona perfectamente sin comportamientos extraños.

Saludos.
__________________
Daniel Didriksen

Guía de estilo - Uso de las etiquetas - La otra guía de estilo ....
Responder Con Cita
  #16  
Antiguo 17-10-2012
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Pues entonces vamos a forzar la máquina un poco mas.

Creo que este código va a funcionar en XP, Vista y Seven. Espero no equivocarme pues sólo lo he probado en XP

Código:
void ReDrawWindow(HWND hWnd)
{
  TRect cr;
  ::GetClientRect(hWnd, &cr);
  InvalidateRect(hWnd, &cr, true);
  SendMessage(hWnd, WM_NCPAINT, 0, 0);
  RedrawWindow(hWnd, &cr, 0, RDW_FRAME|RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN);
}

void  __fastcall TForm2::WndProc(Messages::TMessage& Message)
{
  if(Visible && Message.Msg == WM_WINDOWPOSCHANGING)
    SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

  if(Visible && Message.Msg == WM_ACTIVATE){
    SetWindowPos(Application->MainForm->Handle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
    ReDrawWindow(Application->MainForm->Handle);
  }
  
  TForm::WndProc(Message);
}

Saludos.

Última edición por escafandra fecha: 17-10-2012 a las 23:48:57.
Responder Con Cita
  #17  
Antiguo 18-10-2012
Avatar de escafandra
[escafandra] escafandra is offline
Miembro Premium
 
Registrado: nov 2007
Posts: 2.197
Poder: 20
escafandra Tiene un aura espectacularescafandra Tiene un aura espectacular
Mejorando el código para el caso de tener mas de dos formularios abiertos y sólo uno sea TopMost:
Código:
void ReDrawWindow(HWND hWnd)
{
  TRect cr;
  ::GetClientRect(hWnd, &cr);
  InvalidateRect(hWnd, &cr, true);
  SendMessage(hWnd, WM_NCPAINT, 0, 0);
  RedrawWindow(hWnd, &cr, 0, RDW_FRAME|RDW_ERASE|RDW_INVALIDATE|RDW_UPDATENOW|RDW_ALLCHILDREN);
}

void  __fastcall TForm2::WndProc(Messages::TMessage& Message)
{
  if(Visible && Message.Msg == WM_WINDOWPOSCHANGING)
    SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);

  if(Visible && Message.Msg == WM_ACTIVATE && Message.WParam != 0){
    SetWindowPos(Application->MainForm->Handle, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
    for(int i = 0; i<Application->ComponentCount; i++){
      TForm *F = static_cast<TForm*>(Application->Components[i]);
      if (F) ReDrawWindow(F->Handle);
    }
  }

  TForm::WndProc(Message);
}

Saludos.
Responder Con Cita
  #18  
Antiguo 19-10-2012
chinchan chinchan is offline
Miembro
 
Registrado: abr 2006
Posts: 109
Poder: 19
chinchan Va por buen camino
Desde luego.... soys geniales. Es lo que andaba buscando. Muchas Gracias de nuevo.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
Abrir outlook en primer plano Jose Manuel Servers 3 24-02-2012 19:25:50
2 Form Siempre En Primer Plano FrianxD C++ Builder 16 15-01-2008 22:41:02
Como mostrar en primer plano Blackspike API de Windows 4 14-01-2008 09:13:20
Aplicación en primer plano jordillussa Varios 4 20-03-2007 19:58:43
Aplicación siempre en primer plano Novás Varios 2 08-03-2004 09:31:09


La franja horaria es GMT +2. Ahora son las 19:05:32.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi