关于Windows:带阴影的无边界TForm

Borderless TForm with drop shadow

我制作了一个TForm派生类,它的作用类似于组合的下拉部分,提示窗口或弹出菜单-这是暂时的。它没有标题-它的BorderStyle设置为bsNone。设置位置后,使用"显示"以无模式显示该表单。

要使其脱颖而出,需要在其边框周围添加阴影。但是,将其边框设置为bsNone的结果是,阴影消失了。

各种各样的Google资料来源都建议这样做:

1
2
3
4
5
6
7
8
9
10
11
12
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设置了可调整大小的边框,看起来很糟糕)。这是一个弹出窗口,而不是子窗口,因此我看不出它为什么会失败。

请提出建议?

注意:这是与此问题类似的问题,但仍未得到解答。

NB2:有一个晦涩的VCL组件,称为TShadowWindow,看起来像做对的事情,但事实证明它太粗糙了,不实用。

更新:根据Andreas的以下评论,我对此进行了进一步调查,并发现了一些好处。

在Windows 7下,我发现如果弹出窗口位于同一应用程序的另一个窗口上方,则该阴影不会出现。

这是一个简单的Delphi应用程序,如上所述,它在弹出窗口上使用CreateParams来请求阴影。

Windows

看看投影在超出主窗口的地方如何显示?

但是我想使用无边界窗口作为主窗口的弹出窗口。阴影将弹出窗口与下面的窗口区分开。我上面的所有描述都是针对这种情况。显然,某些Windows机制会干扰这里。

我也在Windows XP下尝试了相同的应用程序。这是它的外观。

Same


找到了!这是证明:

alt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
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消息时调用它。


要使阴影正常工作,我们必须使用SPI_SETDROPSHADOW参数调用SystemParametersInfo win32 API,以打开整个系统的阴影效果,有关更多信息,请参考:

SystemParametersInfo


"它可以在我的计算机上使用。"

(高分辨率)

但是这很有趣,因为我对做出与您相同的结论有微弱的记忆,即CS_DROPSHADOW如果没有厚的,可调整大小的框架不起作用。也许您还在运行Windows Vista?