Re: Create Forms via Parameter

From: Peter Below (TeamB) (100113.1101_at_compuXXserve.com)
Date: 12/12/03


Date: Fri, 12 Dec 2003 12:19:06 +0100

In article <3fd977b9@newsgroups.borland.com>, Arda Han wrote:
> Anybody help me please! Peter Below where are you?

Actually i'm at home suffering from some flu-like symptoms <g>.

> My table structure :
> MenuName,FormName,Note,MenuParent,MenuID
>
> I want create dynamically menu and call assigned form from Table.
>
> I am create menu but I cann't create Form. Ian'c code is not running? Help
> me please...

If you store the forms name (the content of the Name property) you need to
prefix a "T" to it to get the classname. You register form classes, so you
need the classname to retrieve a class registered via RegisterClasses.

There are likely hundreds of examples of this stuff in the newsgroup
archives, one of them is this:

<quote
source="http://codecentral.borland.com/codecentral/ccweb.exe/listing?id=1937
4">
Another take on creating forms "by name" or "by classname"

> A fellow developer and I have a database in which is imbeded names of
> various forms.
>
> When we access the DB we can of course retreive the name as as cmd_text.
>
> Now we need to execute or run the value of cmd_test.
>
> The best, but prolly not feasable in D7, would be able to instansiate a
> TAction for cmd_text then run it from an action list.

I don't see how you get the TAction into the picture, it will certainly
not create a form for you automatically.

The problem to solve is how to get from a form *name* (or classname)
held in a string to a form instance you can show. How to go about that
depends a bit on how you create your forms.

a) the forms are all autocreated on application startup.

This is a very bad idea in large applications, since it makes your app
consume a lot of resources which may never be needed, but it is the
default setup you get when you don't tell the IDE not to autocreate forms
(with the exception of the main form) for you.

In this scenario the form instances already exist, you just need to find
them. Since all autocreated forms are owned by the Application object
the best way to do this is:

 Function ShowFormByName( const formname: String;
                          showit: Boolean = true ): TForm;
   Var
     comp: TComponent;
   Begin
     comp := Application.FindComponent( formname );
     If Assigned( comp ) and (comp Is TForm) Then Begin
       Result := Tform( comp );
       If showit Then
         Result.Show;
     End
     Else Begin
       Result := nil;
       Assert( false, 'Form '+formname+' not found' );
     End;
   End;
       
If what you have is a class name, not a form name, i would iterate over
the Screen objects Forms property:

 Function ShowFormByClassname( const classname: String;
                               showit: Boolean = true ): TForm;
   Var
     i: Integer;
   Begin
     Result := nil;
     For i:= 0 to Screen.Formcount-1 Do
       If Screen.Forms[i].ClassNameIs( classname ) Then Begin
         Result := Tform( Screen.Forms[i] );
         If showit Then
           Result.Show;
         Break;
       End;
     Assert( Assigned( result ), 'Form '+classname+' not found' );
   End;
   
Note that you do not use the form variable the IDE creates for you here.
There is no way to find the address of that variable given its name, but
you really don't need to do that. You need the *content* of the
variable, the form reference, and that can be had the way shown above.

b) You create forms on demand and want to create a new instance of the
form, given its classname.

If your database tables contain the form name (not the class name) you
need to adhere to a naming convention that allows you to derive the class
name from the form name. The IDE uses one already: just prefix a 'T' on
the name and you have the classname.

To create an instance of a form we first need to identify the class and
get a class reference for it, so we can call the Create constructor on
that reference. For this we need a class registry that "knows" about the
available form classes and which we can query for the class using its
name. The VCL contains a suitable class registry, but the form classes
are not registered automatically in it. This you need to do yourself.
You do it by adding an Initialization section to every unit that
implements a form you want to be able to create this way:

Initialization
  RegisterClass( TfrmCustomerDetail );
End.

If you have not worked with Initialization sections before: they go at
the very end of a unit.

If the classes are all registered properly we can use functions similar
to the ones above:

 Function CreateFormByClassname( const classname: String;
                                 showit: Boolean = true ): TForm;
   Var
     classref: TPersistentClass;
   Begin
     classref := GetClass( classname );
     If Assigned( classref ) and classref.InheritsFrom( TForm ) Then Begin
       Result := TFormClass( classref ).Create( Application );
       If showit Then
         Result.Show;
     End
     Else Begin
       Result := nil;
       Assert( false, 'Form '+classname+' not found' );
     End;
   End;

 Function CreateFormByName( const formname: String;
                            showit: Boolean = true ): TForm;
   Begin
     Result := CreateFormByClassname( 'T'+formname, showit );
   End;

The caller takes ownership of the form reference returned by the
functions. If it passes false for showit and then shows the form modally
it should free it it when the showmodal call returns:

  with CreateFormbyClassname( classname, false ) do
  try
    If showmodal = mrOK then
      ... do something
  finally
    free
  end;
  
You can of course also assign the returned reference to a local variable
of type TForm to work with it.

If the form is shown modeless (pass true for showit or omit the
parameter) it should have a handler for the OnClose event that sets
Action := caFree, this way the form will self-destruct when the user
closes it.

Again you do not use the IDE-created form variable. In fact you should
delete this variable from the units source code if you create forms
dynamically this way, it is no use and can lead to errors if you
refer to it in your code, since it will never contain the form
reference you need.

</quote>

--
Peter Below (TeamB)  
Use the newsgroup archives :
http://www.mers.com/searchsite.html
http://www.tamaracka.com/search.htm
http://groups.google.com
http://www.prolix.be


Relevant Pages

  • Connection String Security
    ... Do anyone has any reference about storing connection ... string in registry? ...
    (microsoft.public.sqlserver.security)
  • Re: c:windowsinet20001winlogon.exe (unable to find)
    ... Open the Registry Editor... ... How to backup the Windows XP Registry ... Or get Startup Control Panel and use it to disable any reference to ...
    (microsoft.public.windowsxp.help_and_support)
  • Re: Access Registry
    ... OpenNETCF.Win32.Registry and replace with a reference to OpenNETCF it should ... its the registry project ... >> Peter Foot ... >>>> libraries ...
    (microsoft.public.dotnet.framework.compactframework)
  • Re: Hard coded? Reference in Template
    ... backup to an GUID/ID in the registry. ... to the file path. ... > My Visio has a reference to a COM object that we use. ...
    (microsoft.public.visio.developer.vba)
  • Re: RUNDLL startup error message
    ... That suggests that some malware was removed, but the reference to the file was not removed from the registry. ... You can click File, Export, and save the entry to the Desktop, attach the file to a post in this thread; someone might note whether it's safe to delete first. ... If you remove it and there's a problem, double-click the .reg file you exported to the Desktop and it'll be added to the registry again. ... System.INI tab, and Win.INI tab for any reference to the file. ...
    (microsoft.public.windowsxp.general)