How to make an old form inherit from another? - delphi

I have an existing form and i want this form now, to inherit from another form.
For a new form i know how to do this, just go on File > New > Other > Inheritable items and select the father form. But what about an already existent form ?
Here is what i tried, change this :
type
TFrmMyForm = class(TForm)
To this :
type
TFrmMyForm = class(TFrmFatherForm)
But it doesn't seem to work, as FrmMyForm isn't importing FrmFatherForm components.
Is there a way to achieve this ?
Thanks

Open dfm file in some other text editor and replace object with inherited
object FrmMyForm : TFrmMyForm
to
inherited FrmMyForm : TFrmMyForm
However, Delphi has issues with opening such forms if they don't belong to the same project. For instance, if you have base form declared in a package and you are using it to inherit forms in application or another package.
If you have problem opening such forms, make sure that you first open base form and then inherited.

Related

How to add a property to TTabSheet such that it can be used at design time with TPageControl

I would like to add "MyProperty" to TTabSheet and work with it at design time. However if I subclass it I fear I will need to also subclass TPageControl, since it internally creates/manages the TTabSheets.
I believe this would require duplicating the TTabSheet management code to reference TMyTabSheet instead of TTabSheet, since it will need to invoke TMyTabSheet.create. This feels like something I will regret when a new version of Delphi updates TPageControl and I forget to update TMyPageControl.
I am also researching "class helpers" as another option.
Does anyone have advice on how to best accomplish this?
Thanks!
Type Helpers are merely compile-time sugar, they would cause no effect over the already compiled code, that stock VCL is together with TPageControl and TForm. That is a dead-end.
However you have a slight misconception here that TPageControl... internally creates... the TTabSheets. Indeed, when you create the sheets by the means of TPageControl itself, like right-clicking it and selecting "New Tab" that si what happens. But when you create the living form object out of DFM file (or DFM resource in your compiled EXE) that is TForm itself that creates ALL the components, including both page control and its tabsheets.
Just see my answer at How to efficiently let a `ParentFont = False` child control to use same font name as parent? - that would show you how far it is about the owner - TForm, not about TPageControl or other parent components when it comes about selecting specific classes for the actual tabs or other elements..
So you are free to pursue subclassing tabsheets only.
Create the TMyTabsheet = class(TTabSheet) component
Create and install into IDE the design-time package that would introduce new subclassed tab sheet to Delphi Form Editor
In your form put the stock TPageControl and create all the needed tabs regular way
in IDE form Editor right-click over the form free space and in the menu do the "View As Text Alt-F12" command - you would see the text content of your form's DFM file
in those DFM sources find your tab sheets and change their stock TTabSheet class to be your derived sub-class
right-click the text editor and choose "View As Form Alt-F12" command
If all was done correct then Delphi would recreate the form with your new-class sheets now. Find your new properties in Object Inspector and change them.
Now switch to .Pas sources of your form and find the declarations of those tab sheets and change their type too. That is only required if you would have to access your new properties from the Delphi sources. If not you can leave their declaration as TTabSheet in pas-file as your class is direct descendant from it. You may leave those declarations as they were - but then you would have to add RegisterClass(TMyTabSheet); call into the very initialization section at the bottom of your unit, so when the form would construct itself out of the DFM it would be able to find the class implementation by the name. If you would change the declaration (at least one of those) then your form would automagically call all needed RegisterClass before streaming out of DFM. Choose any option you like.
Optionally and later, extend your design-time package to find and hijack IDE Form Editor's right-click menu for TPageControl and add "New My Subclassed Tab" command there. Just to avoid manual post-factum DFM editing. if you would do it often
This feels like something I will regret when a new version of Delphi updates TPageControl
After you created and tuned the form and saved it into DFM - it would be TForm that creates all the components out of the saved DFM-data, and that includes your tabs too. Unless very improbable event EMBT would kill the whole VCL streaming (made back in Delphi 1 in 1995) and redesign it from scratch (killing all the compatibility with existing Delphi sources at once), there should be no problem with forward compatibility with specifying your class in DFM. It is just the standard way VCL is designed - to get specific component types from the DFM.

