Multiple app windows activation not working correctly

后端 未结 3 1368
夕颜
夕颜 2021-02-11 01:39

I have a Delphi application that has a document browser as the main form. When the user opens a document, we open an editor window. We want to have each editor with a button on

相关标签:
3条回答
  • 2021-02-11 02:25

    Sorry if this is really stupid, but you don't have the formstyle set to fsStayOnTop do you? This would explain this behaviour.

    0 讨论(0)
  • 2021-02-11 02:29

    perhaps add this in the createparams

    Params.ExStyle := Params.ExStyle OR WS_EX_APPWINDOW;
    

    or try this anywhere in the code. I presonally use it on the forms .OnCreate event.

    SetWindowLong(Wnd, GWL_EXSTYLE, 
      GetWindowLong(Wnd, GWL_EXSTYLE) or WS_EX_APPWINDOW) ;
    

    the downside of this is that if the main form is minimized the other forms hide aswell, but restore when the main form does.

    0 讨论(0)
  • 2021-02-11 02:31

    My application works in the way you describe. Here is the approach I took. I would have liked to find a simpler approach but never did.

    I started out by reading these articles. This first one is an great write up by Peter Below:

    http://groups-beta.google.com/group/borland.public.delphi.winapi/msg/e9f75ff48ce960eb?hl=en

    Other information was also found here, however this did not prove to be a valid solution: for my use: http://blogs.teamb.com/DeepakShenoy/archive/2005/04/26/4050.aspx

    Eventually here is what I ended up with.

    My splash screen doubles as the Application Main form. The Main form has a special tie to the Application Object. Using all secondary forms gets me the behavior that I was looking for.

    In each form that I want on the task bar I override CreateParams. I do this on my edit forms and what the users sees as the "main form"

    procedure TUaarSalesMain.CreateParams(var Params: TCreateParams);
    begin
      inherited CreateParams(Params);
      Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
      Params.WndParent := GetDesktopWindow;
    end;
    

    My "Main" form as far as Delphi is concerned loads the true main form in its Activitate function. I use a member variable to keep track of the first activate. Then at the end of the function I hide the splash form, but do not close it. This was important for me because if the user was editing a document and closed the main form I did not want the edit screens to be forced closed at the same time. This way all of the visible forms are treated the same.

        if FFirstActivate = false then
          exit;
    
        FFristActivate := false;
    
        /* 
           Main Load code here 
           Update Splash label, repaint
           Application.CreateForm
           etc.
        */
    
    
        // I can't change visible here but I can change the size of the window
        Self.Height := 0;
        Self.Width := 0;
        Self.Enabled := false;
    
        //  It is tempting to set Self.Visible := false here but that is not
        // possible because you can't change the Visible status inside this
        // function.  So we need to send a message instead.
        ShowWindow(Self.Handle, SW_HIDE);
    
      end;
    

    But there is still a problem. You need the main/splash window to close when all other forms are closed. I have an extra check in my close routines for Parent <> nil because I use forms as plugins (form my purposes they work better than frames).

    I didn't really like using the Idle event, but I don't notice this being a drag on the CPU.

    {
      TApplicationManager.ApplicationEventsIdle
      ---------------------------------------------------------------------------
    }
    procedure TApplicationManager.ApplicationEventsIdle(Sender: TObject;
      var Done: Boolean);
    begin
    
      if Screen.FormCount < 2 then
        Close;
    end;
    
    {
      TApplicationManager.FormCloseQuery
      ---------------------------------------------------------------------------
    }
    procedure TApplicationManager.FormCloseQuery(Sender: TObject;
      var CanClose: Boolean);
    var
      i: integer;
    begin
    
      for i := 0 to Screen.FormCount - 1 do
      begin
        if Screen.Forms[i] <> self then
        begin
          // Forms that have a parent will be cleaned up by that parent so
          // ignore them here and only attempt to close the parent forms
          if Screen.Forms[i].Parent = nil then
          begin
            if Screen.Forms[i].CloseQuery = false then
            begin
              CanClose := false;
              break;
            end;
          end;
        end;
      end;
    
    end;
    
    {
      TApplicationManager.FormClose
      ---------------------------------------------------------------------------
    }
    procedure TApplicationManager.FormClose(Sender: TObject;
      var Action: TCloseAction);
    var
      i: integer;
    begin
    
      for i := Screen.FormCount - 1 downto 0 do
      begin
        if Screen.Forms[i] <> self then
        begin
          // Forms that have a parent will be cleaned up by that parent so
          // ignore them here and only attempt to close the parent forms
          if Screen.Forms[i].Parent = nil then
          begin
            Screen.Forms[i].Close;
          end;
        end;
      end;
    
    end;
    

    This has served me well so far. I did make a small change for Vista because the icon for my "Main/Splash" screen was still showing. I don't remember what that was though. I probably don't need to set width, height, enabled, and send the hide message on the splash screen. I just wanted to make sure it didn't show up :-).

    Dealing with the close events was necessary. If I remember correctly that was needed for when windows sent a shutdown message. I think only the main form gets that message.

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