Delphi XE High DPI Issues

One of my Delphi XE apps has a main form and several other image / video display forms. Those display forms are usually located on a non primary monitor. I set the position of the display forms using offsets from the required monitor’s left and top properties and this has worked well.

More recently I replaced my primary monitor with a 4K unit and set it to 150% so I can actually read stuff. The issue now is that all the display window coordinates are screwed up. XE doesn’t seem to deal with mixed monitors having different scaling factors.

Another issue is the form’s popup menu no longer shows on the form itself. It appears way off an another monitor or not at all.

I did try setting the display forms scaled property to false with no effect either way.

Is upgrading to the latest Delphi the only way forward?

1 Like

You would need to spend months hacking the VCL and third party libraries to solve high dpi issues in XE - the situation is better, but far from perfect in 10.4.2

I’ve been migrating from XE7 to 10.4.2 with the intention of supporting high dpi - and I’ve been working on this now for 9 months ( not full time but the majority). The trouble is when you hit an issue (of which there are many) - it takes time to investigate to see if the problem is in

  1. Your own code
  2. The VCL
  3. A third party control

I’ve given up on

Toolbar 2000/SpTBX - caused issues with other controls
TToolbar - Just completely broken - buttons don’t size properly, the tool bar flickers like crazy during resize.

I created a new Toolbar component based off the Raize one to deal with high dpi (and cut out all the old legacy styling issues) - fortunately Ray designed a really good toolbar.

I’m having issues major with Menus not scaling images properly (seems to be something wrong with detecting which screen it’s on). Debugging this is proving difficult ans the acto of debugging changes the behavior :roll_eyes:

I’ve fixed a few issues with VirtualTreeView recently (we use it extensively) and a few other controls,

I also wasted a lot of time switching from using bitmaps/png’s to svg - and switching back to png’s - the svg’s just don’t render as sharp I would like when resized. This post explains the problem better than I can

If you use VCL Styles then the whole HighDPI issue is 10 times worse - moving windows between monitors (with different dpi’s) causes the windows to redraw over an over for a few seconds before it finally moves to the other monitor.

If you use constraints on your styled forms - have fun figuring this one out!

Resizing controls flicker

I’m slowly coming to the realisation that our next release will probably not have High DPI support enabled by default - there are just too many issues with it - which I expect will result in more support work for us.

The trouble is that embarcadero have tried to fix the high dpi issues a bit at a time - perhaps afraid of breaking changes - and it’s really not working out well.

So to sum up, it’s not simply a case of recompile with the latest delphi and all is good, it’s going to take a lot of work to get it working correctly.


1 Like

I imagine building proper support into the VCL has also been complicated by the Windows high DPI support being a moving target for quite a long time now.

1 Like

That defintiely wouldn’t have helped - I bought a 4K monitor years ago, and tried to use it (before W10 Creators update) and ended up just putting it on a shelf collecting dust in the store room for years because windows and many apps just didn’t work well with the second monitor being a different dpi/scaling.

It’s interesting though that even though the VCL supposedly supports high dpi, the Delphi IDE doesn’t - you would think they would dogfood stuff like this. My guess is they struggled with it just any complex VCL application would.

When the Delphi IDE supports High DPI and works without issue (well without scaling and painting issues at least) - that’s when you will know the VCL high dpi support is up to standard.

Well, that’s all very depressing !

Is my way of positioning a form on the non-primary monitor by offsetting the top / left the way others do it?

1 Like

For my own system, I’ve stuck with a multi-monitor configuration with only 1920x1080 monitors rather than get a 4K monitor and have to deal with the weirdness while Microsoft and Embarcadero get their acts together.

To be honest I’m not sure I would switch to a single large 4K screen for myself. I like having the different physical monitors, it assists greatly in window management. I use a few small utilities to throw windows around and resize them in response to key commands.

1 Like

The reason I need to deal with monitors of varying resolutions and DPI is that my application has a main form as well as one or more video / image display forms. Those forms are usually positioned on the non-primary monitor, or projector output, etc.

