不带 Aero Glass 的 DwmExtendFrameIntoClientArea

发布于 2024-08-21 02:11:03 字数 634 浏览 15 评论 0原文

在启用 Aero Glass 的情况下使用 DwmExtendFrameIntoClientArea API 调用效果很好。但是,我希望它在 Aero Glass 被禁用时也能工作,就像它在 Windows 控制面板中的工作方式一样:

输入图像描述此处

请注意,即使 Aero Glass 已禁用,框架仍如何延伸到客户区域?当我在应用程序中进行 DwmExtendFrameIntoClientArea API 调用时,返回的 HRESULT 肯定不成功,我的应用程序最终看起来像这样:

http://img197.imageshack.us/img197/9629/clientapplication.png

通常,启用 Aero Glass 后,边框会向下延伸到导航按钮下方,就像控制面板。我该怎么做? DwmExtendFrameIntoClientArea 显然不起作用。

顺便说一下,如果相关的话,我的应用程序是WPF应用程序。

Using the DwmExtendFrameIntoClientArea API call with Aero Glass enabled works just fine. However, I want it to work when Aero Glass is disabled as well, like how it works in the Windows control panel:

enter image description here

Notice how the frame has extended into the client area, even though Aero Glass is disabled? When I make the DwmExtendFrameIntoClientArea API call in my application, the returned HRESULT is definitely not success, and my application ends up looking like this:

http://img197.imageshack.us/img197/9629/clientapplication.png

Normally, with Aero Glass enabled, the border stretches down to underneath the navigation buttons, like in the control panel. How do I do this? DwmExtendFrameIntoClientArea clearly isn't working.

By the way, if it is relevant, my application is a WPF application.

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

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

发布评论

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

