Delphi支持Aero Glass和DoubleBuffered属性 - 发生了什么以及我们如何使用它们?

War*_* P 25 delphi composition aero dwm

我很困惑Delphi 2009/2010对Windows中Aero Theme Glass功能的支持,以及DoubleBuffered的含义,以及与Aero glass有什么关系.我发现DoubleBuffered不仅是VCL中的一个属性,它也可以在.net WinForms中找到.最初我想知道它是否设置了公共控件库使用的某种窗口样式位,或者是什么.它为什么使用,何时使用?

[更新:我应该说我知道什么是"双缓冲",作为减少闪烁的一般技术,我想知道的是,为什么它与在Windows Vista中的Aero Glass窗格上渲染控件有任何关系? Windows 7,特别是为什么所有东西的按钮需要双缓冲设置为真,才能在玻璃上工作?下面链接的博客文章似乎最有用.]

特别是,我对DoubleBuffered属性感到困惑,我想知道它为什么存在,以及它在窗体和控件中的玻璃支持和双缓冲属性之间的关系是什么.当您阅读像这样的C++文章时,您会发现没有提到双缓冲.

[更新2:以下内容包含一些事实错误,并已修改:]

我发现一些C++开发人员正在讨论他们如何调用SetLayeredWindowAttributes以避免DWM/Aero合成导致的"黑色变成玻璃"故障,当你在经典的Win32应用程序中打开它时[但是下面的博客链接告诉我这不再起作用在Windows 7中,实际上只在Vista中短暂工作,直到微软阻止它].[开始错误的想法]我们不应该使用其他颜色,如明亮的洋红色,并使其变成玻璃透明色?[结束错误的想法]

什么时候应该设置和不设置DoubleBuffered的规则,以及为什么DoubleBuffered首先添加到VCL?设置什么时候会引起问题?(看来远程桌面是一种情况,但这是唯一的情况吗?)当它没有设置时,我们会搞清楚按钮文本的渲染,很可能是因为看起来Delphi没有改变默认的"渲染黑色如玻璃"在Aero DWM中.

在我看来,Aero Glass渲染基本上是以奇怪或难以理解的方式进行的[由Windows本身,而不是仅仅包含此功能的Delphi],以及2009/2010年的许多内部VCL源代码StdCtrls中的类必须做很多复杂的逻辑才能正确地在Aero Glass上呈现内容,但它仍然存在很多问题,并且看起来像是错误的,并且这可能是这个相关问题和qc问题的背后. [更新3:玻璃上的很多渲染故障,在VCL中在常见控件中渲染错误,看起来,微软并不关心修复.简而言之,Delphi VCL代码修复无法解决这样一个事实:古老的Windows通用控件库和现代[但奇特的] Aero Glass合成功能彼此不太相似,并且不能特别合作.感谢微软建立如此高质量的技术,并将其释放到世界各地.

如果它还不够有趣; 为什么我们有ParentDoubleBuffered?

[7月30日更新:这个问题对我很有意思,因为我认为它表明,当你拥有一个庞大的现有VCL框架时,使用Windows API解决这个问题是一个很难的问题.

Cos*_*und 15

关于DoubleBuffer

.NET可能有一个,它可能与Delphi的名称和目的相同,但是Delphi正在从头开始实现DoubleBuffer,我认为.NET也是如此.没有窗口样式位用于实现此功能.

DoubleBuffer和Glass Aero

相当简单:不要为位于Glass上的控件设置DoubleBuffer.要使DoubleBuffering工作,必须能够初始化"缓冲区" - 但是用Glass初始化它是什么?Windows标准控件(包括TButton)不需要DoubleBuffering.对于需要透明表面和类似doublebuffer行为的新控件,可以使用Layered windows api.

获得控件以在Glass上工作

步骤1:

TForm1 = class(TForm)
...
protected
  procedure CreateWindowHandle(const Params: TCreateParams); override;
...
end;

procedure TForm15.CreateWindowHandle(const Params: TCreateParams);
begin
  inherited;
  SetWindowLong(Handle, GWL_EXSTYLE, GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
  SetLayeredWindowAttributes(Handle, RGB(60, 60, 60), 0, LWA_COLORKEY);
end;
Run Code Online (Sandbox Code Playgroud)

第2步,这应该是你的表单的OnPaint处理程序:

procedure TForm15.FormPaint(Sender: TObject);
var rClientRect:TRect;
begin
  if GlassFrame.Enabled then
  begin
    rClientRect := ClientRect;

    Canvas.Brush.Color := RGB(60, 60, 60);
    Canvas.Brush.Style := bsSolid;
    Canvas.FillRect(rClientRect);

    if not GlassFrame.SheetOfGlass then
    begin
      rClientRect.Top := rClientRect.Top + GlassFrame.Top;
      rClientRect.Left := rClientRect.Left + GlassFrame.Left;
      rClientRect.Right := rClientRect.Right - GlassFrame.Right;
      rClientRect.Bottom := rClientRect.Bottom - GlassFrame.Bottom;
      Canvas.Brush.Color := clBtnFace;
      Canvas.FillRect(rClientRect);
    end;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

第3步:设置GlassFrame.Enabled = True; 设置所有其他Glass属性,在表单中添加控件,无论您喜欢它们.可能在Glass或其他任何地方.确保控件没有"DoubleBuffered = True".就是这样,享受吧.我已经用TButton,TCkBox和TEdit进行了测试.

......编辑......

不幸的是,使用这种方法"玻璃"被视为100%透明的表面,它不是 - 它看起来像玻璃,但它不像玻璃.100%透明度的问题是,如果单击该透明区域,则单击会转到窗口后面的窗口.可怕.

在撰写本文时,我非常确定没有API可以更改原始玻璃的默认BLACK密钥颜色(谷歌发现无数的博客和论坛帖子,您需要如何使用自定义绘图来控制玻璃上的控件而且没有用于在MSDN上的DWM函数列表中更改它的函数).在不更改默认BLACK颜色的情况下,大多数控件无法正确呈现,因为它们使用clWindowText写入文本并且是黑色.在几个论坛上发现的一个建议技巧是使用SetLayeredWindowAttributes API更改透明度颜色.它的工作原理!一旦完成,控件上的黑色文字显示抛出,但不幸的是玻璃不再是玻璃,玻璃看起来像玻璃,但表现得像100%的透明度.这几乎使这个解决方案无效,并且在微软方面显示了双重标准:原始的BLACK表现得不像100%的透明度,如果我们将其更改为更好的行为,就像100%的透明度一样.

在我看来,在Glass上使用自定义控件的常见想法是错误的.这是唯一可行的,但它是错误的,因为我们应该使用在整个平台上保持一致的控件:建议自定义控件打开通向不一致的类似winamp的应用程序的大门,每个用户重新创建轮子到适合它的艺术理念.即使开发人员设法忠实地重新创建任何给定的窗口控件并使其在玻璃上工作,"修复"只是暂时的,需要为下一版本的窗口重新创建.更不用说应该为现有版本的Windows提供多种变体.

另一种解决方案是使用UpdateLayeredWindow的分层窗口.但由于很多原因,这是一个痛苦.

这对我来说是一个死胡同.但我会给这个问题一个"最喜欢的"旗帜,如果有更好的东西出现,我想知道它.


Rod*_*ddy 7

您的问题已经在Delphi Haven上发布了CR的博客文章 ......

看看Stack Overflow,我刚刚注意到一个关于Aero玻璃的相当详细的问题(实际上是一组问题).