Change the selection opacity of a ListBox - delphi

I have trouble changing the selection opacity of the FireMonkey ListBox. In my case I wanted to change the color of the selection, and make it fully opaque. At first I tried to do this by changing the style of de ListBox through a custom style based on the default. The selection part is a TStyleObject with an opacity of 1. I replaced it with a TRectangle filled with the color Red. After I applied my style I noticed that the selection was not the same bright red color that I chose for the selection.
So I just dove into the FMX.ListBox code to see what is happening there. To my surprise I found that the opacity of the selection is set to 0.7 hard-coded in the TCustomListBox ApplyStyle procedure. I expected that the style was responsible for how things looked. I don't know if it's the wrong way to think about it, but this is not what I expected.
After this I tried changing the selection opacity run-time by implementing the OnApplyStyleLookup event with the following code.
procedure TForm1.ListBox1ApplyStyleLookup(Sender: TObject);
var
SelectionControl: TControl;
begin
if ListBox1.FindStyleResource<TControl>('selection', SelectionControl) then
SelectionControl.Opacity := 1;
end;
This however has no effect. I tried to do the same thing in a new custom ListBox control by deriving from TCustomListBox and overriding the ApplyStyle method where after the ApplyStyle of TCustomListBox through the inherited keyword I placed the code to set the selection opacity to 1. This too did not have any effect.
Am I just going about this the wrong way, am I missing something, or is it just Delphi being weird.

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.

How to cope with the bug with style lookup in controls nested in FMX Frames

I have met a bug in applying of StyleLookup in TTabControl nested in FMX Frame. The appearance of the control does not accept the style if the frame with the control is nested in a HorzScrollBox and at form creation the position of the frame is outside the visible area of the form. In other words if the control is visible when the form is shown the control is painted with necessary style appearance otherwise - not.
To reproduce the bug:
Create a new grid metropolis application.
Create a Frame and put a TTabControl on it. Set Align of the TabControl to alClient. Add, say, 4 TTabItems.
Open detail form, and set its width to a value > your Screen.Width (for me 2500 was enough).
Copy-paste any of the Columns (Layouts), say, 2 times and use the most right layout to nest a frame in it. You will see normal presentation of tabitems at designtime. Set style settings. You will get the following picture:
Done. Run the project. You will get the bug.
At runtime the appearance of TabItem is like this:
If you set the StyleLookup manually at runtime the appearance might either not change either be set to every other item (for example 1st, 3rd and not set to 2nd and 4th though you assign the same StyleLookup to all TabItems). The other interesting finding. If you have other forms containing TabControls with TabItems (nested without frames and closer to left border of the form) for example Form2, you get the following. If you show the faulty Form1 at runtime first you will see the bug, but if you close this form and show Form2 you see proper TabControl. Closing Form2 and showing Form1 (faulty) afterwards will give you a proper appearance of TabControl in a faulty form.
It has something in common with the bug reported by me earlier: Incorrect selection of items in an FMX TListbox (Grid Metropolis UI). It is still not fully solved.
There was also a question yesterday but it is about an exact problem with VCL Frames and the solution is not suitable for FMX.
Appended.
The way is to partially set the style is to set OnPainting event handler for TTabControl in the parent form unit (it does not work being set in frame unit) and write something like this:
procedure TPatientsScrollF.HMDiagnosisFr1TabControl2Painting(Sender: TObject;
Canvas: TCanvas; const ARect: TRectF);
var
i: byte;
begin
(Sender as TTabControl).StyleLookup := 'tabcontrolstyle';
for i := 0 to (Sender as TTabControl).TabCount-1 do
(Sender as TTabControl).Tabs[i].StyleLookup := 'tabitemstyle';
end;
But than you still get a problem - the Tabs are not drawn properly - see the lower edge of inactive Tabs.
Or even like this:
Appended 2
I have just met the bug appearing even at design-time after placing a frame in a form and assigning style to TabItems. The TabControl looks like in fig. 3.

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.

Firemonkey style inheritance?

I've just started with Firemonkey, and still have a lot to learn with regards to the usage of styles, but there is something I can't get figure out.
I've learned how to simulate a TListView using styles. So I've made a style which adds a progress bar to a list item, let's call this ListItemStyleProgressBar.
Now I'd like two ListView instances on my form, one where the font of the TListItem is red, and one where the font is blue. How to achieve this? Can I make an style which 'inherits' from ListItemStyleProgressBar (ListItemStyleProgressBarRed)?
Next to that, I'd like to be able to 'style' these two listview instances, so have a style which shows a light back and a style which shows a dark back.
What confuses me is it seems the styling is needed to add functionality (add a TProgressBar to a TListItem) as well as to do styling for this added functionality.
Can anyone tell me what I'm missing here?
No. There is no inheritance mechanism for styles. There are two ways to solve your problem:
1) Create two (or more) very similar styles to represent each 'look'.
2) Make the changes at run-time either with the OnApplyStyleLookup method or, if you have a custom control, by overriding the ApplyStyle method.
In the latter case you'll need something like this:
procedure TMyClass.ApplyStyle;
var O: TFMXObject;
begin
O := FindStyleResource('background');
if O is TRectangle then
TRectangle(O).Fill.Color := claRed;
end;

TPopupActionBar has no ColorMap property?

Ok, so I almost have a good looking UI, using TActionManager, TActionMainMenuBars and TToolBar with DrawingStyle as gradient to create a OfficeXP style interface.
I am using a couple of TPopupActionBar popup menus too, but I dont see a ColorMap property. I am using a ColorMap property to change the color of the default XP style color, and also changing the Hot Color of the TToolBar to match the menu.
I now need the TPopupActionBar popup menu to match the menu and toolbar, but how can I do this when I see no way of assigning a ColorMap to it?
Excuse me if this is non trivial, I have looked and cannot see. I also tried at runtime to assign a ColorMap but there doesnt seem to be the property for it?? I can change the Style of the TPopupActionBar, but cannot assign a ColorMap.
To assign a ColorMap you can use the OnGetControlClass event of the TPopupActionBar component , then check if the PopupMenu is not nil and finally assign the nested property ColorMap of this property.
check this sample.
procedure TFormMain.PopupActionBar1GetControlClass(Sender: TCustomActionBar;
AnItem: TActionClient; var ControlClass: TCustomActionControlClass);
begin
if Assigned(PopupActionBar1.PopupMenu) then
PopupActionBar1.PopupMenu.ColorMap:= TwilightColorMap1;
end;
check this image which contains a TPopupActionBar with the TwilightColorMap applied

Resources