我需要一个表单来禁用菜单关闭按钮(并且还禁用使用 Alt-F4 关闭),因此我使用了 CS_NOCLOSE
类(class)风格。如果我在 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
现在无效并被忽略。
为什么会出现这种行为?为什么在创建窗口类样式后无法更改它? (我认为我可以,因为 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
的行为有点不同。
我错过了什么?
最佳答案
procedure TForm1.CreateParams(var Params: TCreateParams); begin inherited; if FNoCloseButton then Params.WindowClass.style := Params.WindowClass.style or CS_NOCLOSE; end;
上面代码中修改窗口类信息的行没有任何作用,因为该类已经在代码第一次运行时注册;当 FNoCloseButton 为 false 时。
调用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;
关于delphi - 调用 RecreateWnd 后窗口类样式 CS_NOCLOSE 不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44521877/