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.
The usual technique is to play with form.DoubleBuffered, which I see you are already doing in code, so if it was that easy, I would think you would have solved it already.
I think one could also perhaps avoid any operation in the OnPaint other than a stretch-draw directly onto your paintbox.Canvas, from your offscreen bitmap. Anything else in OnPaint is a potentially flicker-inducing mistake. That means, no modification of the TBitmap from within the OnPaint. Let me say that a third time; Don't change state in paint events. Paint events should contain a "bitmap-blit" operation, GDI rectangle and line calls, etc, but nothing else.
I hesitate to recommend to anyone that they experiment with WM_SETREDRAW, but it is one technique people use. You can catch the move/resize window events or messages, and turn WM_SETREDRAW on/off, but this is SO fraught with complications and problems, that I don't recommend it. You can also call various Win32 functions to lock a window, and these are all highly dangerous and not recommended.
Best Answer
Setting
ParentBackground
toFalse
for components on the PageControl helped a lot. However this results in a different color of these panel components, they all have a darker background now. Maybe this can be fixed easily (without losing Theme support).I also installed VCL Fix Pack which has a fix for QC 56252 (TPageControl flickers a lot with active theming).