2010-08-04 8 views
2

J'ai un formulaire (TBigForm dans l'exemple ci-dessous) qui permet de manipuler certaines données complexes et nécessite des informations supplémentaires à afficher. J'ai mis cette information dans un formulaire de fsStayOnTop (OnTopForm dans l'exemple) pour s'assurer qu'il est toujours visible mais peut être déplacé si nécessaire. Maintenant, quand une action de l'utilisateur dans TBigForm montre une forme modale, elle est souvent cachée derrière OnTopForm ce qui rend l'application figée. Comment puis-je éviter ça? (La recherche rapporte beaucoup, mais je n'ai pas pu en distiller une solution.)Formes modales cachées par les formulaires fsStayOnTop

Dans ma vraie application il y a beaucoup d'endroits où les formes modales sont montrées, ainsi je voudrais éviter de changer tout. de ces appels.

Exemple: Créer une nouvelle application VCL, déposez un TButton sur Form1, double-cliquez sur le bouton et remplacer le talon de mise en œuvre Button1Click générée avec les éléments suivants:

type 
    TBigForm = class(TForm) 
    strict private 
    OnTopForm: TForm; 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    protected 
    procedure DoHide; override; 
    procedure DoShow; override; 
    public 
    constructor Create(AOwner: TComponent); override; 
    end; 

{ TBigForm } 

procedure TBigForm.Button1Click(Sender: TObject); 
begin 
    ShowMessage('Test'); 
end; 

constructor TBigForm.Create(AOwner: TComponent); 
begin 
    inherited CreateNew(AOwner); 

    Caption := 'Big form'; 
    WindowState := wsMaximized; 

    Button1 := TButton.Create(Self); 
    Button1.Parent := Self; 
    Button1.Caption := 'Freeze!'; 
    Button1.SetBounds(10, 10, 100, 100); 
    Button1.OnClick := Button1Click; 
end; 

procedure TBigForm.DoHide; 
begin 
    OnTopForm.Free; 
    inherited DoHide; 
end; 

procedure TBigForm.DoShow; 
begin 
    inherited DoShow; 
    OnTopForm := TForm.Create(Self); 
    OnTopForm.Caption := 'Important information'; 
    OnTopForm.BorderStyle := bsToolWindow; 
    OnTopForm.FormStyle := fsStayOnTop; 
    OnTopForm.Position := poScreenCenter; 
    OnTopForm.Show; 
end; 

{ TForm1 } 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    f: TBigForm; 
begin 
    f := TBigForm.Create(nil); 
    try 
    f.ShowModal; 
    finally 
    f.Free; 
    end; 
end; 

Démarrez l'application, cliquez sur " Button1 "puis sur" Freeze! ".

(BTW: Nous utilisons D2007.)

+0

C'est marrant - après 3,5 ans de downvote de rien, sans aucun commentaire. –

+0

Voici un upvote pour compenser le downvote. – Shannon

+0

@Shannon, merci! :-) –

Répondre

1

modifier temporairement le FormStyle de votre OnTopform avant d'afficher un autre formulaire comme Modal:

procedure TBigForm.Button1Click(Sender: TObject); 
begin 
    OnTopForm.FormStyle := fsNormal; 
    ShowMessage('Test'); 
    OnTopForm.FormStyle := fsStayOnTop; 
end; 

Il devrait travailler à ce que vous voulez ...

+0

Merci! Cela semble fonctionner, mais cela nécessite de manipuler chaque appel à ShowModal, ShowMessage etc. - Je voudrais éviter cela. Utiliser Application.OnModalBegin n'aide pas ici car il n'est appelé qu'une seule fois si vous imbriquez des appels ShowModal. :-( –

2

Essayez de définir la propriété PopupParent du formulaire modal comme étant le formulaire StayOnTop ou définissez la propriété Application.ModalPopupMode sur autre chose que pmNone avant d'appeler ShowModal().

+0

Le premier changerait la hiérarchie de fenêtre de l'application - le formulaire StayOnTop resterait sous la forme modale et ce dernier ne serait pas utile puisque 'ShowMessage' est appelé à partir du formulaire modal, mais le formulaire StayOnTop est un –

+0

Vous ne pouvez pas avoir les deux sens, vous dites que le problème est que la fenêtre modale est bloquée derrière la fenêtre de StayOnTop, alors il est évident que la fenêtre modale doit être affichée dessus. , il suffit de déplacer la fenêtre modale vers une zone en dehors de la fenêtre StayOnTop avant d'appeler ShowModal(). Comme pour ShowMessage(), elle affiche une TForm modale et, en tant que telle, est soumise à la propriété TApplication.ModalPopupMode –

+0

Comme je le vois, le problème n'est pas que la forme modale soit bloquée sous le formulaire StayOnTop, c'est que le formulaire ShowMessage est bloqué sous le formulaire StayOnTop. Et puisque le ShowMessage est appelé depuis le formulaire Modal nd ** not ** du formulaire StayOnTop, il ne sera pas détenu par le formulaire StayOnTop .. avec tout ModalPopupMode ... –

0

Voici votre Goody

Create an global TApplicationEvents 
Declare an global var to keep track of modal form count 
Hookup the OnMessage 

var 
    Ctrl: TControl; 

if Msg.hwnd <> 0 then 
    case Msg.message of 
    CM_ACTIVATE, 
    CM_DEACTIVATE: 
    begin 
     Ctrl := FindControl(Msg.hwnd); 
     if Ctrl is TForm then 
     if fsModal in TForm(Ctrl).FormState then 
     begin 
      if Msg.message = CM_ACTIVATE then 
      Inc(Modal form count var) 
      else 
      Dec(Modal form count var); 

      add more logic based on Modal form count var 
     end; 
    end; 
    end; 

Amusez-vous

+0

Je ne peux pas appeler les lignes Inc/Dec - Ctrl est toujours nul. Avez-vous essayé ceci dans mon exemple d'application? –

0
procedure TForm1.ScreenOnActiveFormChange(Sender: TObject); 
begin 
    if (Screen.ActiveForm <> nil) then 
    begin 
    if (Screen.ActiveForm.Handle <> Application.MainForm.Handle) then 
     with Screen.ActiveForm do 
     SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE); 
    Windows.SetForeGroundWindow(Screen.ActiveForm.Handle); 
    end; 
end; 

Cela devrait fonctionner.