2010-06-08 34 views
13

Muchas veces después de la era de Windows 98, hemos experimentado que algunos diálogos pierden su orden Z y vuelven a la forma anterior.Delphi - ¿Cómo evitar que Forms/MsgBoxes se muevan en forma previa?

Por ejemplo:

Dialog1.ShowModal; 

Dialog1.OnClickButton() : ShowMessage('anything'); 

Cuando aparezca de mensaje, que a veces no tiene el enfoque y se mueve bajo Dialog1. Los usuarios están confundidos al respecto, dicen: Mi aplicación se congeló !!! Pero si usan Alt + Tab para moverse a otra aplicación y volver, el foco vuelve al MessageBox y será la ventana de primer plano.

Hemos experimentado esto con ShowMessage, MessageBox, formularios normales y también formularios QuickReport.

¿Alguien sabe de esto? ¿Es un error de Windows? ¿Cómo puedes prevenirlo? Cómo atrapar esto?

Gracias por su ayuda: dd


Me dijo que después de Win98, por lo que todos los sistemas operativos (Win7 también) se ven afectados por este problema. Utilizamos Delphi 6 Prof, por lo que las propiedades no funcionan con los formularios predeterminados.

Alguien dijo que los diálogos de mensaje son controlables con MessageBox + MB_APPLMODAL. Esta es una buena noticia, pero tenemos muchos formularios y componentes antiguos, herramientas de terceros.

Así que es un trabajo difícil hacer una aplicación completamente nueva con la sustitución de los formularios.

Pero intentaremos hacer esto.

Creo que la respuesta es que se trata de un problema de mitad de aplicación y medio problema de Windows. Si Windows a veces maneja esto, y algunas veces no lo hace, parece ser un error de Windows. Pero si podemos forzar una buena ventana modal, entonces es un error de programación.

¿Alguien puede explicarme cuál es el significado de la bandera WS_POPUP? ¿Tiene algún efecto secundario o no?

Gracias: dd

+0

menudo he tenido este problema también, no he encontrado una respuesta tampoco. Esperamos con interés lo que la gente ha inventado. –

+0

¿Con qué versión esto está sucediendo? –

+0

eres Windows 98? Guau. Como pregunta Sertac, la versión de Delphi es crítica. Delphi 2007 y posteriores tienen una solución alternativa. –

Respuesta

13

Eso es lo que el PopupMode and PopupParent properties son para.

por ejemplo, se puede hacer:

Dialog1.PopupMode := pmExplicit; 
Dialog1.PopupParent := self; 
Dialog1.ShowModal; 

Esto indica a Windows el Z-orden correcto.

+0