Maybe I can fudge the position and sizing by doing some math after getting the DPI of the monitor I’m on as well as the one the main app form is on.

1 Like

Not just the high DPI issues either.

On my 5120x1440 monitor there are so many ‘normal’ behaviours that become ‘wrong’.

Apps that start ‘maximised’ (indeed, the whole process of maximisation needs revisiting/rethinking)

Dragging extents causing odd positioning when restarting.

Position of ‘popups’ and the like. (They can even end up behind other windows sometimes)

Delphi’s initial sizing of new forms (1736 on a 5120 monitor)

You could probably write a complex whitepaper on the whole subject.

Who says that you have to have a single large 4k monitor?

I’ve got a 4k 43" in the middle of my desk and a 27" QHD screen on either side. Above the 27" screens, I’ve got my old 24" Dell 1920x1200 U2412M monitors. :slight_smile:

You can use the Screen.Monitors collection to figure out the monitor locations and dimentions.

I do this when FinalBuilder loads to make sure that it shows up (monitors might have been removed, moved, replaced etc since last run)

  MARGIN = 20;
  r : TRect;
  index: Integer;
  ptTopLeft: TPoint;
  bVisible: Boolean;
  r.Left := GetIntAttribute(applicationElement,'left', Left);
  r.Right := r.Left + GetIntAttribute(applicationElement,'width', Width);
  r.Top := GetIntAttribute(applicationElement,'top', Top);
  r.Bottom := r.Top + GetIntAttribute(applicationElement,'height', Height);

  SetBounds(r.Left, r.Top, r.Right - r.Left, r.Bottom - r.Top);

  bVisible := false;
  ptTopLeft := Point(r.Left - MARGIN, r.Top - MARGIN);
  for index := 0 to Screen.MonitorCount - 1 do
    if (Screen.Monitors[index].WorkareaRect.Contains(ptTopLeft)) then
       bVisible := true;

  if not bVisible then
 wState := TWindowState(GetIntAttribute(applicationElement,'windowState', 0));

  if not (rsRunMinimised in TIDEConfigData.AppRunStyle) then
    if wState = wsMinimized then
      wState := wsMaximized;
    Self.WindowState := wstate;
    Self.WindowState := wsMinimized;

This restores the position of the form - but also makes sure it’s actually visible.

1 Like

Yikes - I tried 3 monitors for a while, but found that apps would sometimes launch on a random monitor (visual studio was bad for this) and I’d be staring at the wrong screen for a while wondering what happend.

My primary monitor is a 27" 2650*1140 and secondary is a 27" 4K - this setup is for working on High DPI support - it’s useful having the different dpi’s to test with.


The short answer is: yes.
The long answer, as Vince has already outlined, is that doing it on your own isn’t nearly as simple as it may sound.

if you want to try it on your own, there are two main ways:

  • Hack the VCL as Vince has outlined
  • Cheat

Because Vince has already talked about hacking the VCL, I will talk about cheating (which is the way I chose when doing this and that was quite successful).

There are two main problems to address with cheating: boilerplate and images.
The boilerplate can be addressed by ensuring you have a base form with all the relevant code and every other form inherits from it. This means you could wind up having to do bulk substitutions, but hey, if you don’t want to upgrade, something has to give… :smiley:

Images are another story entirely: the big problem is that you have to have a way to encode/decode images for your resolution or you will end up with horrible images that are completely unfit for use in your app.
The only reasonable way forward with this is to use SVG and SVG image lists. There are some components out there that do this, including at least one that is free.
Sorry but there is really no other way unless you’re willing to detect the right size and switch image list which I totally advise against. Bite the bullet and go with SVG, I promise you it’s just that much easier.

So… how does cheating work?
Basically, you have to handle the right windows messages and use a unit called Winapi.Multimon: in there you can find all the good stuff that you need.(GetMonitorInfo etc.) and that you need to use to make your base form right.

