Delphi Change main form while application is running

后端 未结 8 1733
无人及你
无人及你 2020-12-03 06:07

I have this problem. When I hide my main form, then the taskbar icon of my application is also hidden. I saw a new question about this problem as well and the answers didn\'

相关标签:
8条回答
  • 2020-12-03 06:23

    In the current Delphi implementation, I am sure that there are no consequences using a pointer to change Application.MainForm.

    If you look into TApplication class, you can see that FMainForm is used only to check if the application has at least one form, and iterates the main loop inside the TApplication.Run method while the FMainForm exists. If you do not want to use a pointer to hack this property, you can implement your own TApplication class, like TMyApplication, copy all the routines inside it and define MainForm property to read and write

    0 讨论(0)
  • 2020-12-03 06:26

    It is not possible to change the Application.MainForm once it has been assigned. However, you do not need to, either. The simpliest solution to this issue would be to create a blank hidden TForm to act as the real Application.MainForm and let it manage the taskbar normally, and then you can show/hide any secondary TForm objects when needed, where your desired "MainForm" is a secondary form not the real MainForm.

    0 讨论(0)
  • 2020-12-03 06:35

    As David Heffernan already said it is not possible to change the Main Form of an already running application. This is the limitation of the windows itself.

    What you can do is cheat and never actually change the Main Form but only make it look like you did.
    How do you achieve that?

    Step 1: Add code to the second Form to make its own Taskbar button

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

    Step 2: Dynamically create the second Form just before switching to it. Upon its creation previously added code will create a new Taskbar button for your second form.

    Step 3: Now hide you actual Main Form. Hiding it will also hide the Taskbar button belonging to it. So you end up still having one Taskbar button shown and it is the one belonging to your second Form.

    Step 4: In order to allow your second Form to terminate your application at its closure call Close method of your true Main Form from your second Forms OnClose or OnFormCloseQuery event.
    If you wanna be able to switch back to your true Main Form call Show method of your Main Form instead of Close method.

    This approach allows us of swapping forms pretty quickly so only most keen users will notice short animation of Taskbar button.
    NOTE: If your second for is a complex one and because of that takes some time to create you might wanna create it hidden and then once its creation process is finished show it and do the swap. Otherwise you might end up with two Taskbar buttons being shown at same time which I believe you wanna avoid.

    Here is a short example:
    - LoginForm is a true Main Form that is created at the application startup - WorkForm is the Form on which user will spend most of time after logging in and this one is created in login process

    Login Form code:

    unit ULoginForm;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
    
    type
      TLoginForm = class(TForm)
        BLogIn: TButton;
        procedure BLogInClick(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      LoginForm: TLoginForm;
    
      //Global variable to tell us if we are only logging out or closing our program
      LoggingOut: Boolean;
    
    implementation
    
    uses Unit2;
    
    {$R *.dfm}
    
    procedure TLoginForm.BLogInClick(Sender: TObject);
    begin
      //Create second Form
      Application.CreateForm(TWorkForm, WorkForm);
      //Hide Main Form
      Self.Hide;
      //Don't forget to clear login fields
    end;
    
    end.
    

    Work form code:

    unit UWorkForm;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
    
    type
      TWorkForm = class(TForm)
        BLogOut: TButton;
        //Used in overriding forms creating parameters so we can add its own Taskbar button
        procedure CreateParams(var Params: TCreateParams); override;
        procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
        procedure BLogOutClick(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
    var
      WorkForm: TWorkForm;
    
    implementation
    
    uses Unit1;
    
    {$R *.dfm}
    
    procedure TWorkForm.BLogOutClick(Sender: TObject);
    begin
      //Set to true so we know we are in the process of simply logging out
      LoggingOut := True;
      //Call close method to begin closing the current Form
      Close;
    end;
    
    procedure TWorkForm.CreateParams(var Params: TCreateParams);
    begin
      inherited;
      Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
    end;
    
    procedure TWorkForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    begin
      //Check to see if we are in the process of simply logging out
      if not LoggingOut then
      begin
        //If we are not in the process of logging out close the Main Form
        LoginForm.Close;
        //and then allow closing of current form
        CanClose := True;
      end
      else
      begin
        //But if we are in the process of simply logging out show the Main Form
        LoginForm.Show;
        //Reset the LoggingOut to false
        LoggingOut := False;
        //and then alow closing of current form
        CanClose := True;
      end;
    end;
    
    end.
    
    0 讨论(0)
  • 2020-12-03 06:38

    Is it possible to change the main form while the application is already running?

    It is not possible to change the VCL main form whilst the program is running. This property is determined once and for all when the program starts.

    One possible way to proceed for you is to arrange for the secondary form, the form that is not the main form, to have a button on the taskbar. Do that by making it unowned, or by using the WS_EX_APPWINDOW extended window style.

    Update

    Well, you can change Application.MainForm, but it requires you to destroy the current main form, and then create a new one.

    0 讨论(0)
  • 2020-12-03 06:38

    I implemented this in the same way @DavidHeffernan had already suggested and as yet have not come across any issues, it might not be the best way but it worked for me and what i was trying to achieve, which was have "normal" feeling behaviour when the user minimised their MainWork form.

    Code looked similar to this:

    procedure TfrmLogin.btnLoginClick(Sender: TObject);
    begin
        frmMainWork := TfrmMain.Create(Application);
        try
            Pointer((@Application.MainForm)^) := frmMainWork;
            frmLogin.Hide;
            frmMainWork.ShowModal;
        finally
            Pointer((@Application.MainForm)^) := frmLogin;
            frmLogin.Show;
            FreeAndNil(frmMainWork);
        end;
    
    end;
    

    hope this helps :-)

    0 讨论(0)
  • 2020-12-03 06:39

    If you set Application.MainFormOnTaskbar to false in your startup routine (in the .dpr file), then the VCL will create a hidden form whose sole purpose is to provide the taskbar icon. This is an older approach and is generally not recommended, but as long as other windows are visible, it would let you hide your main form without the application disappearing from the taskbar.

    You can also provide an Application.OnGetMainFormHandle event handler to change your Application.MainFormHandle at runtime (but not Application.MainForm). MainFormHandle affects stuff like the owner of modal popup dialogs.

    More information on Application.MainFormOnTaskbar and the disadvantages of disabling it: This gets complicated in a hurry. The short version is in the VCL docs, which explain that several of Windows' newer features (like live taskbar thumbnails) that were introduced in Vista require MainFormOnTaskbar := True. There's a lot more background reading in this SO discussion.

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