Jump to content
Tom Mueller

Conceptual question about centralized TActionList and HighDPI scaling

Recommended Posts

A common scenario in our applications involves using a centralized TActionList connected to a TVirtualImageList on a data module. The actions in the list are linked to controls on different forms (UI).

 

However, when moving a form to a monitor with a different DPI, the action images do not scale properly. This occurs because the TVirtualImageList is not located on the moved form.

 

Given that we have several centralized TActionLists in our applications, moving or duplicating them to different forms solely for image scaling doesn’t seem like an ideal solution.

 

How should centralized TActionLists be handled in HighDPI-supported applications?

 

 

Share this post


Link to post

That might not answer your specific question but if you have access to DevExpress components, I highly recommend using only SVG icons in their image lists. You will no worries about icon quality, scale, dpi settings... anymore.

Share this post


Link to post

Thank you for your tip. I tested the DevExpress TcxImageList, and it works fine with DevExpress controls. However, it does not support certain Delphi controls, such as TMainMenu, TPopupMenu, TToolBar, TTreeView, TListView and maybe more, which are essential controls for me.

Share this post


Link to post

Usually you connect the actions of such a TActionList to some visual control of a form (TMainMenu, TPopupMenu, TToolBar, TTreeView, TListView ...). Most of these controls have their own property to connect a TVirtualImageList, which should reside on the form itself. The latter is mandatory to make DPI awareness work properly.

 

It may sound wrong to have separate virtual image lists in each form, which often contain the same content - sometimes the same as the one connected to the ActionList. If you imagine that each each image list can only hold one size of images and each form can have run on a different DPI it becomes clear that this is unavoidable.

 

While it can be tedious to have all these TVirtualImagelist instances at design time, there are ways to simplify it. If you are interested I suggest reading my blog posts about ImageLists and High DPI

  • Like 1

Share this post


Link to post

This essentially means that no ImageList can be used for a centralized TActionList. Instead, a TVirtualImageList must be created on each form and associated with the control.

 

This is a significant limitation of the TImageCollection/TVirtualImageList concept.

 

I wonder how DevExpress handles this, as the scaling works even when the cxImageList is placed on a DataModule.

 

Thanks Uwe for pointing me to your blog. The article is very well-written and could help me with implementing centralized image management.

Share this post


Link to post
Just now, Tom Mueller said:

I wonder how DevExpress handles this, as the scaling works even when the cxImageList is placed on a DataModule.

I'm not familiar with the DevExpress approach, but I assume the DX controls can request an image of arbitrary size/DPI from an DX image list (probably acting like a VCL TImageCollection). Standard controls based on Windows require an HIMAGELIST at the end, which contains images all of the same size. Compatibility is the limiting factor here.

Share this post


Link to post
Just now, Uwe Raabe said:

Compatibility is the limiting factor here.

Yes, unfortunately. cxImageList would be the ideal solution if all controls (not just DevExpress) were supported.

Share this post


Link to post

I've just tested a TcxImageList with a SVG image and used by a TActionList, Speed button and standard menu, and it seems to work just fine.

Share this post


Link to post
4 hours ago, John R. said:

DevExpress [...] You will no worries about icon quality, scale, dpi settings... anymore.

Well, I wouldn't say you don't have to worry; They work pretty well but they are not without their own bugs. Our code is littered with work-arounds for DevExpress bugs, many of them High-DPI related.

 

4 hours ago, Tom Mueller said:

it does not support certain Delphi controls, such as TMainMenu, TPopupMenu, TToolBar, TTreeView, TListView and maybe more, which are essential controls for me.

If you enable skinning then TMainMenu and TPopupMenu are drawn by DevExpress. They also have treeview and listview controls based on TTreeView and TListView so migration should be fairly easy. TToolbar will have to be replaced but that should be no great loss.

Share this post


Link to post

I spent a major part of the last 4 years making our application here HighDPI compliant. And I ended up using DevExpress TcxImageList exclusively with SVGs, partially custom made. SVGs not only solve the DPI problem, they also feature a skin-adaptable palette, so that if your app has e.g. a light and a dark skin, the SVGs actually adapt their color (which they have to, to be identifiable in dark mode).

 

With this approach a centralised ImageList is absolutely no problem - in fact you can request a specific image from the list in any desirable size/scale e.g. for use in custom drawings etc.

26 minutes ago, Anders Melander said:

Well, I wouldn't say you don't have to worry; They work pretty well but they are not without their own bugs. Our code is littered with work-arounds for DevExpress bugs, many of them High-DPI related.

Would you be willing to share more info on what these are, e.g. links to DX support issues? Littering code with workarounds sounds awful. I remember that back in maybe 2020 there were still a few issues, especially with the adaptable SVG palette, but with the 2022 version and RX 11.2 I'm currently using I'm actually very satisfied.

 

26 minutes ago, Anders Melander said:

 If you enable skinning then TMainMenu and TPopupMenu are drawn by DevExpress. They also have treeview and listview controls based on TTreeView and TListView so migration should be fairly easy. TToolbar will have to be replaced but that should be no great loss.

I had to stop using TcxTreeView and TcxListView altogether, they are just shells around the native controls and as such do not support proper skinning and scaling as well as the SVG palettes. DX also made it quite clear that they don't intend to put more work into these controls, but rather in the alternatives TcxTreeList and TdxListViewControl. And since TcxTreeList is also capable to replace TVirtualTreeView I went this route.

 

Share this post


Link to post
44 minutes ago, John R. said:

I've just tested a TcxImageList with a SVG image and used by a TActionList, Speed button and standard menu, and it seems to work just fine.

