代码之家  ›  专栏  ›  技术社区  ›  Ian Boyd

如何在Delphi中没有主窗体?

  •  5
  • Ian Boyd  · 技术社区  · 14 年前

    在任务栏上存在窗体之前,VCL有许多问题需要撤消。

    但最后一个问题是最小化VCL指定的 使应用程序中的所有窗口消失。

    Ten years ago, Peter Below (TeamB) documented these problems

    这一切都源于这样一个事实:您在工具栏上看到的按钮并不代表应用程序的窗口;它代表 TApplications MainForm ,然后它被赋予特殊的能力,如果 最小化,然后指示应用程序隐藏自身。

    在我看来,如果我能

    Application.MainForm := nil;
    

    然后所有这些虫子都会消失。应用程序可以有它的隐藏窗口,同时我将覆盖 其他 我的 主窗体,具有:

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

    Application.MainForm 属性是只读的。

    主窗体

    另见

    6 回复  |  直到 7 年前
        1
  •  9
  •   Remy Lebeau    13 年前

    如果没有分配主窗体,则无法运行GUI项目。主消息循环将立即退出而不使用。但是,这并不意味着MainForm必须运行UI。您可以使用空白隐藏的TForm作为指定的主窗体,然后让它将真正的主窗体实例化为辅助TForm。例如:

    project HiddenMainFormApp;
    
    uses
      ..., Forms, HiddenMainForm;
    
    begin
      Application.Initialize;
      Application.CreateForm(THiddenMainForm, MainForm);
      Application.ShowMainForm := False;
      Application.Run;
    end.
    

    HiddenMainForm.cpp:

    uses
      ..., RealMainForm;
    
    procedure THiddenMainForm.FormCreate(Sender: TObject);
    begin
      RealMainForm := TRealMainForm.Create(Self);
      RealMainForm.Show;
    end;
    

    RealMainForm.cpp:

    procedure TRealMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
      Action := caFree;
      Application.Terminate;
    end;
    

    或者:

    project HiddenMainFormApp;
    
    uses
      ..., Forms, HiddenMainForm, RealMainForm;
    
    begin
      Application.Initialize;
      Application.CreateForm(THiddenMainForm, MainForm);
      Application.ShowMainForm := False;
    
      RealMainForm := TRealMainForm.Create(Application);
      RealMainForm.Show;
      RealMainForm.Update;
    
      Application.Run;
    end.
    

    RealMainForm.cpp:

    开始
    作用:=咖啡树;
    结束;
    
        2
  •  5
  •   Ken White    14 年前

    你不能,尤其是在Delphi5中。

    你所说的关于在任务栏上看到的应用程序窗口的引用现在已经有几个Delphi版本不正确了(我相信D2007改变了它)。

    因为您使用的是Delphi5,所以您使用的是Delphi的一个过时副本;当前版本几乎没有您正在编写的内容。我建议您升级到Delphi的更高版本(D5非常老);Delphi 2007如果您需要避免使用Unicode,Delphi XE如果您可以在VCL和RTL中使用(或者不介意)Unicode支持。

    漏洞

        3
  •  3
  •   NGLN Selim Serhat Çelik    13 年前

    在这里,分配Application.MainForm似乎不是在最小化MainForm的同时在任务栏上显示另一个非模式表单的问题。

    项目1.dpr:

    program Project1;
    
    uses
      Forms,
      Windows,
      Unit1 in 'Unit1.pas' {MainForm},
      Unit2 in 'Unit2.pas' {Form2};
    
    {$R *.res}
    
    var
      MainForm: TMainForm;
    
    begin
      Application.Initialize;
      Application.CreateForm(TMainForm, MainForm);
      ShowWindow(Application.Handle, SW_HIDE);
      Application.Run;
    end.
    

    1.pas单元:

    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, Classes, Controls, Forms, StdCtrls, Unit2;
    
    type
      TMainForm = class(TForm)
        ShowForm2Button: TButton;
        ShowForm2ModalButton: TButton;
        procedure ShowForm2ButtonClick(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure ShowForm2ModalButtonClick(Sender: TObject);
      private
        FForm2: TForm2;
        procedure ApplicationActivate(Sender: TObject);
        procedure Form2Close(Sender: TObject; var Action: TCloseAction);
        procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
      protected
        procedure CreateParams(var Params: TCreateParams); override;
      end;
    
    implementation
    
    {$R *.dfm}
    
    procedure TMainForm.FormCreate(Sender: TObject);
    begin
      Visible := True; //Required only for MainForm, can be set designtime
      Application.OnActivate := ApplicationActivate;
    end;
    
    procedure TMainForm.ApplicationActivate(Sender: TObject);
    { Necessary in case of any modal windows dialog or modal Form active }
    var
      TopWindow: HWND;
      I: Integer;
    begin
      TopWindow := 0;
      for I := 0 to Screen.FormCount - 1 do
      begin
        Screen.Forms[I].BringToFront;
        if fsModal in Screen.Forms[I].FormState then
          TopWindow := Screen.Forms[I].Handle;
      end;
      Application.RestoreTopMosts;
      if TopWindow = 0 then
        Application.BringToFront
      else
        SetForegroundWindow(TopWindow);
    end;
    
    procedure TMainForm.CreateParams(var Params: TCreateParams);
    begin
      inherited CreateParams(Params);
      with Params do
      begin
        ExStyle := ExStyle or WS_EX_APPWINDOW;
        WndParent := GetDesktopWindow;
      end;
    end;
    
    procedure TMainForm.WMSysCommand(var Msg: TWMSysCommand);
    begin
      if Msg.CmdType = SC_MINIMIZE then
        ShowWindow(Handle, SW_MINIMIZE)
      else
        inherited;
    end;
    
    { Testing code from here }
    
    procedure TMainForm.ShowForm2ButtonClick(Sender: TObject);
    begin
      if FForm2 = nil then
      begin
        FForm2 := TForm2.Create(Application); //Or: AOwner = nil, or Self
        FForm2.OnClose := Form2Close;
      end;
      ShowWindow(FForm2.Handle, SW_RESTORE);
      FForm2.BringToFront;
    end;
    
    procedure TMainForm.Form2Close(Sender: TObject; var Action: TCloseAction);
    begin
      Action := caFree;
      FForm2 := nil;
    end;
    
    procedure TMainForm.ShowForm2ModalButtonClick(Sender: TObject);
    begin
      with TForm2.Create(nil) do
        try
          ShowModal;
        finally
          Free;
        end;
    end;
    
    end.
    

    unit Unit2;
    
    interface
    
    uses
      Windows, Messages, Classes, Controls, Forms;
    
    type
      TForm2 = class(TForm)
      private
        procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
      protected
        procedure CreateParams(var Params: TCreateParams); override;
      end;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm2.CreateParams(var Params: TCreateParams);
    begin
      inherited CreateParams(Params);
      with Params do
      begin
        ExStyle := ExStyle or WS_EX_APPWINDOW;
        WndParent := GetDesktopWindow;
      end;
    end;
    
    procedure TForm2.WMSysCommand(var Msg: TWMSysCommand);
    begin
      if Msg.CmdType = SC_MINIMIZE then
        ShowWindow(Handle, SW_MINIMIZE)
      else
        inherited;
    end;
    
    end.
    

    (在XP和Win7上使用D5和D7进行测试。)

    (是的,您可以将其标记为不是一个答案,因为它不是:仍然有一个主窗体。但我想这能回答问题背后的问题……)

        4
  •  2
  •   Community CDub    7 年前

    我不能为Delphi5说话,但在Delphi7中,如果你想弄脏你的手,你绝对可以不用主窗体运行。我在另一个答案中谈到了很多细节 here

    由于Delphi 5没有MainFormOnTaskbar属性,您需要在dpr中执行以下操作:

    // Hide application's taskbar entry
    WasVisible := IsWindowVisible(Application.Handle);
    if WasVisible then
      ShowWindow(Application.Handle, SW_HIDE);
    SetWindowLong(Application.Handle, GWL_EXSTYLE,
      GetWindowLong(Application.Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW);
    if WasVisible then
      ShowWindow(Application.Handle, SW_SHOW);
    // Hide the hidden app window window from the Task Manager's
    // "Applications" tab.  Don't change Application.Title since
    // it might get read elsewhere.
    SetWindowText(Application.Handle, '');
    

    创建参数 设置 Params.WndParent := 0 他们每个人都有自己的任务栏条目。Application.MainForm没有被分配,所以最小化重写之类的事情不是问题,但是您必须小心任何假定MainForm有效的代码。

        5
  •  0
  •   Sertac Akyuz    14 年前

    当然,这可能不可行,这取决于表单可能需要做什么。

        6
  •  0
  •   David Heffernan    13 年前

    Windows Features 所有细节。

    问题的关键是所有者的财产,我指的是windows的所有者,而不是VCL的所有者。

    它的所有者被最小化。

    如果希望能够在不隐藏其他窗口的情况下最小化主窗体,则需要了解所属窗口的工作方式。