Wow, la [documentación sobre esto] (http://docwiki.embarcadero.com/VCL/en/Forms.TForm.PopupMode) ¡no es útil en absoluto! Pero inténtalo; ¡funciona! –

+1

@Craig - no ayudaría con ShowMessage, MessageBox y mensajes de excepción, aunque .. –

+0

@Sertac, esas son funciones de conveniencia en ventanas normales. Puede hacer mensajes de excepción personalizados manejando 'Application.OnException'. Del mismo modo, si necesita un 'ShowMessage' personalizado, puede escribir uno. –

6

Para las versiones antiguas de Delphi (antes de Delphi 2007), en formas que no sea su forma principal:

interface 
    TMyForm = Class(TForm) 
    protected 
    procedure CreateParams(var Para: TCreateParams); override; 
    end; 
... 
implementation 
... 
procedure TMyForm.CreateParams(var Para: TCreateParams); 
begin 
    inherited; 
    Para.Style := Para.Style or WS_POPUP; 
    { WinXP Window manager requires this for proper Z-Ordering } 
    // Para.WndParent:=GetActiveWindow; 
    Para.WndParent := Application.MainForm.Handle; 
end; 

Para cuadros de mensaje incluyen MB_TOPMOST en sus banderas:

Application.MessageBox(PChar(amessage), PChar(atitle), otherflags or MB_TOPMOST); 
+0

También tengo una solución para Diálogos creados con la unidad VCL Dialogs, antes de Delphi 2007. Si alguien necesita eso (para versiones anteriores a 2007), haga una nueva pregunta y publicaré ese código. –

0

miré esta página y las preguntas frecuentes durante media hora y todavía no se puede encontrar la manera de publicar un comentario, así que perdón por esta infracción de protocolo.

En primer lugar me gustaría dejar en claro que el cartel, en mi humilde opinión, no está utilizando Windows 98. Escribe "después de Windows 98 era" que entiendo significa que está teniendo este problema con las versiones de Windows después de 98.

Como también estoy teniendo este problema (CB2009), me gustaría enfatizar la pregunta del cartel "¿Es un error de Windows?", Que no he visto respondido. Si se trata de un error de Delphi/Builder, ¿hay alguna forma de evitarlo? No veo cómo interceptar todos los diálogos potenciales es una solución factible, ni evitar el uso de fsStayOnTop. Tengo un formulario de configuración que debe estar en la parte superior de mi formulario principal, pero el formulario de configuración puede y aparecerá en los cuadros de diálogo que bajo ciertas condiciones desaparecerán en el formulario de configuración.

Sería muy útil si entendiera dónde va mal el soporte de z-order, ya que puede ofrecer una pista sobre cómo evitarlo.

+0

Es un error de Windows, en el sentido de que el orden Z de sus formularios no es preservado por la arquitectura del "administrador de ventanas" interno de Windows en Windows XP, después de cierto punto. NO es un error de Windows, en el sentido de que la API de Windows en sí misma no garantiza que recuerde algún tipo de Z-Order particular que exista, a menos que haya establecido correctamente sus enlaces parent-window usando CreateParams (como he mostrado en mi respuesta). –

+0

Por cierto, ¿realmente no puede ver ningún texto (posiblemente gris) o un botón con la etiqueta "Agregar comentario"? –

+0

Sí, pero solo para mi propia publicación. Quizás uno solo puede comentar en otras publicaciones si uno tiene suficientes puntos, pero luego puedo publicar una respuesta. Así que no veo la lógica en esto. Ni por qué existe este error por cierto, parece bastante fácil de hacerlo bien. –

0

Un truco que he utilizado recientemente era aplicar estas dos líneas de código durante la creación de cada forma:

SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or 
    WS_EX_APPWINDOW or WS_EX_TOPMOST); 
SetWindowLong(Handle, GWL_HWNDPARENT, GetDesktopWindow); 

Mango es la manija de la forma (Form1.Handle). La parte WS_EX_APPWINDOW hace que cada ventana aparezca en la barra de tareas, elimínela si no desea ese efecto adicional.

Por mi forma principal que utilizo esta línea:

SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or 
    WS_EX_TOPMOST); 

También utilizo esta función para ayudar a construir mis cuadros de diálogo personalizados (he creado una nueva función para cada estilo de diálogo - error, confirmación, etc.) :

function CustomDlg(const AMessage : string; const ADlgType: TMsgDlgType; 
    const AButtons: TMsgDlgButtons; const ADefaultButton: TMsgDlgBtn) : TForm; 
begin 
    Result := CreateMessageDialog(AMessage, ADlgType, AButtons, ADefaultButton); 
    with Result do 
    begin 
     SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or 
     WS_EX_APPWINDOW or WS_EX_TOPMOST); 
     SetWindowLong(Handle, GWL_HWNDPARENT, GetDesktopwindow); 
     FormStyle := fsStayOnTop; 
     BringToFront; 
    end; 
end; 

la parte FormStyle := fsStayOnTop; es opcional, por supuesto, pero lo uso para asegurarse de que mi confirmación y de error diálogos son siempre visibles para el usuario.

Parece un poco de trabajo, pero el efecto neto es que ya no tengo que preocuparme por las formas que accidentalmente se esconden detrás de otras formas.

+0

Debo agregar que con la función 'SetWindowLong()' no necesita crear sus propios formularios personalizados y puede hacerlo a cualquier formulario existente que tenga. Si ya está creando formularios personalizados, reemplazar el 'CreateParams()' es el camino a seguir. –

Cuestiones relacionadas