带阴影的无边框 TForm

发布于 2024-09-15 23:06:27 字数 1740 浏览 3 评论 0原文

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

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

各种 Google 消息来源建议对此进行变体:

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:有一个名为 TShadowWindow 的不起眼的 VCL 组件,看起来可以用正确的事情,但事实证明写得太粗糙而不实用。

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

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

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

仅在桌面上有阴影的 Windows 7

看看投影超出主窗口的位置如何显示?

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

我也在 Windows XP 下尝试过相同的应用程序。它看起来是这样的。

XP 下的同一应用程序

这可以在阴影无处不在的情况下正常工作*。嘎!

因此,正如 Andreas 所说,这似乎是 Vista/W7 的事情。

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

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.

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.

Various Google sources suggest variations of this:

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;

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.

Suggestions please?

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

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

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

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.

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

Windows 7 with shadow only over desktop

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.

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

Same application under XP

This works correctly with shadow everywhere*. Gah!

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

(*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.)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

向地狱狂奔 2024-09-22 23:06:28

找到了!这是证明:

alt text

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

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

一位名叫 Łukasz Pł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 建议在空闲例程中(例如更新操作时)以及收到 WM_WINDOWPOSCHANGED 消息时调用它。

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.

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

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;

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_WINDOWPOSCHANGED message.

疑心病 2024-09-22 23:06:28

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

SystemParametersInfo

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:

SystemParametersInfo

蓦然回首 2024-09-22 23:06:28

“它可以在我的电脑上运行。”


(高分辨率)

但这很有趣,因为我依稀记得做出了与您相同的结论,即 CS_DROPSHADOW 如果没有厚实的、可调整大小的,就无法工作,框架。也许您还在运行 Windows Vista?

"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_DROPSHADOW does not work without the thick, resizable, frame. Are you still running Windows Vista, perhaps?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文