What's the difference between public and published class members in Delphi? - delphi

Please could someone explain me what's the difference between public and published class members in Delphi?
I tried to look at Delphi help and I understand that these members have the same visibility, but I don't understand very well how they differ and when should I use published members instead of public ones.
Thanks a lot.

The compiler generates RTTI (Run-Time Type Information) metadata for published members, but not for public members (by default). The main effect of this is that the published properties of an object will appear in the Object Inspector at design time.
I do not know if you are writing components, but if you do, you probably know that properties and events are normally published, so that they can be set using the Object Inspector.
Public
public
property MyProperty: integer read FMyProperty write FMyProperty
MyProperty will not be visible in the Object Inspector.
Published
published
property MyProperty: integer read FMyProperty write FMyProperty
MyProperty will be visible in the Object Inspector.

Public properties and published properties have the same visibility, as you already stated. Published properties are included in RTTI, public properties aren't.

As a side note, there is another special thing with published:
The default visibility of class members is published, so check for unsafe code like:
TTopSecret = class(TObject)
Name: string;
Password: string;
function DecryptPassword(const AValue): string;
public
constructor Create(const AName, AEncryptedPassword: string);
end;
Name, Password and DecryptPassword() are visible 'world-wide'.

Published properties will export Runtime Type Information (RTTI).
Have a look here about RTTI in Delphi

It seems there are lots of good answers already, pointing out the Object INspector, RTTI,
etc. These are all pieces of the puzzle.
If you take away the published keyword, the entire Delphi RAD tool design would require some way to specify which properties are stored in a DFM, inspected in the component property inspector, and can be reloaded at runtime from a DFM when the form or data module is created.
This, in a word, is what Published is for. It is interesting to me that the designers of QT (originally TrollTech, later part of Nokia, later still spun off to Digia) had to emulate this level of RTTI for their C++ RAD library "QT", adding a "published" equivalent and a "property" equivalent, while pure C++ still lacks this fundamental facility.

Runtime Type Informations (RTTI) are only generated for published class members.

At run-time, entries in the published and public sections are equally accessible.
The principal difference between them is that published items of a component appear in the Object Inspector at design-time.
This happens because, for fields in published section RTTI is automatically generated.
The Object Inspector picks this up and uses it to identify what to add to its list of properties and events.

In addition to the other answers:
Published properties are automatically stored by the streaming system.
For instance if you have a TComponent's descendant instance and write it to a TStream with WriteComponent, all (well, not all, but that is another question) published properties are written to the stream without any further coding.
Of course, the streaming system only can do that because the RTTI is available for those published properties.

Related

Add properties to an object at runtime

Delphi RTTI makes it very easy to enumerate and extract information about an object's properties, fields and methods at runtime.
However, is it possible to add a property and field to an object at runtime?
I realize that this would involve changes to the VMT if it depends on a getter / setter, which is why i mentioned fields, so the injected property could be bound to said field and thus avoid appending nodes to the VMT tree.
This might seem like a silly question, but I am working on a layout designer. The objects you can move around and position represents web elements, that all have different properties.
It would save me a lot of time if I somehow could populate these proxy design objects with the actual properties from the web elements. Then I could use a normal object inspector directly on them, rather than having to manually populate the inspector rows.
Serialization would also be easier since I could use the standard Delphi way, as opposed to hand writing IO code.
I doubt this is possible without some form of hack, but it's always best to ask.
Delphi is a statically typed language in its root. However, you can use variants - custom variants to be precise to create dynamic properties.
type
TMyCustomObject= class(TInvokeableVariantType)
public
procedure Clear(var V: TVarData); override;
procedure Copy(var Dest: TVarData; const Source: TVarData; const Indirect: Boolean); override;
function GetProperty(var Dest: TVarData; const V: TVarData; const Name: string): Boolean; override;
function SetProperty(const V: TVarData; const Name: string; const Value: TVarData): Boolean; override;
end;
You can implement few virtual methods in the above code and get the desired results.
Here is a tutorial:
http://www.uweraabe.de/Blog/2010/08/07/a-magical-gathering-part-2/
An alternative approche would be to not rely on straight RTTI, but rather on an intermediate description layer.
You could initialize the intermediate layer from the RTTI for what's in the RTTI, and add extras for your dynamic properties.
This would also allow you to shield your layout designer from the RTTI quirks. Most of what the RTTI expose is very low level, and a lot of it is "unsafe" in that it can trigger unsafe behaviors in objects (and thus crash your designer).
This is especially relevant if you dot not have 100% control over the objects to fix their issues, which I guess you do not, as otherwise you would not need dynamic properties.
During interactive design invalid property values are the norm: partial inputs, typing errors, incoherent settings, etc. all these will require some kind of context-specific sanitizing, which an intermediate layer can provide.
In the Delphi IDE, the design-time sanitizing is basically up to each individual component's implementation and the csDesigning component state. While it is simple, there is very limited feedback a component can provide on incoherent or invalid properties.

How to get a method param name array/list in Delphi?

