正如David Heffernan所说,不可能更改已运行应用程序的主窗体。这是Windows本身的限制。
你可以欺骗系统,实际上并没有更改主窗体,只是让它看起来像是更改了。
如何实现呢?
步骤1:在第二个窗体中添加代码以创建自己的任务栏按钮。
procedure TWorkForm.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
end;
步骤2:在切换到第二个表单之前动态创建第二个表单。在其创建时,先前添加的代码将为您的第二个表单创建一个新的任务栏按钮。
步骤3:现在隐藏您实际的主表单。隐藏它也会隐藏属于它的任务栏按钮。因此,您最终仍然只有一个任务栏按钮显示出来,即属于您的第二个表单的任务栏按钮。
步骤4:为了允许您的第二个表单在关闭时终止应用程序,请从第二个表单的OnClose或OnFormCloseQuery事件中调用真正的主表单的Close方法。
如果您想能够切换回真正的主表单,请使用Main Form的Show方法而不是Close方法。
这种方法允许我们快速交换表单,因此只有最敏锐的用户会注意到任务栏按钮的短动画。
注意:如果您的第二个表单比较复杂,因此需要一些时间来创建,则可能希望将其隐藏并在创建过程完成后显示它并进行交换。否则,您可能会同时出现两个任务栏按钮,我相信您希望避免这种情况。
这里是一个简短的例子:
- LoginForm是一个真正的主表单,它在应用程序启动时创建
- WorkForm是用户在登录过程中花费大部分时间的表单,这个表单是在登录过程中创建的
Login Form代码:
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
public
end;
var
LoginForm: TLoginForm;
LoggingOut: Boolean;
implementation
uses Unit2;
{$R *.dfm}
procedure TLoginForm.BLogInClick(Sender: TObject);
begin
Application.CreateForm(TWorkForm, WorkForm);
Self.Hide;
end;
end.
从代码中工作:
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;
procedure CreateParams(var Params: TCreateParams); override;
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure BLogOutClick(Sender: TObject);
private
public
end;
var
WorkForm: TWorkForm;
implementation
uses Unit1;
{$R *.dfm}
procedure TWorkForm.BLogOutClick(Sender: TObject);
begin
LoggingOut := True;
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
if not LoggingOut then
begin
LoginForm.Close;
CanClose := True;
end
else
begin
LoginForm.Show;
LoggingOut := False;
CanClose := True;
end;
end;
end.
Pointer((@Application.MainForm)^) := Form2;
来更改主窗体。 - linlukMainForm
是一个属性,而不是变量。你不能获取属性的地址,所以实际上你获取的是属性返回的指针的地址。然后你修改了那个指针指向不同的对象,你并没有修改TApplication
内部的指针。 - Remy LebeauTApplication
内部的指针,因为MainForm
直接读取了FMainForm
。该语句成功地写入了FMainForm
。 - Sertac AkyuzPointer((@Application.MainForm)^) := Form2;
应该与Tmp := Application.MainForm; Pointer((@Tmp)^) := Form2;
相同 - 修改临时变量,而不是TApplication.FMainForm
字段。你所说的唯一可能是编译器优化了属性读取,因此代码变成了Pointer((@Application.FMainForm)^) := Form2;
。 - Remy Lebeau