2009-10-28 7 views
19

Mon application est basée sur des formulaires modaux. Le formulaire principal ouvre un formulaire avec ShowModal, ce formulaire en ouvre un autre avec ShowModal, nous avons donc des formulaires modaux empilés. Il y a parfois un problème quand on appelle ShowModal sous une forme nouvelle, il se cache derrière les formes précédentes, au lieu de les afficher en haut. Après avoir appuyé sur alt + tab, la forme revient en haut, mais ce n'est pas une bonne solution. Avez-vous rencontré ce problème et comment l'avez-vous géré?Le formulaire est caché derrière d'autres formulaires lorsque ShowModal est appelé

EDIT:

J'utilise Delphi 7.

+0

Merci pour l'ajout de la version. Cela aide si vous incluez cela dans le texte ou les tags de votre question quelque part. :-) –

+0

J'ai tout d'abord réglé la balise appropriée, puis ajouté EDIT :) – LukLed

+0

Tant que vous l'avez mis quelque part, cela fonctionne. Il ne doit pas nécessairement être dans l'une des étiquettes, tant que c'est dans le sujet ou le texte de la question quelque part. Cela permet aux utilisateurs de savoir quelle fonctionnalité vous avez à leur disposition lorsqu'ils répondent. :-) –

Répondre

20

Vous n'avez pas mentionné quelle version de Delphi ...

Les nouvelles versions Delphi ont ajouté deux nouvelles propriétés à TCustomForm: PopupMode et PopupParent. Définir PopupParent de votre boîte de dialogue modale sur le formulaire qui crée cette boîte de dialogue s'assure que le formulaire enfant reste au-dessus de son parent. Il règle généralement le problème que vous décrivez.

Je pense que cette paire de propriétés a été ajoutée dans Delphi 2006, mais elle pourrait avoir été 2005. Ils sont définitivement là dans Delphi 2007 et plus.

EDIT: Après avoir vu que vous utilisez Delphi 7, la seule suggestion que j'ai est que, dans le code qui affiche votre formulaire modal, vous désactivez le formulaire qui le crée, et le réactiver au retour. Cela devrait empêcher la fenêtre de création de recevoir des entrées, ce qui peut aider à garder l'ordre Z correct.

Quelque chose comme cela peut fonctionner (non testé, comme je ne suis plus en utilisant D7):

procedure TForm1.ShowForm2; 
begin 
    Self.Enabled := False; 
    try 
    with TForm2.Create(nil) do 
    begin 
     try 
     if ShowModal = mrOk then 
      // Returned OK. Do something; 
     finally 
     Free; 
     end; 
    end; 
    finally 
    Self.Enabled := True; 
    end; 
end; 

