^ Delphi VCL styles tips

Delphi VCL styles tips

List available styles in a combobox

To list available styles in a combobox:
Uses
    Vcl.Themes,
    Vcl.Styles;

procedure TForm1.ListAvailableStyles(ComboBox: TComboBox);
var
    S: String;
begin
    ComboBox.Items.BeginUpdate;
    try
        ComboBox.Items.Clear;
        for S in TStyleManager.StyleNames do begin
            ComboBox.Items.Add(s);
        end;
        ComboBox.Sorted := True;
        // Select the style that's currently in use in the combobox
        ComboBox.ItemIndex := ComboBox.Items.IndexOf(TStyleManager.ActiveStyle.Name);
    finally
        ComboBox.Items.EndUpdate;
    end;
end;

Disable styles for a specific class

To disable styling for a specific class, for a specific window for example, register the default style hook class ('TStyleHook') for it:
interface

Uses
    Vcl.Themes,
    Vcl.Styles;

type
    TMyForm = class(TForm)
        ...
    end;

Implementation

    ...

Initialization

    TStyleManager.Engine.RegisterStyleHook(TMyForm, TStyleHook);

end.
TMyForm will not be styled from now on.


Fixing the TListView flickering issue when VCL styles are enabled

To fix the flickering when changing the content of a list view disable the drawing of the client area and set the listview's background color by code:
Uses
    Vcl.Themes,
    Vcl.Styles;

procedure FixTListViewStyled(ListView: TListView);
var
    BackgroundColor: TColor;
    LStyle: TCustomStyleServices;
begin
    //* Default value
    BackgroundColor := clWindow;
    LStyle := StyleServices;
    if LStyle.Enabled
    AND (TStyleManager.ActiveStyle.Name <> 'Windows')
    then begin
        BackgroundColor := TStyleManager.ActiveStyle.GetStyleColor(scListView);
    end;
    ListView.StyleElements := ListView.StyleElements - [seClient];
    ListView.DoubleBuffered := True;
    ListView.Color := BackgroundColor;
end;

Fixing the TForm bsSingle and bsDialog size issue when VCL styles are enabled

unit FixFormsWhenStyled;

interface

Uses
    Messages,
    Forms;

type
    TFixedFormStyleHook = class(TFormStyleHook)
    strict protected
        procedure WndProc(var Message: TMessage); override;
    end;

implementation

Uses
    SysUtils,
    Windows,
    Vcl.Themes,
    Vcl.Styles;

{ TFixedFormStyleHook }

procedure TFixedFormStyleHook.WndProc(var Message: TMessage);
var
    ncParams: NCCALCSIZE_PARAMS;
    newMsg: TMessage;
begin
    if (Message.Msg = WM_NCCALCSIZE)
    AND (Message.WParam = 0)
    then begin
            // Convert message to format with WPARAM == TRUE due to VCL styles
            // failure to handle it when WPARAM == FALSE.
            Message.WParam := 1;
            inherited WndProc(Message);
    end else begin
        inherited;
    end;
end;

Initialization

    TCustomStyleEngine.RegisterStyleHook(TForm, TFixedFormStyleHook);
    TCustomStyleEngine.RegisterStyleHook(TCustomForm, TFixedFormStyleHook);

end.

Using styles in app. and in a .dll at the same time

It's possible to use both in the main application and in a loaded .dll (for example a plugin) styles at the same time.
To have this working the .dll needs not to set styles on menus, as the main application already hooks the drawing of menus. Somewhere in the .dll disable menu styles before applying a style, for example in the DLLPROC or add an 'Initialization' section:
Uses
    Vcl.Themes,
    Vcl.Styles,
    VCL.SysStyles; // to gain access to TSysPopupStyleHook;

Initialization

    TStyleManager.SystemHooks := TStyleManager.SystemHooks - [shMenus];
    TCustomStyleEngine.UnRegisterSysStyleHook('#32768', TSysPopupStyleHook);

end.
If the .dll is loading a .vsf style file that it gets as a parameter from the application, there might be a problem if you want to load a style file that is already loaded as this generates an exception. To avoid this parse the style name and catch the exception in case:
procedure SetStyleByApp(StyleNameOrFileName: String);
var
    StyleInfo: TStyleInfo;
begin
    if FileExists(StyleNameOrFileName) then begin
        if TStyleManager.IsValidStyle(StyleNameOrFileName, StyleInfo) then begin
            try
                TStyleManager.LoadFromFile(StyleNameOrFileName);
            except
                //* Style already loaded or not valid
            end;
            TStyleManager.TrySetStyle(StyleInfo.Name);
        end;
    end else begin
        TStyleManager.TrySetStyle(StyleNameOrFileName);
    end;
end;

Integrating style files as resources in a .dll that has styles enabled

Delphi (as of XE7) does not have option to include the style files in the .dll itself. Here's how to do it with resources:
  • Using XN Resource Editor, right click on the left panel of the window and in the pop-up menu select 'Import User Resource'.
  • Select the style file you want to include from 'C:\Program Files (x86)\Embarcadero\Studio\15.0\Redist\styles\vcl\'
  • The new resource should appear on the left, click on 'VSF', presss F2 and change it to 'VCLSTYLE'
  • Repet the above until all the styles needed are added
  • Save the new resource package with menu: 'File/Save As...' for example 'VCLStyles.res'
  • In Delphi include this .res file with adding '{$R VCLStyles.res}' for example after '{$R *.res}' (the .res file should be in the project folder)
  • Build the .dll - Delphi will now automatically load/list the included styles automatically and they are ready to apply them with 'TStyleManager.TrySetStyle(StyleName);'


If you found the above information useful, check my components.


[Top]