似乎唯一的解决方法是所有者绘制,或第三方按钮控件Check out the Glass Button by Roy Klever,或者,如下面链接的 QC 条目中所述,TBitBtn with DoubleBuffered=false,这是上面对这个问题的公认答案.
这是 Windows Aero DWM 中的一个错误,或者是 Windows 公共控件中的一个错误,或者是 VCL 类层次结构处理公共控件窗口消息和在玻璃上绘画时的绘画方式中的一个错误。简而言之,windows 常用控件无法在玻璃上正确绘制自己,或者更确切地说,DWM 组合 (Aero) 已损坏。惊喜惊喜。
标准 VCL 按钮组件使用 Windows 通用控件中的 Window 类 BUTTON。
注意TSpeedButton不使用windows常用控件,不存在这个问题。但是,它也不接受焦点。
Embarcadero 似乎知道这个问题,它是QC # 75246,它已被关闭,因为它确实是公共控件库中的一个错误,因为它不会修复,建议使用 TBitBtn。按钮并不孤单,它是一组 QC 报告的一部分,包括面板和其他常用控件。
但是,我有一个商业 TcxButton(开发人员快递组件的一部分),它接受键盘焦点,并且不会出现此故障。任何使用 Win32 通用控件按钮控件的代码似乎都存在此问题。低级别的 Win32 API 黑客可能会找到解决此问题的方法。我正在调查它。如果我弄清楚了,这个答案将被更新。
一个有趣的细节:TcxButton 有三种绘图样式,cxButton.LookAndFeel.Kind = {lfOffice11,lfFlat,lfStandard}。选择 lfOffice11 会重新添加此故障。这看起来像是 Vista/Win7 中 aero 中的玻璃功能与常见的 control/xptheme 按钮绘制代码之间的奇怪交互。
可能唯一的解决方法是使用完全由应用程序绘制的按钮控件,而不使用 Windows 通用控件按钮,或任何依赖 XP 主题引擎在航空玻璃窗格上绘制按钮的按钮控件。
编辑:7 月 28 日,Embarcadero 有人关闭了上述 QC 入口,这是一个错误。我敦促他们重新打开它,只是为了澄清这是否确实是公共控件 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)