Adding declarations and definitions in the IDE for runtime components - delphi

I'm dealing with creating a number of components at runtime and setting their methods. Is there a way to add the declartion and definition stubs for a component without adding it to the form and clicking the corresponding event on the events tab?
I know I can add a component temporarily to create the stub, or sometimes the help files list the declaration. But there are a lot of features in the IDE that I have not found or used.
Replying to comments:
What I do currently is workable I just wondered if there was a shortcut I was missing. To reiterate as some did not understand; I am using component AwesomeComponent in my application. I only need to create instances of AwesomeComponent at runtime, so it is not on my form (or perhaps is non-visual). AmesomeComponent has an event DoSomething. That event has a number of parameters. In order to assign AmesomeComponent.OnDoSOmething at runtime, I need to code the event, but I don't have direct access to the procedure stub, I have to find it somewhere in documentation or create it on a dummy form to cut and paste it. I didn't know if there was an IDE feature that was smart enough to say "Ok, I recognize this name (AwesomeComponent.OnDoSOmething) as an event and create a stub for it. It must do essentially the same thing when double-clicking on the Events tab in the IDE.

Related

How can I make the IDE aware of units used in a project which uses my package?

I'm writing a package for a custom component. This package allows the user/developer to either include numerous pre-written units in their project which are explicitly designed to work with this custom control, or write their own to do the same as one of the existing ones. Think of it like a "plugin" where code is implemented in its own unit, which inherits a particular object and does custom implementation of that common object.
Each "plugin" unit has an initialization clause at the bottom which registers this class with a global list. So long as that unit is "used" anywhere in the project, it gets registered into a global list, which this custom control makes use of to populate a list of all possible "plugin" units.
For example, this custom control has a property:
property PluginIndex: Integer read FPluginIndex write SetPluginIndex;
Internally, this index corresponds with one of the "plugins" which was registered from within the initialization section of its corresponding unit.
These "plugins" are registered via a global object which is instantiated like this upon first use:
function Plugins: TMyPluginList;
implementation
var
_Plugins: TMyPluginList;
function Plugins: TMyPluginList;
begin
if _Plugins= nil then
_Plugins:= TMyPluginList.Create;
Result:= _Plugins;
end;
The difficulty is that, since the control is implemented within a package (and installed into IDE), yet the "plugin" units are "used" from within another project, the package doesn't pick up the presence of these units, and therefore this custom control is also unable to access the global list, since it's in an entirely different context.
When interacting with this control on the form in design-time, if I set this PluginIndex in design-time, it fails because the control hasn't had any "plugins" register themselves in the global list. But, in run-time, assigning that same property works just fine.
How do I do this in a way that my application which uses this custom control (which relies on client-uses of each "plugin" unit) is able to actually detect these units used?
EDIT
The end goal of what I'm doing is to allow this single custom control to be simply dropped on the form, then have specific units "used" in that same form, and finally on this single custom control instance, choose the index of which of those "plugins" to actually use at any given time. I'm trying to encapsulate and automate as much of the process as possible, making it easier for a developer to simply drop this custom-control and not have to write a bunch of other code to make it work.
EDIT
I realize that this may be interpreted as these "plugin" units being a part of the package. That is not the case. Although currently I have no choice but to add these "plugin" units to the package in order to make design-time work right, I don't want it to be a part of the package, and rather up to the developer using this custom control. They can add a combination of pre-made "plugin" units as well as custom-made ones, simply by "using" them in their application.

Preventing component creation - Delphi

I am creating an application which makes use of several TTabsheets (from the TPageControl component). Is it possible to prevent a component (in this case a tab) from being created during the program startup? I want to manually create the tabs at a later stage.
This is not a dynamic component. It was created in the Delphi 2010 IDE.
Thanks!
If you include components in the designer, then they will be created when the form is created. Nothing you can do to stop that.
The logical conclusion is that you need to create the components at run time. One obvious way to make that easier is to put the components on a frame and create that at run time. That will allow you to group related components and do the visual design and property specification at design time, but then postpone creation until you know you need them.

Will there be any detrimental effects if I accidentally remove something from a forms uses list which a control is referencing?

Let's say that I have a datamodule with an ImageList. I also have a form with a button. If I wanted to hook up the ImageList property of the button, I would add the DataModule to the forms uses then select the ImageList in the Image drop-down in the button properties.
However, I can now remove the DataModule from the Forms uses list and things still seem to work fine.
Additionally, if the DataModule is open in the IDE and not in the forms uses list, I can manually type into the images property of the button the name of the image list, and it seems to correctly display the image on the button.
The Question: Will there be any detrimental effects if I accidentally remove something from a forms uses list which a control is referencing?
I am currently in the process of cleaning up the uses lists of hundreds of forms in a large project (using cnPack and Icarus) and I want to know how careful (or ruthless) I need to be.
For the IDE being able to find a DataModule (for properties not once set) at design time, the following must be true:
The DataModule must be opened/created at least once during the session of the IDE (it may be closed afterwards during the session), see (*), and
The DataModule unit must be present in the uses clause of the Form unit.
For the IDE being able to find a DataModule again (for properties already set) at design time, the following must be true:
The DataModule must be opened/created at least once during the session of the IDE (it may be closed afterwards during the session), or
The DataModule unit must be present in the uses clause of the Form unit, or
The DataModule unit must be added to the project file.
For the program being able to find a DataModule (for properties already set) at runtime:
The DataModule must be created, or
The DataModule unit must be present in the uses clause of the Form unit.
For the program being able to find a DataModule (for properties not set) at runtime:
The DataModule unit must be present in the uses clause of the Form unit.
Thus, theoretically, if all the right conditions are met, your DataModule unit could be omitted from the uses clause of the Form. But to be confident of runtime linkage, I would conclude that there is no safe or at least no convenient escape from adding the DataModule unit to the Form unit's uses clause.
(*) In large projects with many Forms and DataModules, it is very common to not open every DataModule in the IDE, and settings easily can get lost. Being dependent on the designtime binding by DataModule name then may result in your Forms never showing any data (or Images in this case). This is a bug which is hard to foresee whithout checking every Form's DataModule settings.
A solution to that is to set all properties which refer to a DataModule's components manually at runtime, preferably in an overriden constructor or in an OnCreate event handler. This also prevents duplicate naming issues with multiple DataModule instances, as this question deals with.
The linking of component properties (like Images) is independent of a suitable entry in the uses list. The magic is hidden inside the streaming system (look for xxxFixUpReferences). As long as the compiler is not complaining you can safely remove those entries.
It is still possible that the IDE might not be happy with that.

