You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

显示StayOnTop特性的第二个表单后,Delphi主表单无法重复最小化问题

Delphi主窗体Form1显示Form2后无法重复最小化的解决方案

问题现象

  • 主窗体Form1初始状态下,通过任务栏或边框按钮的最小化/恢复功能正常
  • 显示具备StayOnTop特性的Form2后,Form1仅能成功最小化一次,恢复后再次点击最小化按钮无任何响应
  • Form1未冻结(已通过TMemo控件验证)
  • 需求:必须保留Form2的StayOnTop特性

原代码

Unit1

type
  TForm1 = class(TForm)
    Button1: TButton;
    ApplicationEvents1: TApplicationEvents;
    Memo1: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure ApplicationEvents1Minimize(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.ApplicationEvents1Minimize(Sender: TObject);
begin
  //ShowWindow(Form1.Handle, SW_MINIMIZE);
  //SendMessage(Form1.Handle, WM_SYSCOMMAND, SC_MINIMIZE, 0);
  If Form2.Visible then SendMessage(Form2.Handle, WM_SYSCOMMAND, SC_RESTORE, 0);   // for keeping Form2 not going to be minimize
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  Form2.Show;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  //
end;

Unit2

type
  TForm2 = class(TForm)
    procedure FormActivate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    Function Application_Hook(var Message: TMessage): Boolean;
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

function TForm2.Application_Hook(var Message: TMessage): Boolean;
begin
  Result := Message.Msg = WM_ACTIVATEAPP;
  if Result then
  begin
    Message.Result := 0;
    if TWMActivateApp(Message).Active then PostMessage(Application.Handle, CM_ACTIVATE, 0, 0)
                                      else PostMessage(Application.Handle, CM_DEACTIVATE, 0, 0);
  end;
end;

procedure TForm2.FormActivate(Sender: TObject);
begin
  // Functionality for Stay On Top
  SetWindowPos(Form2.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or  SWP_NOSIZE or SWP_NOACTIVATE);
  SetWindowLong(Form2.Handle, GWL_EXSTYLE, GetWindowLong(Form2.Handle, GWL_EXSTYLE) OR WS_EX_TOPMOST);
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  Application.HookMainWindow(Application_Hook);
end;

procedure TForm2.FormDestroy(Sender: TObject);
begin
  Application.UnhookMainWindow(Application_Hook);
end;

问题根源

  1. Form2的消息拦截逻辑错误:Application_Hook方法中拦截WM_ACTIVATEAPP后返回Result := True,直接终止了消息的后续处理,导致Delphi应用框架无法正确维护应用激活状态,进而破坏了主窗体的最小化状态管理。
  2. Form1的多余消息发送:ApplicationEvents1Minimize中给Form2发送SC_RESTORE的操作,干扰了系统对窗体状态的正常维护。

修复方案

1. 修改Unit1的ApplicationEvents1Minimize方法

移除给Form2发送SC_RESTORE的代码,TopMost窗体的显示状态由系统自动维护,无需手动干预:

procedure TForm1.ApplicationEvents1Minimize(Sender: TObject);
begin
  // 移除原有干扰代码
end;

2. 修改Unit2的Application_Hook方法

将Result设为False,允许WM_ACTIVATEAPP消息继续传递给应用主消息循环,保证框架能正确处理激活状态:

function TForm2.Application_Hook(var Message: TMessage): Boolean;
begin
  Result := False; // 不拦截消息,允许后续处理
  if Message.Msg = WM_ACTIVATEAPP then
  begin
    if TWMActivateApp(Message).Active then 
      PostMessage(Application.Handle, CM_ACTIVATE, 0, 0)
    else 
      PostMessage(Application.Handle, CM_DEACTIVATE, 0, 0);
  end;
end;

3. 优化Form2的StayOnTop设置(可选)

简化FormActivate中的TopMost设置,调用SetWindowPos即可完成TopMost设置,无需额外修改窗口扩展样式:

procedure TForm2.FormActivate(Sender: TObject);
begin
  SetWindowPos(Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE);
end;

验证效果

完成修改后:

  • Form1显示Form2后,可正常重复执行最小化/恢复操作
  • Form2的StayOnTop特性完全保留
  • Form1的所有功能保持正常

内容的提问来源于stack exchange,提问作者Mahir Dostalizadeh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 11:29:52