Delphi在应用程序运行时更改主窗体

Sha*_*elt 10 forms delphi vcl taskbar delphi-xe6

我有这个问题.当我隐藏我的主窗体时,我的应用程序的任务栏图标也被隐藏.我也看到了一个关于这个问题的新问题,答案并没有真正帮助.他们建议尽量减少它,但我不想最小化应用程序.

应用程序运行时是否可以更改主窗体?

例如.我有两种形式.当我想隐藏一个表单并显示另一个表单时,任务栏图标应保留在任务栏上,主表单应切换到另一个表单.

我使用的是Delphi XE6,它是一个VCL Forms应用程序.

我还看到了一个关于在运行时更改主窗体的一个不同的老问题,但它很老,仍然基于Delphi 6.

Dav*_*nan 7

应用程序运行时是否可以更改主窗体?

程序运行时无法更改VCL主窗体.程序启动时,此属性一劳永逸地确定.

一种可行的方法是安排辅助表单,即非主表单的表单,在任务栏上有一个按钮.通过使其无主,或使用WS_EX_APPWINDOW扩展窗口样式来做到这一点.

更新

好吧,你可以改变Application.MainForm,但它需要你破坏当前的主窗体,然后创建一个新窗体.

  • @linluk这显然是一个严重的黑客攻击.有什么后果? (3认同)
  • @DavidHeffernan 我认为可以更改主窗体。我知道它,因为我在我的一个应用程序中使用它。我这样做是这样的:“Pointer((@Application.MainForm)^) := Form2;”并且工作正常。我可以关闭旧的主窗体而不关闭应用程序,当我关闭新的主窗体时,应用程序将按预期终止。 (2认同)

Sil*_*ior 6

正如 David Heffernan 已经说过的那样,不可能更改已运行的应用程序的主窗体。这是windows本身的限制。

你能做的就是作弊,永远不会真正改变主窗体,而只是让它看起来像你所做的那样。
你如何实现这一目标?

第 1 步:向第二个窗体添加代码以制作自己的任务栏按钮

procedure TWorkForm.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
end;
Run Code Online (Sandbox Code Playgroud)

步骤 2:在切换到第二个表单之前动态创建它。创建后,先前添加的代码将为您的第二个表单创建一个新的任务栏按钮。

第 3 步:现在隐藏实际的主窗体。隐藏它也会隐藏属于它的任务栏按钮。因此,您最终仍然会显示一个任务栏按钮,并且它是属于您的第二个表单的按钮。

步骤 4:为了允许您的第二个表单在关闭时终止您的应用程序,请从第二个表单 OnClose 或 OnFormCloseQuery 事件中调用真正主表单的 Close 方法。
如果您希望能够切换回真正的主窗体,请调用主窗体的 Show 方法而不是 Close 方法。

这种方法允许我们非常快速地交换表单,因此只有最敏锐的用户才会注意到任务栏按钮的简短动画。
注意:如果您的第二个 for 是一个复杂的,并且因此需要一些时间来创建,您可能希望将其创建为隐藏,然后在其创建过程完成后显示它并进行交换。否则,您最终可能会同时显示两个任务栏按钮,我相信您想避免这种情况。

这是一个简短的示例:
- LoginForm 是在应用程序启动时创建的真正的主表单 - WorkForm 是用户登录后将花费大部分时间的表单,并且此表单是在登录过程中创建的

登录表单代码:

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.
Run Code Online (Sandbox Code Playgroud)

工作表格代码:

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.
Run Code Online (Sandbox Code Playgroud)

  • - *“这是Windows本身的限制。”* - Windows不关心你是否有主窗体。它甚至没有主形式的概念。 (3认同)
  • 切勿将窗口所有者设置为桌面。http://blogs.msdn.com/b/oldnewthing/archive/2004/02/24/79212.aspx (2认同)

Rem*_*eau 5

Application.MainForm一旦分配,就无法更改。但是,您也不需要。这个问题最简单的解决方案是创建一个空白隐藏TForm作为真实 Application.MainForm并让它正常管理任务栏,然后您可以TForm在需要时显示/隐藏任何辅助对象,其中您想要的“MainForm”是辅助表单而不是真实的MainForm