Home Utility class for activating external VCL Style files in Delphi
Post
Cancel

Utility class for activating external VCL Style files in Delphi

The VCL Styles feature in Delphi has seen major improvements as of late, including High DPI and 4K monitors in RAD Studio 10.4 Sydney. It seems like a rather niche feature for many Delphi developers, but it has strong potential now that most of the quirks have been worked out. They were first introduced way back in Delphi XE2 in 2011. (See a VCL Styles overview video on YouTube from the XE2 release.)

You can embed styles in your executable within the Project Options->Application->Appearance configuration screen. If you would rather keep your executable smaller, you can also ship styles in separate .vsf files and load the styles dynamically. I was doing this task with a few executables and decided to put together a simple class to reduce the small bit of duplicate code. The source is available in the iaLib GitHub repository.

The TiaVCLStyleManager class interface section follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  /// <summary>
  /// Typical usage is to populate a combo box within the form's OnCreate event via:  TiaVCLStyleManager.PopulateStyleList(cboYourComboBox.Items);
  /// And then set the combo's "OnChange" event to call:  TiaVCLStyleManager.HandleSelectionChange(xx
  /// </summary>
  TiaVCLStyleManager = class
  private const
    defSubdirectoryName = 'Themes';
  private
    class var fStyleFileList:TiaVCLStyleFileList;
    class var fStyleSearchPath:string;
    class var fStyleSearchSpec:string;
    class function GetVCLStyleFileList():TiaVCLStyleFileList; static;
  public
    class constructor CreateClass();
    class destructor DestroyClass();

    // main methods for end user selecting from a list of styles
    class procedure HandleSelectionChange(const pStyleList:TStrings; const pItemIndex:Integer);
    class procedure PopulateStyleList(const pDestinationList:TStrings; const pListSystemStyleFirst:Boolean = True);

    // support
    class function IsStyleLoaded(const pStyleName:string):Boolean;
    class function TrySetStyleFile(const pStyleFile:TiaVCLStyleFile; const pShowErrorDialog:Boolean = True):Boolean;

    // customizations
    class property StyleFileList:TiaVCLStyleFileList read GetVCLStyleFileList write fStyleFileList;
    class property StyleSearchPath:string read fStyleSearchPath write fStyleSearchPath;
    class property StyleSearchSpec:string read fStyleSearchSpec write fStyleSearchSpec;
  end;

This support class is designed to look for *.vsf files in a folder and allow you to populate a TStrings list (as used by TComboBox or TListBox) with a list of available styles for a user to select from. The list will include the system default style (“Windows”), any embedded styles, and all the *.vsf files found. The external styles are only loaded once they are set by the user.

There is a simple demo available in the same repo. Below is a screen shot of the main form:

VCL Styles manager screenshot

Below is the source from the demo form:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
procedure TDemoForm.FormCreate(Sender:TObject);
begin
  ReportMemoryLeaksOnShutdown := True;

  // Customize path to style files (if needed) before populating the list
  // Search path defaults to IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + 'Themes'
  // A 'VCLStyles' directory was added to the root folder in this GitHub repo
  TiaVCLStyleManager.StyleSearchPath := '..\..\..\..\VCLStyles';

  PopulateStyleLists();
end;


procedure TDemoForm.ResetSelection();
begin
  // simply keeps the two lists in-sync
  cboStyle.ItemIndex := cboStyle.Items.IndexOf(TStyleManager.ActiveStyle.Name);
  lstStyle.ItemIndex := lstStyle.Items.IndexOf(TStyleManager.ActiveStyle.Name);
end;


procedure TDemoForm.PopulateStyleLists();
begin
  // demo ComboBox usage
  TiaVCLStyleManager.PopulateStyleList(cboStyle.Items);

  // demo ListBox usage
  TiaVCLStyleManager.PopulateStyleList(lstStyle.Items);

  ResetSelection();
end;


procedure TDemoForm.cboStyleChange(Sender:TObject);
begin
  // demo ComboBox usage
  TiaVCLStyleManager.HandleSelectionChange(cboStyle.Items, cboStyle.ItemIndex);
  ResetSelection();
end;


procedure TDemoForm.lstStyleClick(Sender:TObject);
begin
  // demo ListBox usage
  TiaVCLStyleManager.HandleSelectionChange(lstStyle.Items, lstStyle.ItemIndex);
  ResetSelection();
end;


procedure TDemoForm.Exit1Click(Sender:TObject);
begin
  Close;
end;

You can see that when the form is created, the StyleSearchPath is customized. By default, the search path is set to a Themes subdirectory based on the executable’s file path. I have included the VCL styles from 10.4 Sydney’s redistributable folder in the VCLStyles folder within the GitHub repository, so I am specifying this custom directory in the FormCreate event.

I have included both a TComboBox and a TListBox in the demo form and those lists of styles are populated by calling the TiaVCLStyleManager.PopulateStyleList method. My preference is to list the “Windows” system style first in the list, while having the rest of the styles sorted alphabetically. You can override this behavior by passing an optional parameter in this method.

When a VCL style is selected by the user, the style is activated via the TiaVCLStyleManager.HandleSelectionChange method. Simply pass in the list from the control and the ItemIndex and the style will be loaded from disk if needed and the style activated.

By including this unit in your project, you can allow user-selectable styles with little code. Simply customize the StyleSearchPath, call the PopulateStyleList and then respond to the user’s selection with the HandleSelectionChange method. To be honest, it is fairly easy to do without using this class, but if you find yourself cutting-n-pasting the same bit of code into separate projects then it really should be refactored into a stand-alone class. If you have not completed that task yet, then you may want to clone the iaLib repo and check out the demo project. If you always embed your VCL styles within your project, then you may not see much benefit from this utility class.

If you would like to see this small utility class expanded in some way, simply let me know and I will see what I can do as I plan on spending more time with VCL Styles in the near future. If you have not used VCL Styles in a while, then perhaps you should take another look. There were a few major issues that prevented me from using this feature in the past, but as of 10.4 Sydney all of my blocking issues seem to have been corrected and the feature has greatly matured. However, after looking through Quality Portal, we may need to wait for a patch or two to address a few new items:

If you have any other blocking issues, I would like to hear about them! Please reach out today!