如果没有一个干净的解决方案,可以使用 TBitBtn
并将 DoubleBuffered = false
作为一种解决方法。
DoubleBuffered
属性设置为False
是解决许多问题的方法! - David Heffernanprocedure 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;
这里我提供了一些代码,可以让TButton在玻璃效果下看起来很好。不幸的是,它会使窗体出现“点击抛出”的问题,所以我认为这不是一个好主意。但也许你可以找到一种方法来解决窗体的“点击抛出”问题。
如果您能够使用Win32 API,请尝试利用NM_CUSTOMDRAW通知(而不是ownerdraw),就像我一样(是的,按钮会发送它,包括单选框和复选框。对于这些控件最好使用WM_CTLCOLORSTATIC)。这是C++中的实现方式,但思路是相同的。虽然我的想法很好,但恰巧在程序执行期间,我的按钮会从窗口中消失一次,并且我需要将鼠标悬停在它们上面才能再次看到它们。这就是为什么我仍在寻找有关此问题的评论。请注意,在单窗体应用程序中很难重现按钮消失的情况。然而,我在每个项目中都遇到了这种行为。
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;