delphidesignertcustomcontrol

How to detect the dfm/project path from a custom control while in the designer?


Context

I created a custom TControl similar to TImageCollection but with a shared database of images for all the application. For this, the control reads a project meta-file which is an XML containing the list of images to include in the image collection. When in the designer, images are read directly from the image files, but at runtime, images are in the resource (*.res) file generated during the compilation.

if csDesigning in Self.ComponentState then
  loadImagesFromFiles(...)
else
  loadImagesFromResource(...)

All seems to work except:

In the designer, before I open the control editor for the first time, the image collection cannot read the resources (*.res) because it has not yet be created (this is done at compile time), consequently, any other control showing those images shows blank. The images must be loaded from the files, but the path to the project is not known from the TControl in the Designer.

The editor is able to detect the project directory, thus, open the metafile and fill all the images in the collection. However, until the editor is open, the image collection has no way to get the directory to access that metafile and all the images.

The question

From a TControl while in the designer, how to detect the directory of the project, or the *dfm that includes it?

What I evaluated

ToolsAPI has few functions to detect the active project, however this unit is not accessible within a TControl custom implementation. Only from editors and other Designer plugins.

Environment variables: Enforcing all the developers to set an environment variable pointing to the project root, and using that in the control. This could work but it has many defects:

Project DEFINE: Having the absolute path of the project as a project DEFINE is not portable. And Delphi seems to not allow this neither.


Solution

  • A TControl can find its parent Form by using the Forms.GetParentForm() function.

    TCustomForm has a Designer property of type IDesignerHook that is non-nil at design-time.

    Query the IDesignerHook for IDesigner using the as operator (do not use a hard cast!).

    IDesigner has a ModuleFileNames() method to retrieve the filenames associated with the object being designed, which in this case will be the TCustomForm so the FormFileName parameter will output the filename of the .dfm (VCL) or .xfm (FMX).