2010-07-26 62 views
10

我一直在使用Delphi 2010中的Aero试图找到一个好看的设计。人们看到的一个明显的用途就是将玻璃框架扩展为包含OK/Cancel按钮在屏幕的底部。我注意到,虽然这在Delphi 2010中看起来不太正确 - 每个按钮周围都有一个白色边框。Delphi按钮在Aero玻璃上显示白色边框

此图显示了问题:前3个按钮来自我的应用程序,最下面两个来自Paint.NET的图层属性对话框。

White borders around Delphi controls http://i30.tinypic.com/1zzqfm0.png

我试图和DoubleBuffered的各种组合第一放置在其他控件的控件的几个组合,但问题仍然存在。有任何想法吗?

+2

您是否拥有显示此行为的最小应用程序的来源? (.dfm和.pas的简单形式将会这样做) – 2010-07-26 14:26:48

+0

@Jeroen:我可以用包含TButton并设置玻璃框的简单表单重现该行为,以便按钮位于玻璃上。我目前无法连接到QC,因此我无法确定是否存在类似的错误。 – 2010-07-26 14:30:50

+0

有趣的行为 - 当button.doublebuffered为true,但形式doublebuffered是假的,我得到一个颜色(黑色)周围的按钮,当两个是真实的,我得到不同的颜色(如上面,灰色或clBtnFace),当按钮不是双缓冲的,文本看起来变灰。所以如果没有看起来像垃圾,在delphi 2010上使用玻璃上的按钮是不可能的? – 2010-07-27 20:13:12

回答

5

如果没有人有干净的解决方案,作为解决方法使用TBitBtnDoubleBuffered = false

+3

+1用于开箱即用的思考。但当然,它从来没有这么简单:-( BitBtn看起来没有双缓冲没有双缓冲,但没有双缓冲,但打开它的形式,并且BitBtn看起来是一样的,关闭窗体,并且你的标签消失了。Aaargh! – 2010-07-26 15:05:08

+0

TSpeedButton在我尝试这里时看起来很好,但它不接受键盘焦点 – 2010-07-27 20:14:16

+0

在Delphi XE中,TBitBtn完美工作 - 无论TBitBtn或表单上的DoubleBuffered设置如何,这都是我的首选解决方案 – 2011-07-12 08:52:43

2

似乎唯一的解决方法是所有者绘制或第三方按钮控件Check out the Glass Button by Roy Klever或者如下面链接的质量控制条目中所述TBitBtn带有DoubleBuffered = false,这是此问题上面已接受的答案。

这是Windows Aero DWM中的一个错误,或者是Windows常见控件中的错误,或者是VCL类层次处理常见控件窗口消息和绘制玻璃时绘画的错误。总之,Windows常用控件不能在玻璃上正确地自行涂漆,或者DWM组合(Aero)破损。惊喜。

标准的VCL按钮组件使用Windows Common Controls中的Window Class BUTTON。

请注意TSpeedButton不使用Windows公共控件,并没有这个问题。但是,它也不接受重点。

看来Embarcadero知道这个问题,它是QC# 75246,它是关闭的,因为它实际上是公共控制库中的一个错误,就像Will not Fix一样,建议使用TBitBtn。按钮并不孤单,这是一组QC报告的一部分,包括面板和其他常用控件。

但是,我有一个商业TcxButton(开发人员快速组件的一部分)接受键盘焦点,并没有画出这个故障。任何使用Win32公共控件按钮控件的代码似乎都有此问题。低级别的Win32 API黑客可能会找到解决方法。我正在研究它。如果我知道这个答案将会被更新。

一个有趣的细节:TcxButton有三种绘画风格,cxButton.LookAndFeel.Kind = {lfOffice11,lfFlat,lfStandard}。选择lfOffice11会将此故障重新加入。它看起来像是Vista/Win7中的aero中的玻璃功能与普通的control/xptheme按钮绘图代码之间的奇怪交互。

这可能是唯一的解决方法是使用完全应用绘制的按钮控件,并且不使用Windows常用控件按钮或任何依赖于XP主题引擎的按钮控件在航空玻璃窗格上绘制按钮。

编辑:7月28日,Embarcadero的某人已经关闭了上述质检条目,这是一个错误。我敦促他们重新打开它,如果只是为了澄清这是否确实是常见控件DLL中的Windows错误。

如果你想玩弄,从StdCtrls复制TButton和TCustomButton类的VCL源代码,就像我在这里所做的那样,修改CNCtlColorBtn,以便强制执行三件事之一 - PerformEraseBackground, DrawParentBackground或继承,并查看结果。有趣的东西。

procedure TCustomGlassButton.CNCtlColorBtn(var Message: TWMCtlColorBtn); 
begin 
    PerformEraseBackground(Self, Message.ChildDC); 
    Message.Result := GetStockObject(NULL_BRUSH); 
(* 
    with ThemeServices do 
    if ThemesEnabled then 
    begin 
     if (Parent <> nil) and Parent.DoubleBuffered then 
     PerformEraseBackground(Self, Message.ChildDC) 
     else 
     DrawParentBackground(Handle, Message.ChildDC, nil, False); 
     { Return an empty brush to prevent Windows from overpainting we just have created. } 
     Message.Result := GetStockObject(NULL_BRUSH); 
    end 
    else 

     inherited; 
    *) 
end; 

Some interesting reading on Vista era glass/DWM/aero APIs (C++ developers blog)

1

Here我提供了一些代码,使TButton的期待权上的玻璃。不幸的是,它使形式“点击投掷”,所以我不认为这是一个好主意。但是,也许你可以找到一种方法来修复表单的“点击”。

0

如果你能够使用win32 api,试着利用NM_CUSTOMDRAW通知(不是ownerdraw),就像我一样(是的,按钮发送它,包括收音机和复选框,但最好使用WM_CTLCOLORSTATIC)。这是如何在C++中完成的,但这个想法是一样的。虽然我的想法很好,但偶尔我的按钮在程序执行过程中从窗口执行DISAPPEAR一次,当它们是customdrawn时,我需要将鼠标悬停在它们上方,以便它们再次可见。这就是为什么我仍然在为此寻找意见。请注意,在单一形式的应用程序中重现消失的按钮非常困难。我在每个项目中都经历过这种行为。

case WM_NOTIFY: 
    switch(((LPNMHDR)lParam)->code){ 
    case NM_CUSTOMDRAW: 
    { 
     NMHDR *nmh=(NMHDR*)lParam; 
     //these 6000 through 6004 are button identifiers assigned by me 
     if(nmh->idFrom >= 6000 && nmh->idFrom <= 6004){ 
     switch(((LPNMCUSTOMDRAW)nmh)->dwDrawStage){ 
      case CDDS_PREERASE: 
      //BackgroundBrush is a HBRUSH used also as window background 
      FillRect(((LPNMCUSTOMDRAW)nmh)->hdc, &((LPNMCUSTOMDRAW)nmh)->rc, BackgroundBrush); 
      break; 
     } 
    } 
    break; 
} 
break;