One of the features I had not touched is VCL Styling. I do not create applications for an industry where graphic design of your applications is key – usability is key. That mostly means: big buttons and the most important information visible at all times. Especially the last part is something you have to get used to. Because – let’s be honest – if you show a certain value ‘all the time’ the customer wants to be able to make changes ‘all the time’ as well…
As an aside, you might need more like 20 minutes to read this, but the 5-Minute-Snack has become somewhat of a moniker associated with my blog in the Delphi Community, so I do not want to change the number …
It has been one of the features that flew by me without it actually noticing. I always associated it with FireMonkey and not the VCL. Especially, as Third-party components deliver on styles and themes already. One of these examples is the TMS Skin Factory (link).
Still, I got curious as I am also preparing for the workshop on component development in May (link). Obviously, new components need to support VCL styling.
So I started off by creating a very simple application that would allow me to switch styles and the form would immediately display that style. I want to share this demo with you so that you can get a hold of styles with VCL as well — may be it is an area you have not touched yourself either.
That being said, let’s create a VCL Forms Application and drop the following components, aligning them as seen in the screenshot. Use Anchors if you want, I did not. If even changed the FormStyle to something that is not resizable:
- TComboBox : name it ‘cbStyles’ – the only mandatory component on the form. Set the st
- TRadioGroup with a few items
- TGroupBox with two TCheckBox
- TPageControl with a few tabs (TTabSheet )
As a test-case that styling is also possible for third party controls, I did add a TAdvStringGrid from TMS Software.
My demo application looks like this in the Delphi form designer:
In order to use VCL syling, we need to add the following unit to the uses-clause.
uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, // ... Vcl.Themes;
Something critical for a change: I have no idea why there is no proper unified terminology. The whole IDE uses the term ‘style’ and ‘custom styles’, but the unit uses the term ‘theme’. Definitely an oversight that might confuse people at first as in some component sets a style is part of a theme or a skin. For VCL applications the term style seems to be used as well as theme for the same thing.
Browsing into that unit gives us some very useful information right at the top:
type TThemedElement = ( // Windows styles teButton, // + teClock, // teComboBox, // + teDatePicker, // new teEdit, // + teExplorerBar, // teFlyOut, // new teHeader, // + teLink, // new teListView, // + teMenu, // + teMenuBand, // new teMonthCal, // new teNavigation, // new tePage, // teProgress, // + teRebar, // + teScrollBar, // + teSpin, // teStartPanel, // + teStatus, // teTab, // + teTaskBand, // teTaskBar, // + teTaskDialog, // new teTextStyle, // new teToolBar, // + teToolTip, // + teTrackBar, // teTrayNotify, // teTreeview, // + teWindow, // + // VCL extensions teCategoryButtons, teCategoryPanelGroup, teCheckListBox, teControlBar, teDataNavButtons, teGrid, teHint, tePanel, teTabSet, teTextLabel, teMPlayerButtons, teToggleSwitch, teSearchIndicators );
So we do know which controls support styles.
So you can add more controls to your form if you want to see how they are affected by the different styles. My form just shows a select few. The only key control is the combo box as that will list all the available styles and allow to switch the style.
This unit also defines a key class when working with styles: TStyleManager .
We can use it to get a list of all the styles that are available in the application and set the style to be used.
Do we need to use an object derived from TStyleManager ? No. All methods are defined as class methods.
So, in order to fill the ComboBox with values we use the following code in the FormCreate -event:
procedure TForm1.FormCreate(Sender: TObject); var style: string; begin // add all style names to combobox for style in TStyleManager.StyleNames do begin cbStyles.AddItem(style, nil); end; // set selection to current style cbStyles.ItemIndex := cbStyles.Items.IndexOf( TStyleManager.ActiveStyle.Name ); end;
Take note that we can iterate over the style names using a for-in-loop. Furthermore, we also set the current item to the name of the current style that can also be queried using the TStyleManager class.
The combobox will now be filled with the names of all the style. At least that is what one could think… Sadly, that is not the case. There is only one style in the list called ‘Windows’.
Delphi expects us to do one more thing. We need to tell the IDE which styles to add to our application. Thus, looking at the Project Options (Menu Project / Options…) under the section Application / Appearance we can clearly see that none of the custom styles are checked.
Let’s be crazy and check all of them! 🙂
I also set the default style to ‘Windows 10’.
And … the app is styled. We also see the list of all the checked styles in the ComboBox. However, changing the selection does not do anything right now. We will fix that with the following event handler for the OnChange -event of the ComboBox:
procedure TForm1.cbStylesChange(Sender: TObject); begin TStyleManager.SetStyle( cbStyles.Items[ cbStyles.ItemIndex ] ); end;
We can use the SetStyle method of TStyleManager and provide the name of the style to be used. This is actually just a string, i.e. every style is uniquely identified by a string that can be persisted in the application settings, for example.
Now, when we change the style, the form immediately changes its appearance:
The screenshot above shows the style called ‘Lavender Classico’.
Also note that the third-party control is nicely styled as well.
I have to be honest that the usage of styles with TStyleManager is much easier than I anticipated. Using the IDE Project Options to determine which styles are to be included is very comfortable as well. Extending your existing apps that use standard components or third-party controls that have been built with styling in mind is very easy to achieve as only a few lines of code need to be added. Persistence of the currently selected style is also very easy as we just need to remember a single string that needs to be reset when the application is restarted.