windows 带阴影的无边框 TForm

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3530051/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 15:04:36  来源:igfitidea点击:

Borderless TForm with drop shadow

windowsdelphiwindows-7windows-xpdelphi-2010

提问by willw

I have made a TForm derivative that acts like the drop down part of a combo, or a hint window, or a popup menu - a temporary thing. It has no caption - its BorderStyle is set to bsNone. The form is displayed non-modally using Show, having set its position.

我制作了一个 TForm 衍生物,它的作用类似于组合的下拉部分、提示窗口或弹出菜单 - 一个临时的东西。它没有标题 - 它的 BorderStyle 设置为 bsNone。使用 Show 以非模态方式显示表单,并设置了其位置。

To make it stand out, it needs a drop shadow around its border. However, a consequence of setting its border to bsNone is that the drop shadow disappears.

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

Various Google sources suggest variations of this:

谷歌的各种来源都提出了这种变体:

procedure TdlgEditServiceTask.CreateParams(var Params: TCreateParams);
const
  CS_DROPSHADOW = 
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;
020000; 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;

but it doesn't work - the shadow is not displayed (unless I also set a resizable border with WS_THICKFRAME set, which looks terrible). This is a popup window, not a child window, so I don't see why it should fail.

但它不起作用 - 不显示阴影(除非我还设置了一个可调整大小的边框,并设置了 WS_THICKFRAME,这看起来很糟糕)。这是一个弹出窗口,而不是子窗口,所以我不明白为什么它会失败。

Suggestions please?

请提出建议?

NB: this is a similar question to thisquestion, which remains unanswered.

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

NB2: There is an obscure VCL component called TShadowWindowthat looks like it will do the right thing, but turns out to be too crudely written to be practical.

NB2:有一个名为TShadowWindow的不起眼的 VCL 组件,看起来它会做正确的事情,但结果证明写得太粗糙而不实用。

Update:Following Andreas' comments below, I have investigated this further, and found some niceties.

更新:根据下面 Andreas 的评论,我进一步调查了这一点,并发现了一些细节。

Under Windows 7, I discovered that the shadow does not appear when the popup window if it is over another window from the same application.

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

Here is a simple Delphi app, which uses CreateParams on a popup window to request a shadow as described above.

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

Windows 7 with shadow only over desktop

Windows 7 仅在桌面上有阴影

See how the drop shadow appears where it extends beyond the main window?

看看投影如何出现在它超出主窗口的地方?

But I want to use the borderless window as a popup over the main window. The drop shadow distinguishes the popup from the window underneath. All my description up above refers to this circumstance. Obviously some Windows mechanism is interfering here.

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

I have also tried the same application under Windows XP. Here is how it looks.

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

Same application under XP

XP下相同的应用程序

This works correctly with shadow everywhere*. Gah!

这适用于无处不在的阴影*。嘎!

So it would seem to be a Vista/W7 thing, as Andreas suggests.

因此,正如 Andreas 所建议的那样,它似乎是 Vista/W7 的事情。

(*An earlier version of this text and screendump suggested that no shadow appeared. However, this turned out to be because I had the Windows XP display option 'Shadows under menus' turned off. Duh.)

(*此文本和屏幕转储的早期版本表明没有出现阴影。然而,这是因为我关闭了 Windows XP 显示选项“菜单下的阴影”。废话。)

采纳答案by willw

Found it! Here is the proof:

找到了!这是证据:

alt text

替代文字

As you can see, the drop shadow now shows properly over the form.

如您所见,阴影现在可以正确显示在表单上。

The problem was one of Z-order. It turns out that the shadow is itself a separate window maintained by Windows itself. In Windows 7, it seems to show the shadow underneath the main window. In order to get it to display properly, one needs to move it up.

问题是 Z 顺序之一。事实证明,阴影本身就是一个由 Windows 自己维护的单独窗口。在 Windows 7 中,它似乎在主窗口下方显示阴影。为了让它正确显示,需要将其向上移动。

A genius called ?ukasz P?omiński explained this in a thread in the Embarcadero newsgroup. Here is his code to sort it out:

一位名叫 ?ukasz P?omiński 的天才在 Embarcadero 新闻组的一个帖子中解释了这一点。这是他的代码来整理它:

##代码##

You have to work out when to call FixSysShadowOrder(), because Z orders change, and it won't stay right. ?ukasz suggested calling it in an idle routine (for example when updating an Action), and on receipt of WM_WINDOWPOSCHANGEDmessage.

您必须确定何时调用FixSysShadowOrder(),因为 Z 顺序发生变化,并且不会保持正确。?ukasz 建议在空闲例程中调用它(例如在更新操作时),并在收到WM_WINDOWPOSCHANGED消息时调用它。

回答by Ravi shankar

For making drop shadow to work we have to invoke SystemParametersInfo win32 API with SPI_SETDROPSHADOW parameter, to turn on the entire system's drop shadow effect, for more information, please refer to:

为了使阴影起作用,我们必须调用带有SPI_SETDROPSHADOW参数的SystemParametersInfo win32 API,以打开整个系统的阴影效果,更多信息请参考:

SystemParametersInfo

系统参数信息

回答by Andreas Rejbrand

"It works on my computer."

“它在我的电脑上工作。”


(High-res)


(高分辨率)

But it is quite funny, for I have a faint memory of making the same conclusion as you make, that is, that CS_DROPSHADOWdoes not work without the thick, resizable, frame. Are you still running Windows Vista, perhaps?

但它很有趣,因为我有一个模糊的记忆,我得出了和你一样的结论,也就是说,如果CS_DROPSHADOW没有厚实的、可调整大小的框架,那是行不通的。也许您还在运行 Windows Vista?