Si Form2 crée une fenêtre modale (comme vous l'avez mentionné), il suffit de répéter le processus - désactiver Form2 , créez Form3 et affichez-le de manière modale, puis réactivez Form2 lorsqu'il est renvoyé. Assurez-vous d'utiliser try..finally comme je l'ai montré, de sorte que si quelque chose ne va pas dans le formulaire modal, le formulaire de création est toujours réactivé.

+0

Désolé, il s'agit de Delphi 7. Il n'y a pas de PopupMode et PopupParent, mais il est bon de savoir qu'ils existent. – LukLed

+0

Je pourrais essayer cette solution, mais nous avons beaucoup de formulaires modaux dans le projet, les boîtes de message sont modales, donc cela peut être difficile à implémenter. Mais je vais essayer de le faire quand c'est possible. – LukLed

+0

Cela a fonctionné pour moi en utilisant Self.Enabled: = False; et Self.Enabled: = True; –

-1

j'ai trouvé que l'utilisation du "Always On Top" drapeau sur plus d'une forme provoque des problèmes avec l'ordre Z. Et vous pouvez également trouver le besoin de la fonction BringWindowToTop. Lors du lancement d'une boîte de message à l'aide du WinAPI intégré (MessageBox), j'ai trouvé que le passage de la poignée de la fenêtre appelante est nécessaire pour s'assurer que l'invite apparaît toujours en haut.

+1

Voir ma réponse à Lars D. Le propriétaire (ou le parent) n'a rien à voir avec le problème décrit. Le problème est un effet secondaire de la fenêtre cachée de TAppication qui est supprimée de la barre des tâches; cela a causé le problème avec les formes enfants qui ont perdu leur place dans l'ordre Z, qui est ce que PopupParent et PopupMode ont été créés pour réparer. –

+0

Juste assez ... sur une inspection plus approfondie, je me rends compte que je pensais à l'aide de la fonction Windows.MessageBox et en passant le handle de la fenêtre d'appel pour s'assurer que le MessageBox apparaît au-dessus de l'appelant - que je considérais être le parent". Éditera ma réponse pour refléter ceci. –

2

De ce link il semble que le problème est avec la "fenêtre fantôme" qui a été introduite en 2000/XP. Vous pouvez désactiver la fonctionnalité fantôme en appelant le code suivant au démarrage.

procedure DisableProcessWindowsGhosting; 
var 
    DisableProcessWindowsGhostingProc: procedure; 
begin 
    DisableProcessWindowsGhostingProc := GetProcAddress(
    GetModuleHandle('user32.dll'), 
    'DisableProcessWindowsGhosting'); 
    if Assigned(DisableProcessWindowsGhostingProc) then 
    DisableProcessWindowsGhostingProc; 
end; 

Le seul problème que je vois est que cela causera des problèmes avec la fonction qui permet à l'utilisateur de minimize, move, or close the main window of an application that is not responding. Mais de cette façon, vous n'avez pas à couvrir chaque appel avec le code Self.Enabled := False.

+0

Si ça marche vraiment, ce serait génial. Je vous remercie. Ce problème me dérange depuis très longtemps. Ce qui m'intrigue c'est: "Cependant, si le formulaire avait le style WS_POPUP et que le" propriétaire "était la bonne fenêtre, même un formulaire" fantôme "ne serait pas autorisé à passer l'ordre Z sous son propriétaire, donc il n'y a aucune chance pour un dialogue modal pour disparaître soudainement. Je n'ai vu aucune référence à l'unité Owner in Forms. – LukLed

4

Désolé d'ajouter une réponse séparée, mais j'ai fait un peu plus de recherche, et certains d'entre eux indiquent que ma réponse précédente (DisableProcessWindowsGhosting) n'aide pas. Comme je ne peux pas toujours reproduire ce problème, je ne peux pas le dire avec certitude.

J'ai trouvé une solution qui semble appropriée. J'ai référencé le code dans Delphi 2007 pour la méthode CreateParams et il correspond assez proche (sans avoir tout l'autre code qui gère PopupMode).

J'ai créé l'unité ci-dessous laquelle sous-classes TForm.

unit uModalForms; 

interface 

uses Forms, Controls, Windows; 
type 
    TModalForm = class(TForm) 
    protected 
    procedure CreateParams(var params: TCreateParams); override; 
    end; 

implementation 

procedure TModalForm.CreateParams(var params: TCreateParams); 
begin 
    inherited; 

    params.WndParent := Screen.ActiveForm.Handle; 

    if (params.WndParent <> 0) and (IsIconic(params.WndParent) 
    or not IsWindowVisible(params.WndParent) 
    or not IsWindowEnabled(params.WndParent)) then 
    params.WndParent := 0; 

    if params.WndParent = 0 then 
    params.WndParent := Application.Handle; 
end; 

Ce que je fais alors est inclure cette unité avec une unité de forme, puis changer class(TForm)-class(TModalForm)

classe du formulaire (dans le fichier de code .pas) Il fonctionne pour moi, semble être proche de la solution de CodeGear.

+0

Je vais d'abord essayer avec DisableProcessWindowsGhosting et vérifier si cela fonctionne. Ensuite, je vais regarder ça. Merci. – LukLed

+0

fonctionne parfaitement - merci Jim – tomo7

1

Il suffit de définir la propriété Visible de la forme que vous souhaitez ouvrir modal, à False. Ensuite, vous pouvez l'ouvrir avec .ShowModal(); et cela fonctionnera.

0

essayez- OnShowForm:

+1

6 ans trop tard, mais merci :) – LukLed