The best way to go about this is to create a sample project which includes tons of controls and that you can use as experimental grounds. Every time you make some progress, commit your code.
When you’re done you will have a base form which will scale correctly (you can use the ScaleBy method for that) and where all controls and images display correctly too.
If you’re careful and thoughtful, this will take you around a month-ish to get the vast majority of things right.
Occasionally, you will find that not everything behaves the way it should: time to go back to the playground and fix it that way. Eventually, you will find that all issues have been sorted.

To be sure, you also need a custom manifest telling Windows that your application is DPI-aware otherwise all is for naught.

You must also make sure that you intercept WM_DPICHANGE alongside other messages, please refer to MSDN for the bulk of 'em.

Finally, the first thing you need to do is detect the monitor information and the right proportions, that’s what you will be using for ScaleBy. There are two main ways to go about it:

  • Use DPI density and match it against 96: this would be the most common way I think, because it’s also the easiest. 4K monitors and the likes have a much higher DPI density (say like 146) so once you have that you can scale.
  • Check against monitor’s X and Y: when using the manifest you can also get the real dimensions and use those. I think that is a much more work-intensive way to do things but it is an option, especially for edge cases which you WILL find, make no mistake.

Please keep in mind that while the whole process may sound easy, it’s a lot of work and depending on your situation could wind up taking weeks or even months. Also, you need to confront the fact that a lot of component suites will already be DPI aware, so you also need to take that into account otherwise you will end up with blown out screens, which is something you definitely don’t want.


I haven’t had that as a major issue. I think that the worst that I’ve had is having to search for the mouse cursor a few times.

I spent months on that, even doing a ton of work on the SVGImageList etc that Carlo put on github. Nothing wrong with the SVG imagelist etc - but major issues with how SVG’s scale.

If you draw the image at a small size, then the lines will look too thick at a larger size.
If you draw the image at a large size, then the lines will look too thin at a smaller size.

Either way you can’t win. After trying and failing, I went back to png’s - this was possible because I’m using 10.4.2 - which has the TImageCollection and TVirtualImageList - so I can provide png’s drawn at different sizes - I chose

96dpi - 16px
144dpi - 24px
200dpi - 32px

I could have done more sizes - but I have thousands of images to sort out.

Another issue I had with svgs - is finding svg source images for third party tools that FinalBuilder has actions for - some were ok but many products don’t have vector logos etc available.

I’m using Axialis Icon Generator along with their icon libraries ( expensive but worth it).

Each image is actually drawn as a vector on 2 grid sizes - 16px and 32px - so when you export pngs - it will chose the best size source image to render at the output size - the results work out better than just rendering a single svg at different sizes.

Tried turning on “Show location of pointer when I press the CTRL key” in mouse, ‘pointer options’?

@vincent I currently do a similar check with the main form to make sure it’s visible to the user on startup, but your code is a bit more comprehensive I think. I may revisit that and apply it to all forms.

As for monitor setups, at home I have a 4K as the main one and another 1 (sometimes 2) along side it. At work I have a pair of 1920 x 1080 side by side as my main monitors, a 1050 x 1680 in portrait off to the side for PDFs, etc and another 1920 x 1080 above the two main ones for less important content.

I haven’t tried that previously - I’ve just tried it now and I can see some situations where it might be helpful, but I don’t think it’s a huge improvement over just moving the mouse around and looking for the movement.

I do most of my work on the 43" monitor, so the mouse is usually on that screen when I come back to the computer, so it’s not too hard to find. The issue is that when I’m looking straight at the 43" it’s the only monitor that I can see with both eyes - all of the other monitors are only in the periphery of one eye, until I turn my head, so if I lose the mouse, I have to turn my head to scan and look for the mouse movement.

Not really a major problem - it’s only happened a couple of times and only took 5-10 seconds to find when it did happen.

I’ve had the very same experience as Vincent - went from bmp/png to svg and then back to png - and also use Axialis. Very time consuming…

Maybe we need a machine learning solution fed with a bunch of svgs, and good pngs …
Paul McGee

This is a test reply as someone has had an issue replying via email.