2010-08-20 103 views
14

我做了一個TForm衍生物,它的作用類似於組合,提示窗口或彈出式菜單的下拉部分 - 一種臨時性的東西。它沒有標題 - 它的BorderStyle設置爲bsNone。該表單使用Show非模態顯示,並已設置其位置。帶投影的無邊界TForm

爲了讓它脫穎而出,它的邊框周圍需要陰影。但是,將其邊框設置爲bsNone的結果是投影消失。

各種谷歌來源建議的這種變化:

procedure TdlgEditServiceTask.CreateParams(var Params: TCreateParams); 
const 
    CS_DROPSHADOW = $00020000; 
begin 
    inherited; 
    { Enable drop shadow effect on Windows XP and later } 
    if (Win32Platform = VER_PLATFORM_WIN32_NT) and 
    ((Win32MajorVersion > 5) or 
     ((Win32MajorVersion = 5) and (Win32MinorVersion >= 1))) then 
    Params.WindowClass.Style := Params.WindowClass.Style or 
      CS_DROPSHADOW; 
end; 

,但它不工作 - 不顯示陰影(除非我還設置有WS_THICKFRAME集,這看起來可怕可調整大小的邊框)。這是一個彈出窗口,而不是一個子窗口,所以我不明白它爲什麼會失敗。

請提出建議?

注意:這是一個與this問題類似的問題,該問題仍未得到解答。

NB2:有一個不起眼的VCL組件,名爲TShadowWindow,看起來它會做正確的事情,但結果太粗糙,寫得很實用。

更新:繼Andreas的評論如下,我進一步調查了這一點,並發現了一些細微之處。

在Windows 7下,我發現如果彈出窗口位於同一應用程序的另一窗口上,則不會出現陰影。

這是一個簡單的Delphi應用程序,它在彈出窗口上使用CreateParams來請求如上所述的陰影。

Windows 7 with shadow only over desktop

查看陰影如何出現的地方超出主窗口?

但我想使用無邊界窗口作爲主窗口上的彈出窗口。下拉陰影區分彈出窗口和下面的窗口。我上面的所有描述都是指這種情況。顯然有些Windows機制在這裏干擾。

我也在Windows XP下試過同樣的應用程序。這是它的外觀。

Same application under XP

這正確的陰影作品無處不在*。爾加!就像安德烈亞斯所說的那樣,它似乎是Vista/W7的東西。

(*此文字和screendump的早期版本提出,沒有陰影出現了。然而,這竟然是因爲我有Windows XP的顯示選項「陰影下的菜單」關閉。咄。)

+0

我不充分了解你想要你的窗戶。您不希望它像RAD Studio IDE中的Code Insight彈出窗口(它有一個可調整大小的邊框),是嗎? – 2010-08-20 10:52:33

+0

@安德里亞斯:正確。我不想要一個可調整大小的邊框 - 這是我可以通過設置問題中提到的WS_THICKFRAME得到的。我希望它的邊框看起來像菜單,即帶陰影的單條細線。 實際上,現在你提到它,我注意到Code Insight根據上下文顯示至少三種不同類型的窗口。我想成爲那些沒有可調整大小的邊界的人! :-) – willw 2010-08-20 11:44:46

回答

6

發現這裏是證明:

alt text

正如你所看到的,陰影現在顯示了正確的形式

問題是Z順序之一。事實證明,影子本身就是Windows本身維護的一個單獨的窗口。在Windows 7中,它似乎在主窗口下面顯示陰影。爲了正確顯示它,需要將其移動。

一位名爲ŁukaszPłomiński的天才在Embarcadero新聞組的一個主題中解釋了這一點。這裏是他的代碼梳理出來:

procedure TForm1.FixSysShadowOrder; 

    function FindSysShadowOrderProc(WindowHandle: HWND; // handle to window 
    Form: TForm1 // application-defined value, 32-bit 
    ): BOOL; stdcall; 
    var 
    Buffer: array [0 .. 255] of char; 
    Rect: TRect; 
    begin 
    Result := True; 
    if IsWindowVisible(WindowHandle) then 
    begin 
     // this code search for SysShadow window created for this window. 
     GetClassName(WindowHandle, Buffer, 255); 
     if 0 <> AnsiStrComp(Buffer, PChar('SysShadow')) then 
     Exit; 

     GetWindowRect(WindowHandle, Rect); 
     if (Rect.Left <> Form.Left) or (Rect.Top <> Form.Top) then 
     Exit; 

     Form.FSysShadowHandle := WindowHandle; 
     // stop enumeration 
     Result := False; 
    end; 
    end; 

begin 
    if not(csDesigning in ComponentState) and 
    ((GetClassLong(Handle, GCL_STYLE) and CS_DROPSHADOW) = CS_DROPSHADOW) 
    and IsWindowVisible(Handle) then 
    begin 
    // for speed, proper SysShadow handle is cached 
    if FSysShadowHandle = 0 then 
     EnumThreadWindows(GetCurrentThreadID(), @FindSysShadowOrderProc, 
     lParam(Self)); 
    // if SysShadow exists, change its z-order, and place it directly below this window 
    if FSysShadowHandle <> 0 then 
     SetWindowPos(FSysShadowHandle, Handle, 0, 0, 0, 0, 
     SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOOWNERZORDER or SWP_NOSIZE); 
    end; 
end; 

你必須制定出何時調用FixSysShadowOrder(),因爲Z訂單改變,而且不會留下正確的。 Łukasz建議在空閒的例行程序中調用它(例如更新一個Action時),並在收到WM_WINDOWPOSCHANGED消息。

+0

嗯......我想知道是否可以稱這是Microsoft Windows中的一個錯誤。 – 2010-08-21 16:31:24

+0

在d2010下這行不能編譯,'Form.FSysShadowHandle' ... – 2013-07-30 18:06:34

+0

@Edwin Yip:可以。正如代碼註釋中所述,您可以自己在TForm1中聲明FSysShadowHandle來緩存句柄。 – willw 2013-08-01 13:47:09

3

「它適用於我的電腦。「

http://privat.rejbrand.se/shdw.png
(High-res)

但它是相當有趣的,因爲我做了同樣的結論淡淡的記憶,你做,那就是,CS_DROPSHADOW不無厚,可調整大小,框架的工作。你還在?!運行Windows Vista,或許

+0

這是一個很好的觀點 - 非常感謝。我使用的是Windows 7,並且從我自己的測試中發現它有所作爲......它至少以兩種不同的方式工作!我正在編輯我的問題,以反映比我知道的情況更復雜的情況。 – willw 2010-08-21 10:38:17

3

爲了使陰影的工作,我們必須調用SystemParametersInfo的Win32 API與SPI_SETDROPSHADOW參數,打開了整個系統的陰影效果,以瞭解更多信息,請參見:

SystemParametersInfo