Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi buttons show white border on Aero glass

I have been trying to find a good-looking design using Aero in Delphi 2010. One of the obvious uses one sees, is where the glass frame is extended to include the OK/Cancel buttons at the bottom of the screen. I notice though that this doesn't look quite right in Delphi 2010 - there is a white border all around each button.

This image shows the problem: the top 3 buttons are from my app, the bottom two were taken from Paint.NET's Layer Properties dialog.

White borders around Delphi controls

I tried various combinations of DoubleBuffered and a few combinations of placing the controls on other controls first, but the problem remains. Any ideas?

like image 813
Cobus Kruger Avatar asked Jul 26 '10 11:07

Cobus Kruger


3 Answers

If no one has a clean solution, as a workaround use TBitBtn with DoubleBuffered = false.

like image 149
Uwe Raabe Avatar answered Oct 25 '22 18:10

Uwe Raabe


It appears that the only workaround is owner-draw, or a third-party button control Check out the Glass Button by Roy Klever or, as stated in the QC entry linked below, TBitBtn with DoubleBuffered=false, which was the accepted answer above to this question.

This is a bug in Windows Aero DWM or else a bug in the windows common controls, or a bug in the way the VCL class hierachy handles common control window messages and painting when painting on glass. In short, windows common controls do not paint themselves properly on glass, or rather DWM composition (Aero) is broken. Surprise surprise.

The standard VCL button component uses the Window Class BUTTON from Windows Common Controls.

Note that TSpeedButton does not use the windows common control, and does not have this problem. however, it also does not accept focus.

It appears Embarcadero knows about this issue, it is QC # 75246, which is closed because it is really a bug in the common controls library, as Won't Fix, with the suggestion to use TBitBtn. Buttons are not alone, this is part of a group of QC reports including panels, and other common controls.

However I have a commercial TcxButton (part of developer express components) which accepts keyboard focus, and does not draw this glitch. Any code that uses the Win32 common control button control appears to have this problem. It may be possible that a low level Win32 API hacker might find a workaround for this. I am looking into it. This answer will be updated if I figure it out.

One interesting detail: TcxButton has three drawing styles, cxButton.LookAndFeel.Kind = {lfOffice11,lfFlat,lfStandard}. Selecting lfOffice11 adds this glitch back in. It looks like a strange interaction between the glass feature in aero in Vista/Win7 and the common control/xptheme button drawing code.

It may be that the only workaround is to use a completely app-drawn button control and to not use Windows common controls buttons, or any button control that relies upon the XP theme engine to draw buttons, on an aero glass pane.

Edit: July 28, someone at Embarcadero has closed the above QC Entry, which was a mistake. I am urging them to reopen it, if only to clarify if this is indeed a Windows bug in the common controls dll.

If you wish to play around, make a copy of the VCL source code for the TButton and TCustomButton classes from StdCtrls, as I have done here, modify CNCtlColorBtn, so that you force one of three things to happen - PerformEraseBackground, DrawParentBackground or inherited, and see the results. Interesting stuff.

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)

like image 37
Warren P Avatar answered Oct 25 '22 18:10

Warren P


Here I'm providing some code that makes TButton look right on Glass. Unfortunately it makes the form "click-throw", so I don't think it's a good idea. But maybe you can find a way to fix the form's "click-throw".

like image 24
Cosmin Prund Avatar answered Oct 25 '22 20:10

Cosmin Prund