繁体   English   中英

与投影的无边界的TForm

[英]Borderless TForm with drop shadow

我制作了一个类似于组合的下拉部分,或提示窗口或弹出菜单的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组件,看起来它会做正确的事情,但事实证明它写得太粗糙了。

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

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

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

Windows 7仅具有桌面阴影

看看阴影如何出现在主窗口之外的位置?

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

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

XP下的相同应用程序

这适用于任何地方的阴影*。 尔加!

所以它似乎是Vista / W7的东西,正如安德烈亚斯所暗示的那样。

(*此文本的早期版本和screendump表示没有出现阴影。但是,原来是因为我关闭了Windows XP显示选项'菜单下的阴影'。杜。)

找到了! 这是证明:

替代文字

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

问题是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建议在空闲例程(例如更新操作时)和收到WM_WINDOWPOSCHANGED消息时调用它。

“它适用于我的电脑。”


(高分辨率)

但这很有趣,因为我有一个微弱的记忆,就是你得到的结论与你做的一样,也就是说,如果没有厚的,可调整大小的帧, CS_DROPSHADOW就无法工作。 你还在运行Windows Vista吗?

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

SystemParametersInfo

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM