Delphi支持Aero Glass和DoubleBuffered属性 - 发生了什么,我们如何使用它们? [英] Delphi support for Aero Glass and the DoubleBuffered property - what is going on and how do we use them?

查看:236
本文介绍了Delphi支持Aero Glass和DoubleBuffered属性 - 发生了什么,我们如何使用它们?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我感到困惑的是,Delphi 2009/2010支持Windows中的Aero Theme Glass功能,以及什么,正是DoubleBuffered的意思,以及它与Aero Glass有什么关系。我发现DoubleBuffered不仅是VCL中的一个属性,还可以在 .net WinForms 中找到。最初我想知道它是否设置了通用控件库使用的某种窗口样式位,或什么。为什么使用它,什么时候使用?



[更新:我应该声明我知道什么是双缓冲,作为一般的减少技术闪烁,我想知道的是,为什么它与在Windows Vista / Windows 7中的Aero Glass窗格上的渲染控件有任何关系,特别是为什么所有事情的按钮都需要双重缓冲设置为true在玻璃上工作?下面的博客文章看起来最有帮助。]



特别是,我被DoubleBuffered属性困惑,我想知道,为什么它存在,以及它的关系在玻璃支架和双缓冲属性之间设置一个窗体和一个控件。当你阅读这样的C ++文章你看到没有提到双缓冲。



[Update2:以下包含一些事实错误,并已修改:]



我发现一些C ++开发人员谈论他们如何调用SetLayeredWindowAttributes,以避免在您的经典Win32应用程序中切换DWM / Aero合成导致的黑色变成玻璃故障[但是下面的博客链接告诉我,这不再适用于Windows 7,实际上只在Vista中简单地工作,直到微软阻止它]。 [开始错误的想法]我们不应该使用一些其他颜色,如明亮的洋红色,并将其转化为玻璃透明度的颜色? [结束错误的想法]



当DoubleBuffered应该被设置并且没有被设置是什么规则,为什么DoubleBuffered首先添加到VCL?什么时候会出现问题? (看起来远程桌面是一种情况,但是这是唯一的情况吗?),而当它没有设置时,我们会看到渲染按钮文本,很可能是因为看起来Delphi不会更改默认的渲染黑色 在航空DWM中。



在我看来,Aero Glass渲染正在以奇怪或难以理解的方式完成(由Windows本身,而不是由Delphi,它仅仅包装了这个功能],而且在2009/2010的StdCtrls类中的很多内部VCL源代码必须做很多复杂的逻辑才能在Aero Glass上正确渲染东西,但它仍然有很多问题和外观对我来说这样做是错误的,这可能在这个相关的问题和qc问题。 [Update3:在玻璃上的很多渲染故障,在VCL中渲染完成错误内部常见的控件,这似乎Micro软不关心固定。简而言之,Delphi VCL代码修复不能解决古代Windows通用控件库和现代[但古怪] Aero Glass合成功能不相似的事实,并不能一起工作。感谢Microsoft建立如此高品质的技术,并将其发布在世界各地。]



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



[更新7月30日:这个问题对我很有趣,因为我认为这表明在Windows API上工作来解决这个问题,当你有一个大的现有的VCL框架,是一个困难的问题。]

解决方案

关于DoubleBuffer



.NET可能有一个,它可能具有与Delphi相同的名称和相同的用途,但是Delphi正在从底层实现DoubleBuffer,我认为.NET也是一样的。没有窗口样式位用于实现。



DoubleBuffer和Glass Aero



相当简单:不要设置DoubleBuffer用于坐在玻璃上的控件。对于DoubleBuffering工作,必须能够初始化缓冲区 - 但是要为Glass初始化什么? Windows标准控件(包括TButton)不需要DoubleBuffering。对于需要透明表面和双缓冲行为的新控件,可以使用分层窗口api。



使控件在Glass上工作



步骤1:

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

程序TForm15.CreateWindowHandle(const Params:TCreateParams);
开始
继承;
SetWindowLong(Handle,GWL_EXSTYLE,GetWindowLong(Handle,GWL_EXSTYLE)或WS_EX_LAYERED);
SetLayeredWindowAttributes(Handle,RGB(60,60,60),0,LWA_COLORKEY);
结束

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

  procedure TForm15.FormPaint(Sender:TObject); 
var rClientRect:TRect;
begin
如果GlassFrame.Enabled然后
begin
rClientRect:= ClientRect;

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

如果不是GlassFrame.SheetOfGlass然后
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);
结束
结束
结束

步骤3 :设置GlassFrame.Enabled = True;设置所有其他Glass属性,添加控件到窗体,无论你喜欢它们。可能在玻璃或其他地方。确保控件没有DoubleBuffered = True。就这样,享受吧。我已经用TButton,TCkBox和TEdit测试了。



...编辑...



这种方法玻璃被视为100%透明的表面,它不是 - 它看起来像玻璃,但它不像玻璃。 100%透明度的问题是,如果您点击该透明区域,您的点击将转到窗口后面的窗口。可怕的



在撰写本文时,我确定没有API可以更改原始玻璃杯的默认BLACK键颜色(谷歌发现无数的博客和论坛帖子关于如何使用自定义绘图来控制坐在玻璃上的控件,并且没有任何功能可以在 MSDN上DWM函数的列表)。无需更改默认的BLACK颜色,大多数控件无法正确呈现,因为它们使用clWindowText写入文本,而且是BLACK。在几个论坛上发现的一个建议技巧是使用SetLayeredWindowAttributes API更改透明度颜色。它的工作原理一旦这样做,控件上的黑色文本就会显示出来,但不幸的是,玻璃不再是玻璃,玻璃看起来像玻璃,但表现为100%的透明度。这几乎使这个解决方案无效,并显示出微软方面的双重标准:原来的BLACK不像100%的透明度,但如果我们把它改成更好的东西,它的行为就像100%的透明度。



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



另一个解决方案是使用UpdateLayeredWindow分层窗口。但是,这是很多原因的PAIN。



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


I am confused by Delphi 2009/2010 support for the Aero Theme Glass features in Windows, and by what, exactly DoubleBuffered means, and what it has to do with Aero glass. I have found that DoubleBuffered is not only a property in the VCL, it also is found in .net WinForms. Initially I wondered if it set some kind of window style bit used by the common controls library, or what. Why is it used, and when should it be used?

[Update: I should state that I know what "double-buffering" is, as a general technique for reduction of flicker, what I wondered is, why does it have ANYTHING to do with rendering controls on an Aero Glass pane in Windows Vista/Windows 7, and in particular why would a BUTTON of all things need to have double-buffering set true, to work over glass?. The blog post linked below seems most informative.]

In particular, I am confused by the DoubleBuffered property, and I want to know, why it exists, and what its relationship between the glass support and the double-buffered property in a form and a control are set. When you read C++ articles like this one you see that there is no mention of double buffering.

[Update2: The following contained some factual errors, and has been amended:]

I found some C++ developers talking about how they can call SetLayeredWindowAttributes to avoid the "black becomes glass" glitch that DWM/Aero compositing causes when you switch it on in your classic Win32 app [however the blog link below tells me that this no longer works in Windows 7, and actually only briefly worked in Vista, until Microsoft blocked it]. [Begin WRONG Idea] Shouldn't we use some other color, like bright magenta and make that turn into the glass transparency color? [End WRONG Idea]

What are the rules for when DoubleBuffered should be set and not set, and why was DoubleBuffered added to the VCL in the first place? When will it cause problems when set? (It appears remote desktop is one case, but is that the only case?) and when it is not set, we get glitched out rendering of button text, most likely because it appears that Delphi does not change the default "render black as glass" in the Aero DWM.

It seems to me that Aero Glass rendering is being done fundamentally in an odd or hard to understand way [by Windows itself, not by Delphi, which merely wraps this functionality], and that a lot of internal VCL source code in 2009/2010 in classes in StdCtrls has to do a lot of complex logic to render stuff correctly on Aero Glass, and yet it's still got lots of problems and looks to me like it's done wrong, and that this might be behind this related question, and qc issue. [Update3: A lot of rendering glitches on glass, in the VCL are rendering done wrong inside common controls, which it seems, Microsoft doesn't care about fixing. In short, Delphi VCL code fixes can't fix the fact that the ancient Windows common controls library and the modern [but quirky] Aero Glass compositing feature don't like each other much and don't particularly work well together. Thank you Microsoft for building such a high quality technology and unleashing it on the world.]

And if it wasn't fun enough yet; Why do we have ParentDoubleBuffered?

[Update July 30: This question is interesting to me because I think it shows that working on the Windows API to solve this problem, when you have a large existing VCL framework, is a hard hard problem.]

解决方案

About DoubleBuffer

.NET may have one, and it may have the same name and the same purpose as Delphi's one, but Delphi is implementing DoubleBuffer from ground-up and I assume .NET does the same. No window style bits are used implementing this.

DoubleBuffer and Glass Aero

Fairly simple: Don't set DoubleBuffer for controls that sit on Glass. For DoubleBuffering to work one has to be able to initialize the "Buffer" - but what to initialize it with for Glass? DoubleBuffering is not required for Windows standard controls (including TButton). For new controls that need both transparent surfaces and doublebuffer-like behaviour, one can use the Layered windows api's.

Getting controls to work on Glass

Step 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;

Step 2, this should be your form's OnPaint handler:

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;

Step 3: Set GlassFrame.Enabled = True; Set all other Glass properties, add controls to the form, wherever you like them. May be on Glass or anywhere else. Make sure the controls don't have "DoubleBuffered = True". That's it, enjoy. I've tested with TButton, TCkBox and TEdit.

... EDIT ...

Unfortunately using this method "Glass" is treated as an 100% transparent surface, and it's not - it looks like glass, but it doesn't behave like glass. The problem with 100% transparency is, if you click on that transparent area, your click goes to the window behind your window. Horrible.

At the time of this writing I'm pretty sure there's no API to change the default BLACK key color for the original glass (google finds countless blog and forum posts on how you need to use custom drawing for controls that sit on glass and there's no function to change that in the list of DWM functions on MSDN). Without changing the default BLACK color most controls can't render properly because they write text using clWindowText and that's BLACK. One suggested trick found on several forums is to change the transparency color using the SetLayeredWindowAttributes API. And it works! Once that's done black text on controls shows throw, but unfortunately glass is no longer glass, glass looks like glass but behaves like 100% transparency. This pretty much invalidates this solution and shows an double standard on Microsoft's side: The original BLACK does not behave like 100% transparency yet if we change it to something better it does behave like 100% transparency.

In my opinion the common thinking of using custom-controls on Glass is wrong. It's the only thing that might work, but it's wrong, because we're supposed to use controls that are consistent across the platform: suggesting custom controls opens the door to inconsistent, winamp-like applications, where each user re-creates the wheel to suit it's artistic ideas. Even if an developer manages to faithfully recreate any given windows control and make it work on glass, the "fix" is only temporary and needs to be re-created for the next version of windows. Not to mention one should probably have multiple variants for the existing versions of windows.

The other solution is to use Layered windows with UpdateLayeredWindow. But that's a PAIN for sooo many reasons.

This is an dead end for me. But I'll give the question an "favorite" flag, if something better shows up I'd like to know about it.

这篇关于Delphi支持Aero Glass和DoubleBuffered属性 - 发生了什么,我们如何使用它们?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