Is there any way to get the names of the parameters of a given method of a class/object in an array/delimited string in Delphi 7? Somehow like this:
var
s : string;
aSL : TStringList;
begin
...
// using rtti calls in TMethodUtility.collectParamNames
s := TMethodUtility.collectParamNames( TStringList.addObject );
// or
TMethodUtility.collectParamNames( TStringList.addObject, aSL );
...
end;
Thanks in advance!
It is technically possible (otherwise the IDE's Form Designer could not generate code for component event handlers at design-time), however, there are important caveats that will hinder your goal (and make the particular example in your question impossible to resolve):
the necessary RTTI is only generated for properties that are declared as published (such as component events). RTTI is not generated for methods themselves (even published ones), or for properties that are not published.
TObject has a public MethodAddress() method for getting the memory address of a published method (the DFM streaming system uses this when hooking up event handlers), however you cannot get the necessary RTTI from a method pointer alone.
IF you can match a given method pointer to the value of a published event, then you can extract the parameter names from the event's RTTI. Obtain a TypInfo.PPropInfo pointer for the event using the TypInfo.GetPropInfo() function, then pass its PropType field value to the TypInfo.GetTypeData() function to get a TypInfo.PTypeData pointer, and then you can iterate through its ParamList field (which is an array of records containing ParamName and TypeName fields).
See the following blog article on this topic for more details:
Getting the parameters of published methods.
For what you are attempting, a general-purpose solution would require Extended RTTI that was introduced in Delphi 2010 and thus is not available in Delphi 7. Extended RTTI is not limited to published items, and is much more detailed than what the old-style RTTI provides.

Is there a component to automatically create a config form?

I have a settings class in my system, where I store configuration values for important settings. It looks like the code below, but with many more attributes of different types.
Now I need to implement a form with which I can adjust and configure these settings at runtime. Its very cumbersome to implement the fields for each attibute and guarantee that all values are mapped without error.
Now my question: is a vcl component that could automatically create an interface to solve that. Eg. offer a tree-like or listview-like interface with the names of the attributes and fields to edit the values (like the property pane in the IDE, with printer settings, see screenshot below). That would be a great thing. No?
How do you deal with configuration forms like that?
Thanks for your input!
TGoldmannSettings = class
private
FInitialSymbolSize : Integer;
FPenWidth : Single;
FCanvasColor : TColor;
FShowLiveCoordinates : Boolean;
FFont1 : TFont;
FMsmPointSymbol : TAvailableSymbols; // own type
...
public
constructor Create;
destructor Destroy; override;
property SymbolSize : Integer read FInitialSymbolSize write FInitialSymbolSize;
property Font1: TFont read FFont1 write FFont1;
...
published
property PenWidth: Single read FPenWidth write FPenWidth;
property CanvasColor: TColor read FCanvasColor write FCanvasColor;
property ShowLiveCoordinates: Boolean read FShowLiveCoordinates write FShowLiveCoordinates;
...
end;
You sometimes find something I mean in printer setting dialogs:
The TJVInspector component from the Delphi Jedi JVCL project creates a property editor very similar to what you are looking for. They have an advanced example that works on an INI file.
JVCL Site: http://jvcl.delphi-jedi.org/
Nice example: http://www.neugls.info/?tag=tjvinspector
The JVCL / JCL package is huge but has a ton of useful components and functionality.
I have never yet created an automatic-configuration form generator similar to the one in the delphi project options, but I have seen this done in several projects that I work on, and seen the source code, and it works very much like this:
I would have a base type of frame called TConfigFrameBase and it would contain some properties like this: Caption (user displayed name of property), Hint (some help), and Name (config property), and Section (page this property is shown on).
Specialized inherited frames would be used for boolean properties, string properties, etc. Your domain (your app) will have its own custom types. Dates? Lists of apothecary locations in Denmark? Only you know for sure the complete set of UI configuration property types you need, and that's why I haven't seen a component that makes this automatic or just a component. The boolean frame would contain a Label control and a checkbox and would have a default height around 30 pixels. A frame that let me move a list of options on side A to options on side B (columns visible within a particular grid, for instance) might be as high as 300 pixels. By vertically stacking these frames, in a scrollbox, you don't have to do much thought about layout. Everything will be usable when these frames are used to populate a listbox.
A tree view on the left that lets you pick a section. In the on-click in the tree view, the right side pane is built by iterating through my internal list of config-frames that are registered in a list or dictionary, and filtered by the Section they belong to.
I wouldn't use a JVCL Property Inspector as my configuration control, but it might work for you. I also don't think you're going to get everything you need out of VirtualTreeView, but your mileage might vary. You can write your own custom Editor controls, and if you like writing in-place-editor controls, you might find VirtualTreeView perfect.

Class Reference as Property

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!
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.
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.

How can I check an interface property's visibility?

I have started writing web services in Delphi 2010 and am unit testing to make sure they function as planned. My unit tests of the code passed but one web service method didn’t return a value when called as a service (i.e. through SoapUI). After many hours of searching through the code I discovered it was because the properties on my return object weren’t in the published section of the interface; they were in the public section.
Is there a way for my unit tests to check variable visibility on objects so I can avoid this problem in the future? I was trying to find a way with RTTI but haven’t been able to find anything.
You can determine whether a property was declared published by attempting to access that property's RTTI. A public property has no RTTI, a published property does.
Something like this:
if (GetPropInfo(myobject, "PropertyName") != null) then
// it's published...
For more info on RTTI, see Brian Long's article: http://www.blong.com/Conferences/BorConUK98/DelphiRTTI/CB140.htm
You can do it with RTTI easily enough. You can use the classic RTTI function GetPropInfo in the TypInfo unit. If it returns nil, then no published property by that name exists. Or you can look it up with extended RTTI and check the Visibility property, which will tell you what visibility level it's declared at.

Resources