Le formulaire est caché derrière d'autres formulaires lorsque ShowModal est appelé
Question
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 empilé des formulaires modaux. Il arrive parfois que lorsque nous appelons ShowModal sous une nouvelle forme, celui-ci se cache derrière les formulaires précédents, au lieu de s'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é?
MODIFIER :
J'utilise Delphi 7.
La solution
Vous n'avez pas mentionné quelle version de Delphi ...
Les versions les plus récentes de 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 garantit que le formulaire enfant reste au-dessus de son parent. Cela résout généralement le problème que vous décrivez.
Je pense que cette paire de propriétés a été ajoutée à Delphi 2006, mais c'était peut-être en 2005. Elles sont définitivement présentes dans Delphi 2007 et les versions ultérieures.
EDIT: Après avoir constaté que vous utilisiez Delphi 7, la seule suggestion que je puisse vous donner est la suivante: dans le code qui affiche votre formulaire modal, vous désactivez le formulaire le créant et réactivez-le à son retour. Cela devrait empêcher la fenêtre de création de recevoir des entrées, ce qui peut aider à maintenir l'ordre Z correct.
Quelque chose comme cela pourrait fonctionner (non testé, car je n'utilise plus de 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é), répétez simplement le processus: désactivez Form2, créez Form3 et affichez-le sous forme modale, puis réactivez Form2 à son retour. Assurez-vous d’utiliser try..finally comme je l’ai montré, afin que, en cas de problème avec le formulaire modal, le formulaire de création soit toujours réactivé.
Autres conseils
Désolé d’ajouter une réponse distincte, mais j’ai fait un peu plus de recherches et certaines d’entre elles indiquent que ma réponse précédente (DisableProcessWindowsGhosting) n’aide en rien. 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 bien (sans avoir tout le code qui gère PopupMode).
J'ai créé l'unité au-dessous des 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 d'inclure cette unité dans une unité de formulaire, puis de changer la classe du formulaire (dans le fichier de code .pas) de classe (TForm)
en classe (TModalForm )
Cela fonctionne pour moi, semble être proche de la solution CodeGear.
De ce lien , il semble que le problème soit lié à la " Fenêtre fantôme " cela a été introduit en 2000 / XP. Vous pouvez désactiver cette fonctionnalité 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 fonctionnalité qui permet à l'utilisateur de minimiser, déplacer ou fermer la fenêtre principale d'une application qui ne répond pas . De cette manière, vous ne devez pas couvrir chaque appel avec le code Self.Enabled: = False
.
Définissez simplement la propriété Visible
du formulaire que vous souhaitez ouvrir en mode modal sur False
. Ensuite, vous pouvez l'ouvrir avec .ShowModal ();
et cela fonctionnera.
l'essayer OnShowForm:
PostMessage(Self.Handle, WM_USER_SET_FOCUS_AT_START, 0, 0);
J'ai constaté que l'utilisation de l'option "Toujours au premier plan" drapeau sur plus d'une forme provoque des problèmes avec l'ordre Z. Et vous pouvez également trouver le besoin de Fonction BringWindowToTop
.
Lors du lancement d'une boîte de message à l'aide de l'interface WinAPI intégrée ( MessageBox
), j'ai constaté qu'il était nécessaire de passer le handle de la fenêtre appelante pour s'assurer que l'invite apparaît en haut de tous les temps.