2017-06-13 25 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