I am looking for a Delphi button designed to use with Aero Glass running Vista and Windows 7, with the following properties:
completely self-drawn TCustomControl descendant.
looks good [ renders in a way that looks to the user like a normal button, with no glitches ] over a Glass pane with Aero composition (DWM), no white or black ring around the button, and no problems with the caption getting messed up by Aero composition. (This will knock out any button that has not been written to be glass aware.)
The usual features of a TButton/TBitButton, including link to TActions, support for a glyph (bitmap/picture), etc.
Optional, nice to have features:
Transparency support (optional, it would be nice if it could be opaque but draw cleanly over glass).
I can throw TRzButton from Raize Components into the ring. The form should have DoubleBuffered set to true to make the labels visible, but the button must have DoubleBuffered switched off to remove the unwanted frame.
You can also use TRzBitBtn if a glyph is required. As an alternative TPngBitBtn from PngComponents will also qualify.
Related
I have a form filled with a TImage. I put over this a TGridPanel. If themes are enabled in Windows 7 the TGirdPanel appears with transparency. If themes are disabled (no visual styles) the TGridPanel loses transparency and hides the part it ocupies. I use Delphi XE2
Is there any workaround for this?
That's a basic fact of life for panels. It's not special to the TGridPanel, you will see the same effect for any control derived from TCustomPanel. The transparency is only supported when the application is themed.
The grid panel is just a convenient way to layout your controls. If you want to support running unthemed then the simplest solution is to remove the TGridPanel and layout your controls manually. That's pretty much trivial to do. Handle the OnResize event of the control that currently contains the panel, and position your controls as desired.
I'm working on a Windows Deskband in Delphi XE2 for Windows XP, Vista and 7 (Win32 and Win64)...
I've implemented all the necessary interfaces (ITrayDeskBand, IDeskBandInfo, IDeskBand2, IDeskBand) in my code, and that all works exactly as it should (there are no warnings on Vista/7 complaining about compatibility as others have experienced).
The problem I have is that my Deskband Form appears with a non-transparent band. Also, only certain Controls are displaying (in this case TBitBtn and TImage containing a PNG). I need it to display TEdit and TComboBox objects properly too, but they won't appear at all.
I've tried enabling GlassFrame and SheetOfGlass properties on my Form, but this doesn't help one bit.
Furthermore, the Form itself is exceeding the top boundary of the Taskbar, meaning you cannot (for example) resize the Taskbar if the cursor is in-line with the top of the Taskbar immediately above my Deskband.
I believe there is something Delphi's VCL TForm type is doing behind the scenes which renders the TForm type incompatible as a Deskband container... but this is just a suspicion.
Here's a screenshot illustrating the various problems:
As you can see (above), the Deskband's Form is pale (instead of Transparent), it overlaps the top of the Taskbar (preventing resizing and Autohide triggering when the Taskbar is "hidden")
Any ideas?
UPDATE 1
Okay, I have been playing around and noticed that a totally different behaviour is observed when creating a TToolBar control to be used for the Deskband, rather than a form:
Notice there are three TToolButton controls (with their text virtually invisible due to the Glass theme)? There should also be a TEdit and TComboBox between two separators, but these refuse to display at all.
Also notice the artefacting (the repetition of actual Taskbar Icons)?
I'm not sure if this is a step in the right direction or not, but it might help you (or others) to deduce a solution!
Okay... I've finally figured this out, and it is the most absurd thing I've ever come across.
I'm posting my findings here for the benefit of others (to save you going through the nuisance I've just been through).
To get all of the controls on your Deskband Form to display and function properly, simply set the Visible property of your Form (in the IDE designer) to True.
Ridiculous, I know, but it works and is easily repeatable.
It was recently brought to my attention that one of our applications paints incorrectly on non-themed Windows.
Toolbar is built from TSpeedButtons nested in TToolbar which in turn lives inside a page control.
On themed Windows everything looks nice. Well, not nice, but ok.
On non-themed Windows, however, weird vertical lines appear inside buttons.
I've searched around but cannot find any report of such a problem. (Most probably just my search kung fu sucks.) Does anybody know of a description of this problem or, even better, a fix?
TToolbar isn't designed to hold TSpeedButtons. It's designed to hold TToolButtons, which are made to not only sit on a TToolBar, but are specially written to behave correctly on the bar.
The issue you're having (particularly with the separators being drawn the way they are) is because you're using the incompatible TSpeedButton and separating them with TToolButton separatorss. TSpeedButton works well on a TPanel, and IIRC were designed for just that prior to MS providing the TToolBar/TToolButton pair in ComCtl.
A quick test app with both a TToolBar with TToolButtons and a TPanel with TSpeedButtons should see if this solves the problem.
EDIT: Your comment isn't quite correct. :)
Set the TToolBar.AllowTextButtons to True, and then set the button's you want wider to style tbsTextButton. As you can see, I've used a plain button, a separator, a text button (with text and image), a separator, and another plain button.
As TOndrej said in comments, this happens when TSpeedButton.Flat and .Transparent are both set to True. As David found out, TToolbar must also have .Flat set to True for the problem to occur.
A workaround that doesn't require changing the VCL source code is to set .Transparent to False.
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.
I tried various combinations of DoubleBuffered and a few combinations of placing the controls on other controls first, but the problem remains. Any ideas?
If no one has a clean solution, as a workaround use TBitBtn with DoubleBuffered = false.
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)
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".
if you are able to use win32 api, try exploiting NM_CUSTOMDRAW notification (not ownerdraw), as i do (yes, buttons DO send it, including radio and checkboxes. For these it is best to use WM_CTLCOLORSTATIC though.). This is how it is done in C++, but the idea is the same. While my idea is good, it so happens that my buttons do DISAPPEAR once per program execution from the window, when they are customdrawn and i need to hover mouse over them so they are visible again. That's why i'm still looking for comments for this. Note that it is really difficult to reproduce disappearing buttons in one-form applications. I hovewer am experiencing this behaviour in every project.
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;
With Delphi 7 trying to change the color of the title bar of the software from the window theme. I have seen code which allows you to change ALL the title bars of all programs, but I am just wanting to change my program.
Anyone seen/done anything like this? Don't mind paying for a component if needed.
I believe Windows sends the WM_NCPAINT message to an application when it should paint the window frame including the title bar. The default behaviour is to fall back to the default Windows handler which draws the default frame. You could replace this, or re-paint the title-bar section right after.
This looks like a good example: http://delphi.about.com/od/adptips2006/qt/draw_captionbar.htm
The answer by Stijn is not fully complete, as the caption and border of the window will also be redrawn when it is (de-)activated. So in addition to WM_NCPAINT you will also need to handle WM_NCACTIVATE. Unfortunately this can not simply be replaced, as there is other code in the default message handler (apart from drawing code) that needs to be executed. But calling the default handler will in turn lead to the default caption and border being drawn first, which you would then need to draw over with your intended colour, resulting in flicker.
One way to work around this is to adjust the drawing region that the default message handler is called with. See "Drawing titlebar on XP with themes" for an example using Windows API calls that should easily translate to Delphi. Note that this deals only with the text in the caption bar, but the principle applies.
You might take a look at a skinning library. ExpressSkin by DevExpress is a good one.