Modern versions of Microsoft Windows are arguably a lot more pleasing to look at. Gone are the days of apps being gray slabs and chunky buttons. When Microsoft adopted the Fluent UI interface, along with it came a richer color palette, a cleaner, leaner look, and fonts without the curls and twists of the Serif families. Sidling in with that beauty treatment were a number of other usability and user convenience facets of being a modern app for us to consider: high DPI, notifications, and themes designed to cater for a âlightâ and âdarkâ mode. Windows App Development Tools like Rad Studio help you Modernize VCL apps for Windows 11 with new user interface controls, WinRT APIs, and High dpi support.
Table of Contents
High DPI in your apps
RAD Studio Delphi already handles the high DPI changes. If you right click on your project in the IDE and select âpropertiesâ and then click on the âmanifestâ section you should see it say âper monitor v2â. Having this section ticked lets Windows know that your app (actually the VCL in your app) understands the high DPI â screen resolution pixels â and contains assets and API handling to work with it. There is a substantial amount of work going on behind the scenes in the VCL runtime when the per monitor v2 setting is enabled, which it is by default, but for ordinary mortals like you and I we donât get to worry about any of that; it just works.
If you compare a program compiled with an older version of a compiler which doesnât understand per monitor v2 you should notice that things on higher resolution monitors can look a little fuzzy. Thatâs because that manifest file setting is not there and the internal API calls are older âbackwardly compatibleâ ones which work using the lowest common denominator, resulting in the app not making the best use of modern display technology. Itâs a bit like watching a 1970s movie on a 4K OLED TV â bearable, but it looksâŠdated.
What isnât covered by the latest VCL?
The other major visible change ushered in by Windows 10 was the introduction of a âdark modeâ. For years weâve all really been running Windows with almost the only choice available â white backgrounds, gray buttons and some colors dotted around to relieve the glare. Then, Microsoft brought out a âdark modeâ. This dark mode turns all the Windows assets, dark (itâs well named!) and this is a setting that your apps are expected to both understand and react to. Currently this is an area where the VCL has not quite got covered for us.
Detecting dark mode
When your app launches it should try and detect whether Windows is currently expecting you to be âin dark modeâ or âlight modeâ. This is currently handled by a set of API calls for which we do not currently have support in the VCL. Luckily, thereâs a registry key we can check.
When our app detects that it should be âdarkâ then we should tell our Delphi app to load an appropriate âdarkâ theme. Conversely, if Windows indicates we are expecting âlight modeâ then a similarly appropriate light-colored VCL theme should be loaded.
How to detect dark mode in your VCL apps the easy way
It wouldnât be Delphi if there wasnât an easy way to do all the hard work. So I wrote a little unit you can include in your VCL Delphi programs to easily detect Windows dark or light mode and to load the correct theme for you â and of course itâs free and open source.
Find out how to enable Developer Mode on Chromebook in this step-by-step article.
Getting The Delphi Dark Mode Unit
Go to my GitHub repository here: https://github.com/checkdigits/delphidarkmode
And clone it to your local machine.
In your application select “Add to Project” (shift + F11) and navigate to where you cloned the DelphiDarkMode
unit.
You can read more about the DelphiDarkMode unit and Windows Dark Mode in general in my blog post from CodeRage here: https://www.codedotshow.com/blog/coderage-2019-vcl-the-dark-side/
Using Delphi Dark Mode to automatically change your Delphi theme
The first thing you need to do is choose and apply two VCL themes to your app.
Go to the project, options dialog and pick âappearanceâ.
Now check on two themes, one for the âlight modeâ and one for the âdark modeâ. Note down the exact names of the themes because you will need them in a moment.
I chose âWindows10
â and âWindows10 Dark
â. There are MANY gorgeous VCL themes to pick from and you can use the GetIt package manager to install and apply dozens of other professionally-designed custom themes as well as a staggering array from the superb Delphi Styles site found here https://www.delphistyles.com/vcl/index.html
Go back to your program and add the following code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// ... add to your form's definition private procedure HandleThemes; end; uses WindowsDarkMode; procedure TForm1.FormCreate(Sender: TObject); begin HandleThemes; end; procedure TForm1.HandleThemes; begin SetAppropriateThemeMode('Windows10 Dark', 'Windows10'); end; |
Now try running your program. You should find if Windows is set to dark mode then your app will use the âWindows10 Dark
â theme and if Windows is in light mode then it will use the lighter âWindows10
â theme.
You can replace those two themes with anything you like â the only caveat is that the theme must already be applied as a possible theme by putting a tick against its name in the appearance section.
Detecting when Windows changes to dark or light mode while the app is running
So, what happens if our app is already running and the user changes from light mode to dark mode or vice versa? Well, Windows broadcasts a WM_SETTINGSCHANGE
message to all top-level Windows of running apps. The âsectionâ parameter of this message is âImmersiveColorSet
â. If we test for the arrival of the WM_SETTINGSCHANGE
message and look for that parameter we know that the user has changed the Windows theme from light to dark or dark to light mode.
Adding code to detect a Windows dark or light mode change
Add the following code to your main formâs definition:
1 |
procedure WMSettingChange(var Message: TWMSettingChange); message WM_SETTINGCHANGE; |
Now in the implementation section put:
1 2 3 4 5 6 |
procedure TForm1.WMSettingChange(var Message: TWMSettingChange); begin if SameText('ImmersiveColorSet', String(Message.Section)) then HandleThemes; end; |
Here it is in action in my sample app
Alternatives
As is typical with RAD Studio Delphi there is more than one way to detect the Windows settings change message.
You can use the TApplicationEvents
control. Add code to the OnSettingsChange
event handler like so:
And then add this code to the event
1 2 3 4 5 6 7 8 9 |
procedure TForm1.ApplicationEvents1SettingChange(Sender: TObject; Flag: Integer; const Section: string; var Result: Integer); begin if SameText('ImmersiveColorSet', String(Section)) then HandleThemes; end; |
You can obviously create this control dynamically too. Personally itâs easier for me to just trap the WMSettingChange
message as Iâve shown in my example.
The whole code to detect Windows Dark Mode in VCL apps
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 |
type TForm1 = class(TForm) Image1: TImage; procedure FormCreate(Sender: TObject); private procedure WMSettingChange(var Message: TWMSettingChange); message WM_SETTINGCHANGE; procedure HandleThemes; end; var Form1: TForm1; implementation {$R *.dfm} uses WindowsDarkMode; procedure TForm1.FormCreate(Sender: TObject); begin HandleThemes; end; procedure TForm1.HandleThemes; begin SetAppropriateThemeMode('Windows10 Dark', 'Windows10'); end; procedure TForm1.WMSettingChange(var Message: TWMSettingChange); begin if SameText('ImmersiveColorSet', String(Message.Section)) then HandleThemes; end; |
More on themes
Thereâs a lot more to properly handling theme changes. For example there are settings for the theme âaccent color
â which your app should probably detect and use where possible. There are also settings for border colors and when the theme changes you should also manage older controls which are not âtheme awareâ and therefore do not get repainted with the correct values when the VCL theme changes. Overall though, detecting dark and light mode is really the largest part of making your apps look more like the belong on Windows 10.
What about Dark Mode in Firemonkey?
Detecting Dark Mode cross platform is a little more complicated. On iOS Firemonkey already deals with this for you. Android, macOS and Linux are more tricky – especially Linux. The code shown in this article deals exclusively with Windows and it can be adapted to load FMX styles but messaging in Firemonkey apps is a little different in general anyway.
Learn about the advantages of implementing Chromebook Developer Mode.
Design. Code. Compile. Deploy.
Start Free Trial   Upgrade Today
   Free Delphi Community Edition   Free C++Builder Community Edition