Jump to content
corneliusdavid

SetStyle overloads are not compatible

Recommended Posts

I've got a Delphi 12.1 VCL application where, by default, there is no style applied. If the user wants, they can switch to a dark mode at which point, I load a pre-selected .vsf file and all is good. If the user wants to switch back, I simply set the style to 'Windows' and it switches back to the default style. It all still works.

 

Because there will be several programs with this same functionality and option, I don't store the style file in the application but load it dynamically at runtime. And if, down the road, I want to replace the style file with a different one, I can  because it's named simply "DarkMode.vsf" even though the internal style name could be "CopperDark" or "Windows10 BlackPearl" for example. With the overloaded TStyleManager.SetStyle procedure that can take either a string (the style name) or a TStyleServicesHandle (returned from LoadFromFile), I figured I could use either one interchangeably; therefore, it's simplest in my code to refer to the loaded file by its handle and not it's name but when changing back to the default style, I simply use the standard 'Windows' string name, leading to these procedures:

procedure TMainForm.LoadThemeFiles;
begin
  // save handle to dark style for later 
  FDarkStyleServicesHandle := TStyleManager.LoadFromFile(TPath.Combine(ThemePath, 'DarkMode.vsf'));  
end;
procedure TsMainForm.SetDarkTheme;
begin
  TStyleManager.SetStyle(FDarkStyleServicesHandle);
end;
procedure TcssMainForm.ClearTheme;
begin
  TStyleManager.SetStyle('Windows');
end;

However, I found that once SetDarkTheme has been called followed by ClearTheme, SetDarkTheme will no longer work (as in the case the user switches DarkMode off then tries to turn it back on). I've attached a small program to demonstrate this; I've tried it in both Delphi 11.3 and 12.1.

 

I've submitted a bug report but also have a work-around. Since SetStyle(string-name) works consistently, I've changed the LoadThemeFiles procedure to get and save the name of the style. The TStyleManager has a list of all registered style names, including 'Windows' so if I load one style, TStyleManager should have two style names:

procedure TsMainForm.LoadThemeFiles;
var
  StyNames: TArray<string>;
begin
  TStyleManager.LoadFromFile(TPath.Combine(ThemePath, 'DarkMode.vsf'));
  StyNames := TStyleManager.StyleNames;
  
  // reminder not to load any styles into the project
  if Length(StyNames) > 2 then
    raise EProgrammerNotFound.Create('Styles should not be defined in the project!');
  
  for var sn in StyNames do
  begin
    if not SameText(sn, 'Windows') then
    begin
      // save the dark-mode style name
      FDarkStyleName := sn;
      Break;
    end;
  end;
end;

After that, the change to SetDarkMode procedure is pretty obvious:

procedure TcssMainForm.SetDarkTheme;
begin
  TStyleManager.SetStyle(FDarkStyleName);
end;

 

I looked at the VCL source for the two SetStyle procedures and the string version simply looks through the list of registered style names and calls the TStyleServicesHandle version.

 

So why does the first method fail?

VclStyleToggle.zip

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×