我需要一个表单来禁用菜单关闭按钮(并且还禁用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类样式? (我想我可以,因为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
的行为有点不同。
我错过了什么?
答案 0 :(得分:2)
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;