2017-06-13 26 views
4

我需要一个窗体来禁用菜单关闭按钮(并禁用Alt-F4关闭),因此我使用了CS_NOCLOSE类风格。它能正常工作,如果我在CreateParams设置:窗口类风格CS_NOCLOSE在调用RecreateWnd后不起作用

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的行为有点不同。

我错过了什么?

+2

参见[如何启用和禁用最小化,最大化,并在我的标题栏关闭按钮?](https://blogs.msdn.microsoft.com/oldnewthing/20100604-00/?p= 13803 /)和[修改CS_NOCLOSE样式确实会影响该类的所有窗口,但不一定会立即以明显的方式](https://blogs.msdn.microsoft.com/oldnewthing/20150305-00/?p=44533) 。 – IInspectable

+0

@IInspectable,谢谢。我会研究它。 – kobik

+1

我不明白的是为什么'RecreateWnd'调用'DestroyWindow'(并重新创建它)不会使用'CS_NOCLOSE'。 – kobik

回答

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; 
+0

谢谢!现在按预期工作。我*假设* DestroyWindowHandle将取消注册窗口类,所以我甚至没有检查源代码。 – kobik