2010-08-20 104 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