无边框形式与投影

时间:2010-08-20 10:33:15

标签: windows delphi windows-7 windows-xp delphi-2010

我制作了一个类似于组合下拉部分,或提示窗口或弹出菜单的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,它看起来很糟糕)。这是一个弹出窗口,而不是子窗口,所以我不明白它为什么会失败。

建议吗?

注意:这是一个与this问题类似的问题,仍然没有答案。

NB2:有一个名为TShadowWindow的模糊VCL组件,它看起来会做正确的事情,但事实证明它过于粗略而不实用。

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

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

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

Windows 7 with shadow only over desktop

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

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

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

Same application under XP

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

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

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

3 个答案:

答案 0 :(得分:7)

发现它!以下是证据:

alt text

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

问题是Z-order之一。事实证明,阴影本身就是由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消息时调用它。

答案 1 :(得分:3)

“它适用于我的电脑。”

http://privat.rejbrand.se/shdw.png
(High-res)

但这很有趣,因为我有一个微弱的记忆,可以得出与你所做的相同的结论,也就是说,CS_DROPSHADOW没有厚的,可调整大小的框架就行不通。你还在运行Windows Vista吗?

答案 2 :(得分:3)

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

SystemParametersInfo