[更新:我应该声明,我知道什么是“双缓冲”,作为减少闪烁的一般技术,我想知道的是,为什么有任何关于渲染控制在Windows Vista / Windows 7,特别是为什么一个BUTTON的所有东西都需要双缓冲设置为真,在玻璃上工作。下面链接的博客帖子似乎是最丰富的信息。]
特别是,我很困惑的DoubleBuffered属性,我想知道,为什么它存在,它的玻璃支持和双缓冲属性在窗体和控件之间的关系设置。当你读到C++ articles like this one,你会发现没有提到双缓冲。
我发现一些C开发人员谈论他们如何可以调用SetLayeredWindowAttributes,以避免DWM / Aero合成导致当你在经典的Win32应用程序中打开“黑色变成玻璃”毛刺[但是下面的博客链接告诉我,这不再工作在Windows 7中,实际上只是简单地在Vista中,直到Microsoft阻止它]。 [开始错误的想法]我们不应该使用一些其他颜色,像明亮的洋红色,使之变成玻璃透明色? [结束错误想法]
当DoubleBuffered应该设置和未设置,以及为什么DoubleBuffered添加到VCL的规则是什么?什么时候设置会导致问题? (它看起来远程桌面是一种情况,但是是唯一的情况?),当它没有设置,我们得到闪烁的按钮文本的渲染,很可能是因为它似乎Delphi不改变默认“渲染黑色玻璃“在Aero DWM。
在我看来,Aero Glass渲染基本上是以奇怪或难以理解的方式完成的[由Windows本身,而不是由Delphi,它只是包装这个功能],并且在2009/2010的许多内部VCL源代码在StdCtrls中的类必须做很多复杂的逻辑来在Aero Glass上正确地渲染东西,但它仍然有很多问题,并且看起来像我做错了,这可能是在这之后related question,and qc issue. [Update3:很多在玻璃上渲染毛刺,在VCL中渲染做错了内部的常见控件,这似乎微软不在乎固定。总之,Delphi VCL代码修复不能修复的事实,古老的Windows公共控制库和现代[但古怪] Aero玻璃合成功能不喜欢对方,不是特别是一起工作。感谢Microsoft建立这样一个高质量的技术,并释放它在世界上。
如果它还不够有趣;为什么我们有ParentDoubleBuffered?
[7月30日更新:这个问题对我很有趣,因为我认为它表明,工作在Windows API解决这个问题,当你有一个大的现有VCL框架,是一个艰难的问题。
解决方法
.NET可能有一个,它可能有与Delphi相同的名称和目的,但Delphi正在从头开始实现DoubleBuffer,我认为.NET也是一样。不使用窗口样式位来实现此。
双缓冲和玻璃航空
相当简单:不要为坐在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),LWA_COLORKEY); end;
步骤2,这应该是你的窗体的OnPaint处理程序:
procedure TForm15.FormPaint(Sender: TObject); var rClientRect:TRect; begin if GlassFrame.Enabled then begin rClientRect := ClientRect; Canvas.Brush.Color := RGB(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;
步骤3:设置GlassFrame.Enabled = True;设置所有其他玻璃属性,添加控件到窗体,无论你喜欢他们。可能在玻璃上或其他地方。确保控件没有“DoubleBuffered = True”。就是这样,享受。我已经测试与TButton,TCkBox和TEdit。
…编辑…
不幸的是,使用这种方法“玻璃”被视为100%透明表面,它不是 – 它看起来像玻璃,但它的行为不像玻璃。 100%透明度的问题是,如果你点击那个透明区域,你的点击进入窗口后面的窗口。可怕。
在写这篇文章的时候,我确定没有API可以更改原始玻璃的默认BLACK键颜色(google发现无数博客和论坛帖子,您需要使用自定义绘图来控制坐在玻璃上的控件,并且没有功能改变在the list of DWM functions on MSDN)。没有改变默认的BLACK颜色,大多数控件不能正确呈现,因为他们使用clWindowText编写文本,这是BLACK。在几个论坛上发现的一个建议的技巧是使用SetLayeredWindowAttributes API更改透明度颜色。它的工作原理!一旦完成黑色文本控件显示投掷,但不幸的是,玻璃不再是玻璃,玻璃看起来像玻璃,但表现得像100%的透明度。这几乎使这个解决方案无效,并在微软方面显示了双重标准:原来的BLACK不像100%透明度,如果我们改变它的行为像100%透明度的行为。
在我看来,在Glass上使用自定义控件的常见思考是错误的。这是唯一可能的工作,但它是错误的,因为我们应该使用在平台上一致的控件:建议自定义控件打开不一致,winamp的应用程序的门,每个用户重新创建车轮西装是艺术的想法。即使开发人员设法忠实地重新创建任何给定的窗口控件,并使其在玻璃上工作,“修复”只是临时的,需要为下一个版本的窗口重新创建。更不用说现有版本的Windows应该有多个变体。
另一个解决方案是使用带有UpdateLayeredWindow的分层窗口。但是这是一个痛苦的sooo很多原因。
这对我来说是一个死胡同。但我会给这个问题一个“最喜欢”的旗帜,如果更好的东西出现我想知道它。