评论(3

紫南 2024-08-28 02:11:03

尼尔的回答是正确的;当构图被禁用时,您必须自己绘制该区域。

我可以向您展示表单顶部面板的绘制处理程序中的代码 - 该面板通常负责绘制 0x00000000 透明黑色以使玻璃出现:

伪代码:

procedure DrawGlassHeaderArea(g: Graphics; r: Rectangle; IsFormFocused: Boolean);
const
   clFakeGlassColor = $00EAD1B9;  //(185, 209, 234) This is the fake foreground glass color (for use when composition is disabled)
   clFakeGlassColorUnfocused = $00F2E4D7; //(215, 228, 242) This is the fake background glass color (for use when composition is disabled)
begin
   if Dwm.IsCompositionEnabled then
   begin
      g.FillRectangle(r, 0x00000000); //fill rectangle with transparent black
   end
   else
      //Composition disabled; fake it like Microsoft does

      //The color to use depends if the form has focused or not
      Color glassColor;
      if (IsFormFocused) then
         c = clFakeGlassColor 
      else
         c = clFakeGlassColorUnfocused;

      g.FillRectangle(r, glassColor); //fill rectangle with fake color


      //Now we have to draw the two accent lines along the bottom
      Color edgeHighlight = ColorBlend(Colors.White, glassColor, 0.33); //mix 33% of glass color to white
      Color edgeShadow = ColorBlend(Colors.Black, glassColor, 0.33); //mix 33% of glass color to black

      //Draw highlight as 2nd-last row:
      g.DrawLine(edgeHighlight, Point(r.Left, r.Bottom-2), Point(r.Right, r.Bottom-2);

      //Draw shadow on the very last row:
      g.DrawLine(edgeHighlight, Point(r.Left, r.Bottom-1), Point(r.Right, r.Bottom-1);
   end;
end;

示例使用

procedure MyForm.PaintBox1Paint(PaintEventArgs e)
begin
   DrawGlassHeaderArea(e.Graphics, PaintBox1.ClientRectangle, this.HasFocus); 
end;

奖励屏幕截图

在此处输入图像描述

更新 7/9/2014

@JakePetroules 是对的,而我错了。用于假玻璃的“蓝色”硬编码到Windows中。并且可以使用GetThemeColor

我编码了可用于 Window 类的所有可用颜色 (TMT_COLOR):

在此处输入图像描述

注意:有关类、部分和状态的详细信息,请参阅航空样式类、零件和状态

使用时:

  • Window< /code>
  • 部分WP_CAPTION
  • 状态不适用(StateID 不用于标题部分,也不是整个Window类)

并获取颜色代码propertyID

  • TMT_FILLCOLORHINT:当窗口具有焦点时
  • TMT_BORDERCOLORHINT:当窗口没有焦点时,

您将获得两种重要的颜色:

在此处输入图像描述

我现在用来获取假玻璃颜色的伪代码:

public Color GetFakeClassColor(Boolean isWindowFocused=true)
{
   static Color fakeGlass= 0x00B8D0E9; //the correct answer anyway

   if ((GetThemeAppProperties() && STAP_ALLOW_CONTROLS) == 0)
      return fakeGlass;

   hTheme = OpenThemeData(GetDesktopWindow(), "Window");
   if (hTheme = 0)
      return fakeGlass;

   Int32 propID;
   if (isWindowFocused)
       propID= TMT_FILLCOLORHINT; //The color used as a fill color hint for custom controls.
   else
       propID= TMT_BORDERCOLORHINT; //The color used as a border color hint for custom controls.

   DWORD rgb;
   if (Failed(GetThemeColor(hTheme, WP_CAPTION, 0, propID, ref rgb))
      return fakeGlass;

   Result = new Color(rgb);
}

实际上,由于我使用 Delphi,我的实际代码是:

function GetFakeGlassColor(IsWindowFocused: Boolean=True): TColor;
var
    ted: TThemedElement;
    hTheme: THandle;
    propID: Integer;
    rgb: DWORD;
begin
    Result := $00B8D0E9; //the correct answer anyway

    //We can't use the ThemeServcies.ThemesEnabled, as that mistakenly checks for version 6 of the common controls library
    //Themes can be enabled without using ComCtl V6, or common controls at all
    if not ThemeServices.ThemesAvailable then
        Exit;
    if (GetThemeAppProperties and STAP_ALLOW_CONTROLS) = 0 then
        Exit;

    htheme := ThemeServices.Theme[teWindow];
    if hTheme = 0 then
        Exit;

    if IsWindowFocused then
        propID := TMT_FILLCOLORHINT //The color used as a fill color hint for custom controls.
    else
        propID := TMT_BORDERCOLORHINT; //The color used as a border color hint for custom controls.

    if Failed(GetThemeColor(hTheme, WP_CAPTION, 0, propID, {var}rgb)) then
        Exit;

    Result := rgb;
end;

Nir's answer is correct; when composition is disabled you have to draw that area yourself.

i can show you the code i have in the paint handler of the panel at the top of my form - the panel normally responsible for drawing the 0x00000000 transparent black to make the glass appear:

Psuedo-code:

procedure DrawGlassHeaderArea(g: Graphics; r: Rectangle; IsFormFocused: Boolean);
const
   clFakeGlassColor = $00EAD1B9;  //(185, 209, 234) This is the fake foreground glass color (for use when composition is disabled)
   clFakeGlassColorUnfocused = $00F2E4D7; //(215, 228, 242) This is the fake background glass color (for use when composition is disabled)
begin
   if Dwm.IsCompositionEnabled then
   begin
      g.FillRectangle(r, 0x00000000); //fill rectangle with transparent black
   end
   else
      //Composition disabled; fake it like Microsoft does

      //The color to use depends if the form has focused or not
      Color glassColor;
      if (IsFormFocused) then
         c = clFakeGlassColor 
      else
         c = clFakeGlassColorUnfocused;

      g.FillRectangle(r, glassColor); //fill rectangle with fake color


      //Now we have to draw the two accent lines along the bottom
      Color edgeHighlight = ColorBlend(Colors.White, glassColor, 0.33); //mix 33% of glass color to white
      Color edgeShadow = ColorBlend(Colors.Black, glassColor, 0.33); //mix 33% of glass color to black

      //Draw highlight as 2nd-last row:
      g.DrawLine(edgeHighlight, Point(r.Left, r.Bottom-2), Point(r.Right, r.Bottom-2);

      //Draw shadow on the very last row:
      g.DrawLine(edgeHighlight, Point(r.Left, r.Bottom-1), Point(r.Right, r.Bottom-1);
   end;
end;

Sample usage

procedure MyForm.PaintBox1Paint(PaintEventArgs e)
begin
   DrawGlassHeaderArea(e.Graphics, PaintBox1.ClientRectangle, this.HasFocus); 
end;

Bonus Screenshot

enter image description here

Update 7/9/2014

@JakePetroules was right, and i was wrong. The "blue" used for fake glass is not hard-coded into Windows. And it is accessible using GetThemeColor.

I coded up all the available colors (TMT_COLOR) available for a Window class:

enter image description here

Note: For more information about Classes, Parts, and States, see Aero Style Classes, Parts, and States

When using:

  • Class: Window
  • Part: WP_CAPTION
  • State: n/a (StateID is not used for the Caption part, nor the entire Window class)

and fetch the color code propertyID:

  • TMT_FILLCOLORHINT: for when the window has focus
  • TMT_BORDERCOLORHINT: for when the window does not have focus

you get the two important colors:

enter image description here

The pseudo-code i now use to get the fake glass color:

public Color GetFakeClassColor(Boolean isWindowFocused=true)
{
   static Color fakeGlass= 0x00B8D0E9; //the correct answer anyway

   if ((GetThemeAppProperties() && STAP_ALLOW_CONTROLS) == 0)
      return fakeGlass;

   hTheme = OpenThemeData(GetDesktopWindow(), "Window");
   if (hTheme = 0)
      return fakeGlass;

   Int32 propID;
   if (isWindowFocused)
       propID= TMT_FILLCOLORHINT; //The color used as a fill color hint for custom controls.
   else
       propID= TMT_BORDERCOLORHINT; //The color used as a border color hint for custom controls.

   DWORD rgb;
   if (Failed(GetThemeColor(hTheme, WP_CAPTION, 0, propID, ref rgb))
      return fakeGlass;

   Result = new Color(rgb);
}

In reality, since i use Delphi, my actual code is:

function GetFakeGlassColor(IsWindowFocused: Boolean=True): TColor;
var
    ted: TThemedElement;
    hTheme: THandle;
    propID: Integer;
    rgb: DWORD;
begin
    Result := $00B8D0E9; //the correct answer anyway

    //We can't use the ThemeServcies.ThemesEnabled, as that mistakenly checks for version 6 of the common controls library
    //Themes can be enabled without using ComCtl V6, or common controls at all
    if not ThemeServices.ThemesAvailable then
        Exit;
    if (GetThemeAppProperties and STAP_ALLOW_CONTROLS) = 0 then
        Exit;

    htheme := ThemeServices.Theme[teWindow];
    if hTheme = 0 then
        Exit;

    if IsWindowFocused then
        propID := TMT_FILLCOLORHINT //The color used as a fill color hint for custom controls.
    else
        propID := TMT_BORDERCOLORHINT; //The color used as a border color hint for custom controls.

    if Failed(GetThemeColor(hTheme, WP_CAPTION, 0, propID, {var}rgb)) then
        Exit;

    Result := rgb;
end;
梦魇绽荼蘼 2024-08-28 02:11:03

你必须把它画成你自己的框架。

您必须使用 DwmIsCompositionEnabled 来检查 DWM 是否已启用,并处理 WM_DWMCOMPOSITIONCHANGED 来检测 DWM 状态更改。

然后你必须以单独的方式绘制窗口,如果启用了 DWM,则使用 DwmExtendFrameIntoClientArea,如果禁用,则自己绘制“框架”。

我不知道如何在 WPF 中复制 Aero 框架(在我的应用程序中,我有自己的配色方案,并且没有使用 Auro 框架)。

这很烦人,但是当 DWM 被禁用时,系统会回退到 XP 样式绘图,并且 DWM 的任何服务都不起作用 - 即使是那些与玻璃效果无关的服务。

You have to paint it to be frame-like yourself.

You have to use DwmIsCompositionEnabled to check if the DWM is enabled and handle WM_DWMCOMPOSITIONCHANGED to detect DWM state changed.

Then you have to have to separate way of drawing the window, if DWM is enabled you use DwmExtendFrameIntoClientArea, if it's disabled you draw the "frame" yourself.

I have no idea how to duplicate the Aero frame in WPF (in my app I have my own color scheme and I'm not using the Auro frame).

This is annoying but when the DWM is disabled the system falls back to XP-style drawing and none of the DWM's services work - even those that aren't related to the glass effect.

梦魇绽荼蘼 2024-08-28 02:11:03

您需要自己绘制窗口背景。您实际上不应该像以前的帖子所建议的那样对颜色进行硬编码,而是使用主题函数来检索它们,如下所示(半伪代码):

DWORD rgb;
HANDLE hTheme = OpenThemeData(GetDesktopWindow(), L"WINDOW");
GetThemeColor(hTheme, WP_CAPTION, CS_ACTIVE,
    <is active window> ? TMT_FILLCOLORHINT : TMT_BORDERCOLORHINT, &rgb);

// Can use these functions to retrieve the individual RGB values
BYTE r = GetRValue(rgb);
BYTE g = GetGValue(rgb);
BYTE b = GetBValue(rgb);

即使用户在控制面板中更改标题栏颜色,这些颜色也将保持正确(与使用 COLOR_ACTIVECAPTION / COLOR_GRADIENTACTIVECAPTION 不同)。在尝试获取主题颜色之前,您还应该使用 IsThemeActive() 检查主题是否处于活动状态。

供快速参考的常量值:

  • WP_CAPTION: 1
  • CS_ACTIVE: 1
  • TMT_FILLCOLORHINT: 3821
  • TMT_BORDERCOLORHINT: 3822

You need to paint the window background yourself. You should not actually hard-code the colors as previous posts have suggested, but use the theme functions to retrieve them, like so (semi-pseudocode):

DWORD rgb;
HANDLE hTheme = OpenThemeData(GetDesktopWindow(), L"WINDOW");
GetThemeColor(hTheme, WP_CAPTION, CS_ACTIVE,
    <is active window> ? TMT_FILLCOLORHINT : TMT_BORDERCOLORHINT, &rgb);

// Can use these functions to retrieve the individual RGB values
BYTE r = GetRValue(rgb);
BYTE g = GetGValue(rgb);
BYTE b = GetBValue(rgb);

These colors will remain correct even if the user changes title bar colors in the control panel (unlike using COLOR_ACTIVECAPTION / COLOR_GRADIENTACTIVECAPTION). You should also check that themes are active using IsThemeActive() before attempting to get theme colors.

The values of the constants for quick reference:

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