Modifying VCL Component CODE

I need to change the functionality in a component. What do you do when you get a "you can't override this" message, or you need to change the code in a private method ("method does not exist in base class" message), rendering it impossible to descend the component?
If I face that problem,
I first try to inherit from the component, or its CustomXXX ancestor and see if that fixes the problem. If that doesn't,
I go deeper, i.e. try to intercept the messages that come in. That can be done dynamically. If that turns out to be too deep, because the code that has to be built on that is too extensive, or if I still have to access items I can't access,
I try hacks. One hack is to copy the component and the dependent code to a new unit with a different name, rename the component and modify what needs to be modified.
Sometimes I only need to redo one or two methods to make my new behaviour possible.
Never forget to give the unit a different name and the component a different name too (possibly inheriting from the original component or one of its ancestors, so they remain in the same hierarchy). Do never modify the original sources and then recompile the VCL. That is a maintenance nightmare.
I am no fan of interposer classes, i.e. classes that get the same name but different behaviour than the original classes, inheriting from the original. Their functionality depends on the order of inclusion in the uses clause, and that seems rahter flaky to me. I can't recommend that.
But what I do greatly depends on the problem. I don't think one can (or should) give a blanket advice that covers all situations.
But my main advice: do not modify the original units, always put the new code in a new unit and use a new class name. That way the original and the modified versions can peacefully co-exist, also in the IDE.
There are some (mainly hacky) options when it comes to modifying private methods or behavior therein:
modify the original source, recompile the unit and use the changed dcu as suggested here; never did this but I think this can cause you a good headache when your code uses the new dcu but other VCL code don't
often component behavior is controlled by numerous window messages - look if you can achieve your change by modifying the reaction on some of these messages; you can override the message handling methods (the ones with the message keyword) even if they are declared private and you can also replace the WndProc
you can use hacks like this one which is tinkering with casting
you could use some detour mechanism as described in the answers here
Or you can get another component.

Visual Form Inheritance problem. "cannot inherit from (parent form). Contains a component that does not support inheritance"

I have a base form with descendents. The base form has a TElRelDataSource on it (from ElPack v4.00). When I open the descendent form I get an error "cannot inherit from (parent form). Contains a component that does not support inheritance". This is with the ancestor forms open (there are two), to avoid the "ancestor for (parent form) not found" error.
Delphi 7 doesn't (AFAIK) support finalising classes, but this seems to be a standard error message. It's in the index for "Tomes of Delphi: Troubleshooting" but I don't have a copy of that and I'm reluctant to spend $US60 to read an entry like "this is why you should avoid VFI" (being pessimistic about the contents of the book). Other than that, no references in Google or Bing.
This is in code that I've recently inherited from someone who left a while ago and I'm the first person to change it since they left. Which means I can't ask how he created the offending form.
So, how do I get around this error message?
You got yourself into an interesting problem. First of all, you say the parent form already includes the offending DataSource, so you've got to ask yourself a question: How did the original developer manage to put the dataset on the parent form and then create child forms, if creating child forms is rejected by the datasource?
The original code didn't have the TElRelDataSource
This implies you're trying to add it your self. Don't add it, find an other solution that doesn't rely on the TElRelDataSource.
The original code did have it!
The original was probably compiled against a different version of TElRelDataSource, one that did allow inheritance. "Inherability" is controlled by the "csInheritable" component style. That is, if the component doesn't include "csInheritable" in ComponentStyle, the Delphi IDE will not allow visual inheritance. You have a number of options:
Use a different version of TElRelDataSource, maybe the original was compiled against a NEWER version of TElRelDataSource. If you are using the latest TElRelDataSource, the author probably decided it's code can't handle visual inheritance so he/she removed the csInheritable flag from ComponentStyle!
Try making your own derived component and set that style yourself. This is easily done, but if TElRelDataSource's author removed the csInheritable flag for a reason, you'll probably get into trouble.
Normally HeartWare's idea would work just fine; Unfortunately it's not that easy with a DATA SOURCE component: I assume you have DB-Aware controls linked to that data source. If you create the DataSource from code, you'll need to re-create the connections to data-aware controls as well, and that's going to take a lot of "if-s" (or clever use of RTTI).
You may try moving the DataSource to a TDataModule. This is probably more trouble then it's worth it.
One option would be to remove the offending component from the form and allocate it dynamically in the FormCreate event. Depending on how many properties the (presumed) non-visual Data Source component has, this could be fairly simple.

Resources