TGraphicControl transparency on a TCustomControl - delphi

I created a control based on TGraphicControl that is transparent and mostly empty space. It actually implements a simple symbol in line art.
i.e. TLFMagicControl = class(TGraphicControl)
In the constructor which I have:
ControlStyle := ControlStyle + [csOpaque];
My "TLFMagicControl" is then placed on my own panel that is a TCustomControl.
i.e. TLFGridPanel = class(TCustomControl)
The transparency of the TLFMagicControl works perfectly interacting with each other but not with the parent panel they are on (TLFGridPanel).
The TLFGridPanel spends most of its time just black so its not an issue but I want to user to be able to turn on/off grid lines on the panel. When I override the paint handler TLFGridPanel and draw my grid the controls placed on top are not transparent and block the grid lines underneath.
Is there a way around this for a TCustomControl or have I chosen the wrong base for my panel?

csOpaque tells the VCL that you draw the control entirely by yourself, which supresses the automatic background drawing (or erasing). Remove that control style in order to let WM_ERASEBKGND do its work.

Related

Change TToolBar background color

I got a problem, that I can't normally change the background color (e.g. clwhite) of TToolBar with its property ToolBar.Color. I'm not very experienced in Delphi and I find out two possible solutions, but still I'd like to know, how to change it proper way or why it's not possible.
1) Change style to Gradient, but it also changes the basic animations for buttons.
ToolBar.DrawingStyle := dsGradient
ToolBar.GradientStartColor := clWhite
ToolBar.GradientEndColor := clWhite
2) Put TToolBar inside TPanel with the following settings.
Panel.Color := clwhite
ToolBar.Parent := Panel
ToolBar.Align := alClient
ToolBar.Transparent := True
By default a TToolbar ignores its Color property.
Also by default the Transparent property is true, therefore whatever the color of the Toolbar's parent is will shine through.
If you look at the VCL source code you'll see that TToolbar does not do its own drawing; it is a wrapper around the ToolbarWindow32 Win32 common control in ComCtl32.dll.
This is the code that does the drawing.
When Windows XP was introduced Microsoft added UI themes and Borland supported this via VCL.Themes.TStyleManager.
You can change the appearance of Common Controls through the style manager: Project -> Options -> Appearance -> Custom Styles, but its hard to know what effect this has, because the IDE does not display the result (you can see it at run time) and you can only choose from a limited list of rather odd themes; also the feature is buggy.
The same goes for TPageControl/TTabSheet which does not publish its Color propery.
All the controls imported via ComCtl32.dll and implemented by VCL.ComCtrls suffer from these inconsistencies.
In short
There is nothing you can do to make TToolbar respect its Color property.
You've already found the workarounds, either:
Set a gradient with identical GradientEndColor and GradientStartColor, or
Place the toolbar on another control (e.g. a TPanel) and change the color of that control, because the toolbar is transparent the parent color will shine through.
You'll need to set the panel's BevelInner/BevelOuter to bvNone, or
Enable VCL styles and suffer all the issues related with that corporate tickbox anti-pattern.

Paint TProgressBar behind text and icon in TSpeedButton

