【问题标题】:Window class style CS_NOCLOSE does not work after calling to RecreateWnd调用 RecreateWnd 后窗口类样式 CS_NOCLOSE 不起作用
【发布时间】:2017-06-13 12:42:24
【问题描述】:

我需要一个表单来禁用菜单关闭按钮(也禁用 Alt-F4 关闭),所以我使用了CS_NOCLOSE 类样式。如果我在CreateParams 中设置它,它会按预期工作:

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited;  
  Params.WindowClass.style := Params.WindowClass.style or CS_NOCLOSE;
end;

关闭按钮被禁用,您无法使用 ALT+F4 关闭窗口(我有自己的关闭按钮)。

现在我添加了一个标志:FNoCloseButton,最初设置为False

procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited;
  if FNoCloseButton then
    Params.WindowClass.style := Params.WindowClass.style or CS_NOCLOSE;
end;

创建表格后,我有这个:

procedure TForm1.Button1Click(Sender: TObject);
begin
  FNoCloseButton := True;
  RecreateWnd;
end;

点击 Button1 后,窗口重新创建,但 CS_NOCLOSE 现在无效,被忽略。

为什么会有这种行为? Window类style创建后为什么不能更改? (我想我可以,因为SetClassLong api 存在)

我还尝试了SetClassLong

procedure TForm1.Button2Click(Sender: TObject);
begin
  SetClassLong(Self.Handle, GCL_STYLE, GetClassLong(Self.Handle, GCL_STYLE) or CS_NOCLOSE);
  DrawMenuBar(Self.Handle); // Must call this to invalidate
end;

这行得通。关闭被禁用(加上 Alt-F4),但系统菜单项“关闭”是可见的,我可以通过单击它来关闭窗口。所以SetClassLong 的行为有点不同。

我错过了什么?

【问题讨论】:

标签: delphi winapi


【解决方案1】:
procedure TForm1.CreateParams(var Params: TCreateParams);
begin
  inherited;
  if FNoCloseButton then
    Params.WindowClass.style := Params.WindowClass.style or CS_NOCLOSE;
end;

上述代码中修改窗口类信息的那行没有任何作用,因为该类在代码第一次运行时已经注册;当FNoCloseButton 为假时。

调用RecreateWindow 后,VCL 会销毁并创建窗口,但不会尝试重新注册会因ERROR_CLASS_ALREADY_EXISTS 而失败的类。您可能会争辩说,在销毁窗口时不取消注册类是一个设计错误,但事实并非如此。不要忘记,您可以在 VCL 应用程序生命周期的不同时间拥有一个或多个表单类实例。


对于解决方案,如果您可以确保要销毁的窗口是同类窗口中的唯一实例,您可以自己注销该类。然后VCL,查询类信息,发现没有注册,会在创建窗口之前为你注册。否则你必须使用SetClassLong[Ptr],就像你已经在做的那样。

type
  TForm1 = class(TForm)
    ..
  protected
    procedure CreateParams(var Params: TCreateParams); override;
    procedure DestroyHandle; override;
    ...

..

procedure TForm1.DestroyHandle;
begin
  inherited;
  if not winapi.windows.UnregisterClass(PChar(ClassName), HInstance) then
    RaiseLastOSError;
end;

【讨论】:

  • 谢谢!这现在按预期工作。我假设 DestroyWindowHandle 将注销窗口类,所以我什至没有检查源代码。
猜你喜欢
  • 1970-01-01
  • 2020-04-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-17
  • 2012-05-02
相关资源
最近更新 更多