How to debug or fix "Module has open descendants or linked modules" error?

I've had this long time problem that I can't view as text the main form for a project I inherited. Even if no other forms are open.
How can I debug the cause of this error message? What options do I have to fix it?
I found one related newsgroup post http://embarcadero.newsgroups.archived.at/public.delphi.ide/200906/0906193960.html but this only addresses the form inheritance cause, and doesn't explain anything about linked modules. I don't believe I'm using form inheritance.
I do have a DM (data module) for the project, and the form does load a couple of images from the dm through properties of a TTreeView on the form--does having a data module automatically mean I can never view as text a form in Delphi (aside from viewing the form as text in notepad)? It doesn't seem to matter whether my DM is open or closed in the IDE.
I also found one SO question with a related title (Module %s has open descendants or linked modules. can not reload) but the question itself and it's answer is not particularly relevant.
This is sometimes caused by a form that inherits from another form in your project (or the gallery) (known as Visual Form Inheritance in the documentation, IIRC). The IDE doesn't know how to find the base class for the form; it needs that opened before the descendant form. For instance, this can cause the same error if the unit containing TMyBaseForm isn't opened first in the IDE, particularly if the base (ancestor) unit is not included in the project first:
unit SpecialForm;
interface
uses
Forms, { all the other usual stuff }, BaseForm;
type
TMySpecialForm = class(TMyBaseForm)
private
public
end;
You can tell if this is the case by looking at your form's class declaration - if it descends from anything other than TForm, this is probably the cause of the error.
(Another instance of it happening is often when using a datamodule, because the base TDataModule .DFM isn't available. Attempting to view the datamodule .DFM as text will cause this error every time; the solution is to close your project and use an external editor such as Notepad or Notepad++ to edit the .dfm for your datamodule.)
I've had this issue occasionally, perhaps when I've used Frames, but my latest instance didn't involve Frames nor Data Modules nor inherited forms.
After an enormous amount of work creating a copy of the form (which copy didn't have the problem) and renaming the original unit and the form itself (which initially seemed to solve the problem), it turned out to be a live binding between forms.
Specifically, in my FMX application Form A has an options page with a TSpinBox that allows the user to set the minimum value for a TTrackBar on Form B (which was the form giving me grief). So the TSpinBox.Value was set to update the TTrackBar.Min field by means of a live binding. Closing Form A, or removing that live binding (and replacing it with an event handler to do the same thing) solved the problem.
I'd like to call upon the answer of Phillip J. Rayment and ADD that you don't have to have live binding to have this problem occur. It's sufficient to have custom control (class) of which you have an instance in another form. Then the RLink32 problem can appear and won't be solved until you close the form where you have the instance. The problem I experienced gave the following messages:
-RLink32 (during building)
-Access violation in module designide160.bpl` (if I made a modification to the problematic form)
-The module has open descendants or linked modules” error (if I tried to 'View as Form')

Transfer data between forms in borland c++ builder

I designed two forms in c++ builder:
TfrmMain
TfrmChooseName
In TfrmMain class I have button named btnNext. when btnNext is clicked, code below runs and creates new TfrmChooseName.
frmChooseName = new TfrmChooseName(this);
this->Hide();
frmChooseName->ShowModal();
this->Show();
delete frmChooseName;
frmChooseName = NULL;
also in TfrmMain I have TEdit control named txtInput.
In costructor of TfrmChooseName I want to get text of txtInput and set it as a caption of form but access volation error occured!
I also made both classes friend!
The best way to handle this is to pass the desired Caption value to the constructor itself, rather than code it to hunt for the value, eg:
__fastcall TfrmChooseName(TComponent *Owner, const String &ACaption)
: TForm(Owner)
{
Caption = ACaption;
}
.
frmChooseName = new TfrmChooseName(this, txtInput->Text);
Alternatively, you can set the Caption after the constructor exits, eg:
frmChooseName = new TfrmChooseName(this);
frmChooseName->Caption = txtInput->Text;
I think it's not possible to detect the exact problem without seeing more of the code. Making the classes friends shouldn't be necessary, since components added using the form designer have public access anyway.
Have you removed TfrmChooseName from Auto-Create forms? If not, and if frmChooseName is the global variable pointing to the auto-created form, that might cause the Access Violation.
The RADStudio Documentation article Creating Forms Dynamically says:
Note: If you create a form using its constructor, be sure to check that the form is not in the Auto-create forms list on the Project > Options > Forms page.
Specifically, if you create the new form without deleting the form of the same name from the list, Delphi creates the form at startup and this event-handler creates a new instance of the form, overwriting the reference to the auto-created instance. The auto-created instance still exists, but the application can no longer access it. After the event-handler terminates, the global variable no longer points to a valid form. Any attempt to use the global variable will likely crash the application.
You may also want to take a look at Creating a Form Instance Using a Local Variable.

error while creating form in delphi

Hi I am having delphi application which uses more than 100 forms. There is one form call Form B which derived from the Form A.
Unit B
interace
uses A;
Type
Form B = Class(Form A)
End;
Now, when i try to open Form B on the IDE i m getting the error, "Error cerating form: Ancestor for TFormA not found". But when i open Form A and then try to form B then i am able to open form without any error.
I am not able to find why its happening. Am i missed something?
Two items to keep in mind when using form inheritance. The dfm file needs to have the declaration "inherited TFormB" instead of "object TFormB" The other item is Delphi needs to know where TFormA is located before it can create TFormB. It's been a while since I have done this and if I remember correctly, it works better when the base form has been added to the repository
Since you point out you did it manually make sure that the declaration in the dfm is using the word "inherited" instead of "object" as I described above. To make the change yourself do the following
1) open both forms.
2) Then view TFormB as text
3) Change it to inherited like described below
inherited FormB: TFormB
Caption = 'FormB'
PixelsPerInch = 96
TextHeight = 13
end
// not
object FormB: TFormB
Caption = 'FormB'
PixelsPerInch = 96
TextHeight = 13
end
You should use visual form inheritance provided by Delphi IDE; I have no Delphi 5, in Delphi XE it is accessed by File->New->Other...->Inheritable Items. I am sure it is available in Delphi 5 too, but probably from a different menu item
I had the same problem despite everything being "inherited" in the DFM file.
What fixed my problem was adding the ancestor file to the project by right-clicking in the project manager -> add and selecting the ancestor file.

Unable to open designer on form in C# 2010

I have generated a solution in C# 2010 by way of the Artinsoft conversion from VB6.
When I open the new solution in C# I right-click on the forms but there is no "View Designer" option. I assume this is because something is failing to compile. What could be the problem and how should I fix it?
Try a clean and rebuild
Make sure you have proper designer.cs file
Make sure the initialize method is called from the constructor of your Forms.
Make sure if there are any custom dlls they are in right places.
Better create a new app in Windows forms and check how the things are arranged. so that you can compare the conversion.
I would not expect that from a failure to compile, but rather a failure to convert properly. Even if the class doesn't compile, if it's a form you shouldbe able to see and edit the form portion.
The reason should be marked in the error list if it's failing to compile. It's more likely that it's created it as just a class (that doesn't inherit from Form).
Check that there's a MyForm.Designer.cs (where your form name is MyForm) and also check that the declaration of the class in MyForm.cs inherits from form
public partial class MyForm : Form
If this isn't the case, it hasn't converted properly, so you may have to inherit from form, drop on the UI controls again and hook them up to any events
Have you tried running Visual Studio as Administrator (elevated rights)?
Can you try Shift+F7 key combination?

Resources