How to prevent modifying a design time component in derived form - delphi

I have defined a base VCL form class with a (non-visual) designtime component on it that contains a collection of styles.
I want to prevent developers (and myself) to change those styles in the forms that are derived from my base form. To speak in C# terms, I would like the component to be sealed in the base VCL form.
How can I achieve that?
On a side note: I never did understand the declaration of designtime components on a form in Delphi.. kinda public but not placed in the public section of the class declaration. Can anybody explain the reason for this?

Well, short answer you can't. In case you really need it I would suggest to create the component in run-time and make it private. If you are using GExpert (click here) you may use "Components to Code" command to get the required code. If you need more details, please share your DFM file and I will post the corresponding code here.
As for your side note, the components are declared as published. See Visibility of Class Members quote
If a member's declaration appears without its own visibility
specifier, the member has the same visibility as the one that precedes
it. Members at the beginning of a class declaration that do not have a
specified visibility are by default published, provided the class is
compiled in the {$M+} state or is derived from a class compiled in the
{$M+} state; otherwise, such members are public
NB TForm is a descendant of TPersistent which is compiled with {$M+} directive
PS the published declaration is required for TComponent.SetName (actually TComponent.SetReference) which should assign the component reference to the corresponding field when you modifying the component Name property.

Related

Hide properties and events in new component

I created in Lazarus a new component based on TPaintBox. Now in Object Inspector I have all Properties and Events which belong to this base component (TPaintBox).
My question is: can I hide chosen Properties and Events for my component?
For example I would like to leave visible only Width and Height properties.
Can you help me?
Once a property/event has been published, it cannot be un-published.
However, it can be hidden from the Object Inspector, at least (it is still accessible to code).
After your design-time code has registered the component with the IDE, it can then:
in Delphi, call UnlistPublishedProperty() from the DesignIntf unit.
in Lazarus, call RegisterPropertyEditor() from the PropEdits unit to register the THiddenPropertyEditor class for the property/event (see Hide Properties (UnlistPublishedProperty) in the Lazarus forum).
Not sure about Lazarus, but in Delphi TPaintBox is a lightweight descendant of TGraphicControl. The majority of its declaration is just publishing properties. I don't know what your component is doing, but it might be easier to derive it directly from TGraphicControl and duplicate the TPaintBox code wherever it actually is needed. Then you can publish only the properties you want. Note that you still have those properties declared published in TControl and TComponent.
No, you can't hide (unpublish) published properties.
In Delphi most objects are based on a parent classes with all the same properties, but mostly hidden.
So while you can't hide exposed properties you can usually achieve what you want by basing your class on the TCustomxxx instead.
Sadly, TPaintbox is an exception. It is descended from TGraphicControl, but that in turn is descended from TControl which already has a number of published properties, including AlignWithMargins, CustomHint and several others, and that in turn is descended from TComponent which has Name and Tag published. To be fair, you need name for sure, and Tag is not a problem I would think.
If you just had to go back to TGraphicControl, that is not too bad. Just one member and a couple of routines to copy. But to go back to TComponent, which is what you would need to do to hide a number of properties is not really viable.

Inherit uses from parent class

I have added some units to the uses part of my parent TForm.
Then I went to File > New... and created a form inhering my form which has the usages.
The child form seems not to have access to the units used in the parent form.
Is this the correct behavior or is it possible to inherit the uses?
This behaviour is correct. The units listed in a uses clause are made available to that unit only.
If your other unit, containing he derived class, requires symbols from other units, it must list those units in its own uses clause.

Can I make a custom Delphi component add multiple units to the uses clause?

I'm working on some components in XE2. Is it possible to have more than the component's unit added to the uses clause of the form it's dropped on?
Example:
When I choose the TCustomComponent from a package I've built and installed the unit CustomComponent is added to the form's uses clause. I would like to also add the unit GlobalConstants.
Does anyone know if this can be done?
Create a design-time package for your component (if you do not already have one). In that package, create a class that implements the ISelectionEditor interface (the easiest way is to derive from the TSelectionEditor class), overriding its virtual RequiresUnits() method to report any additional units you want to appear in the uses clause of any Form/Frame/DataModule that uses your component. Then, have your package's Register() function register that class by calling RegisterSelectionEditor() (in addition to RegisterComponents()).
Indy 10 does exactly this for its TIdTCPServer, TIdCmdTCPClient, and TIdUDPServer components, to make sure the IdContext and IdSocketHandle units get added to uses clauses. Look at the IdCoreSelectionEditors.pas and IdRegisterCore.pas units to see how Indy implements this.
Update: the IdCoreSelectionEditors.pas and IdProtocolsSelectionEditors.pas units were removed from Indy 10 in March 2014. All of the per-component SelectionEditor classes were replaced with a new single class implemented in the IdRegisterCore unit itself. This new SelectionEditor class is registered for all Indy components, and it looks for all instances of any Indy component that has been placed at design-time, using RTTI of the data types of all parameters and return values for any assigned event handlers to know which units to report for inclusion in the uses clause.

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.

What is the difference between types defined in the implementation as compared to the interface section of a unit?

Almost all of the Delphi code I have read has all the class type definitions in the units interface section, but I have seen occasional use of type definitions within the implementation section.
What exactly is the difference between these, and why would I use this?
It's pretty simple: types defined in implementation only are only visible within the implementation, so they cannot be used as types of arguments or return values in the interface. So, position your type definitions (like anything else;-) based on whether those types are only an implementation detail, or something you want to make visible externally, i.e., through the interface!
Scope. Interface declarations are public and availabe to other units when that unit is include in the Uses clause. Implementation declarations are private and only available within that specific Unit.
There is a general difference between code changes in interface and the code changes implementation during compilation. If you add a class to or change an existing class in the interface section then every unit that references the changed unit will need to be recompiled. However a change in the implementation section (a new subclass or code changes) will only required the recompilation of that unit and the IDE will link the previously compiled DCU plus the new one together to create the EXE file.
Overall the major benefit, is that it allows you to design you code to hide implementation details - define the parent class in the interface and any subclasses in the implementation. Or define classes in the implementation if they are solely needed to implement the behavious of a class/method available in the interface section.

Resources