Form is hidden behind other forms when ShowModal is called

后端 未结 6 1248
攒了一身酷
攒了一身酷 2020-12-04 22:34

My application is based on modal forms. Main form opens one form with ShowModal, this form opens another with ShowModal, so we have stacked modal forms. There is sometimes a

相关标签:
6条回答
  • 2020-12-04 22:45

    You didn't mention which version of Delphi...

    Newer Delphi versions have added two new properties to TCustomForm: PopupMode and PopupParent. Setting PopupParent of your modal dialog to the form that's creating that dialog makes sure that the child form stays on top of it's parent. It usually fixes the problem you're describing.

    I think this pair of properties were added in Delphi 2006, but it may have been 2005. They're definitely there in Delphi 2007 and up.

    EDIT: After seeing you're using Delphi 7, the only suggestion I have is that, in the code that displays your modal form, you disable the form creating it, and re-enable on return. That should prevent the creating window from receiving input, which may help keep the Z-order correct.

    Something like this may work (untested, as I'm no longer using 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;
    

    If Form2 creates a modal window (as you've mentioned), just repeat the process - disable Form2, create Form3 and show it modally, and re-enable Form2 when it returns. Make sure to use try..finally as I've shown, so that if something goes wrong in the modal form the creating form is always re-enabled.

    0 讨论(0)
  • 2020-12-04 22:47

    From this link it appears that the problem is with the "Ghosting window" that was introduced in 2000/XP. You can disable the ghosting feature by calling the following code at startup.

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

    The only issue that I can see is that it will cause problems with the feature that allows for the user to minimize, move, or close the main window of an application that is not responding. But in this way you do not have to cover each call with the Self.Enabled := False code.

    0 讨论(0)
  • 2020-12-04 22:57

    Sorry for adding a separate answer, but I have done a bit more research, and some of it indicates that my previous answer (DisableProcessWindowsGhosting) doesn't help. Since I can't always reproduce this issue, I cannot say for sure.

    I found a solution that appears to appropriate. I referenced the code in Delphi 2007 for the CreateParams method and it matches pretty close (without having all of the other code that handles PopupMode).

    I created the unit below which subclasses 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;
    

    What I do then is include this unit in with a form unit, and then change the form's class (in the .pas code file) from class(TForm) to class(TModalForm)

    It works for me, appears to be close to CodeGear's solution.

    0 讨论(0)
  • 2020-12-04 22:57

    try it OnShowForm:

    PostMessage(Self.Handle, WM_USER_SET_FOCUS_AT_START, 0, 0);
    
    0 讨论(0)
  • 2020-12-04 23:03

    I have found that using the "Always On Top" flag on more than one form causes problems with the Z order. And you may also find the need for the BringWindowToTop function.

    When launching a message box using the built-in WinAPI (MessageBox), I have found that passing the calling window's handle is necessary in order to make sure that the the prompt appears on top all the time.

    0 讨论(0)
  • 2020-12-04 23:12

    Just set the Visible property of the form, that you want to open modal, to False. Then you can open it with .ShowModal(); and it will work.

    0 讨论(0)
提交回复
热议问题