Is it possible to paint a TProgressBar on a TSpeedButton, behind text and icon ?
I have no idea how to get started on this (assuming it's possible).
How would I go about it ?
In this particular case I use the button to start and stop a process, and it would be nice to display the process in that button as well.
No, this is not possible with the standard TSpeedButton without creating your own descendant.
TSpeedButton does all of its drawing in response to the WM_PAINT message, and there is no way for you to inject another control behind the content that is drawn, because the drawing would erase the area where your control is drawing itself. You can see this yourself; you have the source code for TSpeedButton in almost every Delphi and C++ Builder version.
In addition, a TSpeedButton is a graphical control, not a windowed control (it derives from TGraphicControl instead of TWinControl), so it does not have a window handle to be used as the parent for other controls.

Draw an image instead of window caption

I need to do something which seems to be easy, but I'm searching for days with no success.
I have a window of fixed size (say 500*250) and need to replace the whole caption bar with a fixed size JPEG (or better PNG) image (say 500*25).
There are lots of samples talking about Glass, Aero, DWM, blah blah blah. But I just need to draw a fixed image!
I've already tried this, but it doesn't work:
procedure TForm1.Button1Click(Sender: TObject);
var
bmp:TBitmap;
DC:HDC;
begin
DC:=GetWindowDC(form1.Handle);
bmp:=tbitmap.Create;
bmp.SetSize(500, 25);
bmp.Canvas.TextOut(5,5,'Helloooooooooooooooooo');
BitBlt(dc,0,0,500,25,bmp.Canvas.Handle,0,0,SRCCOPY);
bmp.Free;
ReleaseDC(form1.Handle,DC);
end;
It should work both on XP and Vista/7. Please help.
P.S: I have Delphi XE.
You can do so by using VCL Styles.
You can change the appearance of the Windows caption bar like that by using the Delphi integrated Bitmap style designer to change a custom style and then use that Style in your application.
If you don't want to enforce the style to the whole application you can set the StyleElements property of the form to only include seBorder, this means that only the border aka caption of your application will be rendered using your custom style.
If you're working in Delphi XE2 then you won't be able to use the StyleElements property but that is just a minor obstacle, it just means that you will have to resort to using StyleHooks to implement the same behaviour and there is enough documentation on how to do that here.
Sadly, if your Delphi version is older then XE2 then you won't be able to use VCL Styles.
Another but rather unpleasant way would be to create a borderless form by changing the BorderStyle property to bsNone and then implementing your image in a way that it would act as a title bar, processing all actions made on the image and sending appropriate Messages to the application.
You can either:
Intercept the WM_NCPAINT message and custom-draw the caption bar manually.
Remove the caption bar altogether, by using SetWindowRgn() or overriding the CreateParams() method to remove the WS_CAPTION style, and then use the form's OnPaint event, or even a TImage, to display the graphic at the top of the form's remaining client area.
The simplest solution would be to use CreateParams() and TImage.

How to avoid image is Hidden by Button

I have kept an TImage component at the Top-right corner of a bitbutton.While loading of Form some part of image is Hidden by Button as like in image .How to avoid this.? and also tell me how to find corner of a Button such that i can place my image correctly to show notification correctly in case of Dynamically loaded buttons.
Yours Rakesh.
A TImage cannot be brought in front of a TBitButton since a BitButton is a windowed control (TWinControl). Instead of a TBitBtn or a TButton, you can use a control which does not descend from TWinControl, like a TSpeedButton.
The top-right corner of a button is at (Button.Left + Button.Width, Button.Top).
A TBitButton owns a window handle and only controls with an own window handle can be placed in front of it. You could place your bitmap on a TPanel (TPanel inherits from TWinControl and has a window handle), and this panel you can bring in front of any other control. Set the BorderStyle of the panel to bsNone, so it only works as a container and is not visible.
P.S. If your bitmap is as simple as the one in your example, you could directly write onto the panel and set the colors accordingly.

Avoid painting over nested controls

I am writing a toolbar-style control and use the ThemeServices unit to paint the background required by the toolbar. Like so:
ThemeServices.DrawElement(Canvas.Handle,
ThemeServices.GetElementDetails(trRebarRoot), ARect);
I then drop child controls onto the toolbar and voila - instant toolbar. Except that every now and again I notice that the nested (child) controls don't repaint as well. So my control paints its background and the child controls disappear until you move the mouse over them.
Some of the edit controls show their client area (no border) and some of them are just gone altogether.
This happens mostly when I place a window from another application over the toolbar and move it away.
I keep thinking this has to be very easy to cure, that perhaps I'm somehow preventing the paint message from reaching the child controls, or missing an override but I have been unable to figure it out.
For this to work properly so you do not end up over-painting the child controls from the WM_NCPaint, you can use the Window's GDI Region functions to create a clipping region which excludes the areas you do not want to paint.
You can do this by creating a Region using the CreateRectRgn (or similar) function with the size of your background.
Select this region in to the DC you are using via the SelectClipRgn function.
Next, loop through the top level child windows on your toolbar / panel and calling ExcludeClipRect with the appropriate coords for each child.
Finally when you paint, only the area's that have not been excluded will be painted.
Also be aware you might need to clear up your region (best check the GDI help).
That's normal for a canvas to have to repaint when covered by another windows control.
You should draw your tool bar in the OnPaint event of the container control.
OK, I found the problem myself. I was drawing the background in WM_NCPAINT because it is a gradiated background that cannot really be drawn bit by bit. I didn't realize that WM_NCPAINT is often called without the client controls being repainted. So I still paint the background in WM_NCPAINT but also in WM_PAINT. The latter is already clipped to exclude the border and to get the former to clip the client area, I called ExcludeClipRect.
This works like a treat.

Resources