My little tests with TcxImageList and SVG images shows the lack of scaling on a HighDPI monitor (here scaled to 225%).

 

Even TcxListView does not scale correctly compared to Delphi TVirtualImageList.

DevExpress-ImageList.thumb.png.f182f2b0c6608858844a06b388843e00.png 262378283_Delphi-VirtualImageList.thumb.png.f6e391f59baf4ff7b2fd0227651b40c3.png

 

35 minutes ago, Anders Melander said:

If you enable skinning then TMainMenu and TPopupMenu are drawn by DevExpress. They also have treeview and listview controls based on TTreeView and TListView so migration should be fairly easy. TToolbar will have to be replaced but that should be no great loss.

Thank you for the skinning tip. Until now we tried to avoid skinning or styling our applications - but I'll give it a try. 

Share this post


Link to post
11 minutes ago, msohn said:

I spent a major part of the last 4 years making our application here HighDPI compliant. And I ended up using DevExpress TcxImageList exclusively with SVGs...

Thank you for sharing your experience with us.

 

How did you replace TMainMenu, TPopupMenu, and TToolBar controls? Especially the MainMenu and PopupMenus, as they are widely used in our applications.

Share this post


Link to post
Just now, Tom Mueller said:

How did you replace TMainMenu, TPopupMenu, and TToolBar controls? Especially the MainMenu and PopupMenus, as they are widely used in our applications.

We already used ExpressBars in most of the places. And just like TListView and TTreeView (regardless if original or cx version) don't support SVGs and skinning properly, so is the skinning and SVG support for TMainMenu et al very limited.

With regard to TPopupMenu, if you need to use a control which cannot handle TcxPopupMenu, you can just handle popping up the menu manually via an OnContextPopup even handler (not sure if this is the right name).

 

But I freely admit, this is only giving good results if you go all-in on the DX controls and it's a lot of work. But for us this was just a logical conclusion and it made us clean up very old parts of the GUI. The end result using TdxLayoutControl etc. is much more flexible than it ever was before.

Share this post


Link to post
5 minutes ago, msohn said:

Would you be willing to share more info on what these are, e.g. links to DX support issues? Littering code with workarounds sounds awful.

Here's the latest (not HighDPI related though):

https://supportcenter.devexpress.com/ticket/details/t1277096/drawing-of-screentip-description-does-not-take-skin-palette-into-account

TLDR; It ended up as "won't do" since they deem it a corner case (ScreenTip with formatted text and skins) and too expensive to fix. Even though I don't think it's that much of a corner case I can't really blame them much; Resources are limited.

 

I don't mind the workarounds that much. I do mind the cases where I have to patch their code because that is really a pain to maintain.

 

A search, in the project I have open right now, for "work.?around.+devexpress" gives me 29 hits. Most have no reference to a DevExpress issue (and some have probably never been reported) but here's the first 5 that does have a reference (only one of them is HighDPI related):

Share this post


Link to post
4 minutes ago, msohn said:

The end result using TdxLayoutControl etc. is much more flexible than it ever was before.

For me this is the single most useful of their controls in terms of UI design. It can be be hard to work with if you need an unusual layout but for the bread and butter dialog layout it is just perfect.

 

With regard to skinning, I recommend chosing one of the vector based skins (this avoids most of the bloat). If the user must be able to customize the color scheme, then just give them 3 choices: Light, Dark, Custom (selects among the available color palettes). As an example, here's the UI to do this from BTM:

image.thumb.png.d5561675d7aa6d58723468f98969990c.png

As far as I remember that whole dialog is a layout control.

Share this post


Link to post
12 minutes ago, Anders Melander said:

A search, in the project I have open right now, for "work.?around.+devexpress" gives me 29 hits

Thanks for sharing Anders. I regularly run into tickets by you on the DX support site and I'm often impressed how well written and researched these are. I bet the support guys at DX very much remember your name by now 😉 FWIW I "starred" a few tickets which I'd like to see fixed as well - one can only hope.

 

1 minute ago, Anders Melander said:

For me this is the single most useful of their controls in terms of UI design. It can be be hard to work with if you need an unusual layout but for the bread and butter dialog layout it is just perfect.

Yes that is exactly my experience as well. Sometimes one feels like your hands are being tied, but then you just need to remember how much more tedious it was without the LayoutControl.

 

3 minutes ago, Anders Melander said:

With regard to skinning, I recommend chosing one of the vector based skins (this avoids most of the bloat).

 

Yes that's also exactly what I did - specifically TheBezier skin with different palettes and an unskinned mode where main forms are lfOffice11 (yeah I know, looks a bit old) and all dialogs use NativeStyle - this was the original look and was kept for people not wanting to adapt the looks.

Share this post


Link to post

What we have done is have a centralized imageList in a datamodule for the application. We then have separate actionList/imageList pairs on every form. In the form Create, we copy the image(s) we need for that form from the central image list to the image list on the form being shown.  Its a bit of a pain, we have a list of constants on the central datamodule so we can request images in an easy to read manner. So, on any given form's Create, we do something like

 

actExportToExcel.ImageIndex:=CentralImageDataModule.AddImage(self.ImageList,IMG_EXPORT_TO_EXCEL)

 

Its a bit of a pain  and we have some utility functions like

 

CentralDAtaModule.AddImageIndices([act1,act2,ac3],[CONST1,CONST2,CONST3])

 

to make it a bit simpler. But that way we can update the images in the central data module and have them update everywhere. 

Edited by Dave Novo

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

×