7

Google is useless for these sorts of searches, because you get hundreds of millions of results absolutely none of which relate to the specific question.

The question is simply this:

  • Is it possible to have a Class Reference Property in Delphi?
  • If so, how?

Here's what I've tried...

type

  TMyObject = class
    // ...
  end;

  TMyObjectClass = class of TMyObject

  TMyObjectA = class(TMyObject)
    // specifics here
  end;

  TMyObjectB  =class(TMyObject)
    // specifics here
  end;

  TMyComponent = class(TComponent)
  private
    FObjectType: TMyObjectClass;
  published
    property ObjectType: TMyObjectClass read FObjectType write FObjectType;
  end;

The above code compiles fine, however the Object Inspector does not show the ObjectType property at all.

My objective here (if you haven't already guessed) is to make it so that I can select a class descendant from a specific base class, to make the same component behave in a different way.

I want to do it this way so that the component doesn't need to know about the sub-classes directly (it needs to be fully modular).

Let me just make this bit clear: I cannot use an Enum to choose between the sub-class types as the component cannot directly link to the sub-class types (It's simply not possible in this particular case)

Anyway... thanks in advance!

LaKraven
  • 5,804
  • 2
  • 23
  • 49
  • Object inspector does not show the property because there is no registered property editor for it. – kludg Jan 28 '12 at 16:39

2 Answers2

5

You can find all classes that descend from a particular base class: Delphi: At runtime find classes that descend from a given base class? and make this a special property with list of values using TPropertyEditor.

Community
  • 1
  • 1
Pol
  • 5,064
  • 4
  • 32
  • 51
  • Marked your answer as correct as you were first to answer (and this is the correct answer, of course). I won't be using this method because I don't want to use any RTTI in this system. Decided to go with the "cross-linked components" idea (where a component of `TMyObjectA` or `TMyObjectB` links to a `TMyComponent` instance via a property. Easier this way! – LaKraven Jan 28 '12 at 16:45
  • Simon, consider how such a property editor would actually get hold of class types in the context of a design time package. – David Heffernan Jan 28 '12 at 16:47
  • David, yes... it would be relatively easy (using RTTI) to add a Property Editor to handle this sort of thing... but as I said in my prior comment, I don't want to use the RTTI in the compiled executable (which I'd have to do to obtain the Class from its Qualified Name as stored in the DFM) – LaKraven Jan 28 '12 at 16:50
  • @LaKraven No it would not be easy. You would have to parse the source code of the project currently loaded into the IDE! Remember that the class types don't actually exist until runtime but your IDE package runs at designtime. – David Heffernan Jan 28 '12 at 16:54
  • @DavidHeffernan When you install a package into the IDE, the enhanced RTTI in Delphi 2010 and above can then introspect all classes defined within it. Any instance, therefore, of a component within that package which has the "Class Reference Property" would (assuming the existence of the Property Editor to handle it) work just fine! – LaKraven Jan 28 '12 at 16:58
  • @LaKraven OK, but I would assume you would in fact want to refer to classes that were not installed into the IDE. What about a class defined in Unit1.pas in your VCL app? Do you only want to refer to VCL classes? – David Heffernan Jan 28 '12 at 17:00
  • David, this also works! Load any project into the IDE, and the RTTI can see all Types defined within it at design-time. This is actually how my Lua4Delphi Wrapper Unit Generator works... so I'm already exploiting this capability! – LaKraven Jan 28 '12 at 17:02
  • Really? It can see types in source code that is not in a design time package? – David Heffernan Jan 28 '12 at 17:04
  • David, yes! I think since D2010 they've been using the RTTI to at-least support things like Code Completion and UML modelling... either way, the RTTI can introspect all types defined within the scope of anything active inside the IDE... including active projects! – LaKraven Jan 28 '12 at 17:07
  • If you want to make a PropertyEditor for this property, then change its type to type string, because TMyObjectClass has no type info. – NGLN Jan 29 '12 at 09:43
  • @LaKraven: This discussion about exploring types declared in any Unit1.pas or other project file is intriguing but as yet I'm unable to reproduce it. Anyone care to fill me in on how it works by answering this question. http://stackoverflow.com/questions/9057312/can-rtti-interrogate-types-from-project-code-at-designtime – LachlanG Jan 29 '12 at 22:23
  • 4
    To clear up the above... it turns out I was entirely mistaken and @DavidHeffernan was correct! RTTI cannot be used at design-time to introspect Types defined within an active project. It can only do this for types registered within a package! – LaKraven Jan 30 '12 at 20:50
3

If you were going to do this then you would need to provide a property editor. The IDE does not come with property editors for class type properties. You would also need to handle .dfm persistence. You would write the class type out to the .dfm file as a string and when the .dfm file is read, you would need to fixup the reference. New style RTTI could do that.

However, I don't think any of this is actually viable for the following reason. Your design time code runs in a package inside the IDE and does not have access to the class types in the active project in the IDE. Those class types only exist when that project runs. So the ObjectType property in the code in your question cannot be assigned to anything meaningful in the design time package. Well, you could use it for classes defined in the VCL and any other packages installed in your IDE but I rather imagine you'd want to use it on classes defined in the active project.

I think all this means that you should instead use a simple string property and fixup the class type references only at runtime.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490