Jump to content

Recommended Posts

Good Day,

var
  CardForm:TForm;

begin

  if Dataset = dm.Customer then

     CardForm := fCustomer else

if Dataset = dm.Items then

   CardForm := fItems;

.....

.....

 

if CardForm = Nil then
      CardForm := TForm(CardForm).Create(Self);

end;

 

I'm getting Access Violation err.msg

What am i doing wrong ?

 

Thank You

 

Share this post


Link to post

How can you create something that is nil?

More specifically, cast nil to something.

Edited by Stano

Share this post


Link to post

Thank You Stano,  Attila

 

Attila,

 CardForm := TCardForm.Create(Self)

with above code i get below err. and cant compile

i get  [DCC Error] Unit2.pas(34): E2003 Undeclared identifier: 'TCardForm'  

Share this post


Link to post

you can try this way:

var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  Unit2,
  Unit3;

procedure TForm1.Button1Click(Sender: TObject);
var
  FormX: TFormClass;
begin
  FormX := TFormClass(FindClass('TForm2')); // TForm3
  if (FormX <> nil) then
    FormX.Create(nil).ShowModal;

end;

initialization

RegisterClass(TForm2); // needs register the "classes" in somewhere... to use it
RegisterClass(TForm3);

end.

 

Share this post


Link to post

or...

unit uMyRegisterForms;

interface

uses
  System.Classes;

implementation

uses
  Unit2,
  Unit3;

initialization

RegisterClass(TForm2);
RegisterClass(TForm3);

end.
var
  Form1: TForm1;

implementation

{$R *.dfm}

uses
  uMyRegisterForms;

procedure TForm1.Button1Click(Sender: TObject);
var
  FormX: TFormClass;
begin
  FormX := TFormClass(FindClass('TForm2')); // TForm3
  if (FormX <> nil) then
    FormX.Create(nil).ShowModal;

end;

end.

 

Share this post


Link to post
procedure TForm1.Button1Click(Sender: TObject);
var
  PersistentClass: TPersistentClass;
  FormX          : TFormClass;
begin
  //FindClass(...) raise an exception if not found, then is better use "GetClass(...)" directly!
  PersistentClass := GetClass('TForm4');
  //
  if (PersistentClass = nil) then
    exit;
  //
  FormX := TFormClass(PersistentClass); // TForm4 does not exist in my project...then will raise an exception using FindClass(...)
  if (FormX <> nil) then
    FormX.Create(nil).ShowModal;
end;

NOTE: Better use a "Local variable" and "FREE it" after usage!

xx := TMyForm.Create...
try
  ...
finally
  xx.Free;
end;

 

Edited by programmerdelphi2k

Share this post


Link to post

Jednoduchými slovami. Ak chceš vytvoriť nový prázdny formulár, tak použi príspevok od FPiette.
Ak nejaký existujúci tak

 CardForm := TMyForm.Create(Self);

 

Share this post


Link to post

I think it would be better then to use polymorphism, as the need is just to create a form according to the current value contained in a polymorphic variable! No?

Already, using "TFormClass", you exempt yourself from such a maneuver, because the very definition of the "type class" is generic for forms!

Myslím, že potom by bolo lepšie použiť polymorfizmus, pretože je potrebné len vytvoriť formulár podľa aktuálnej hodnoty obsiahnutej v polymorfnej premennej! nie?

Už pri použití „TFormClass“ sa oslobodíte od takéhoto manévru, pretože samotná definícia „triedy typu“ je pre formuláre všeobecná!

Quote

TFormClass = class of TForm;

 

Edited by programmerdelphi2k

Share this post


Link to post
5 hours ago, Henry Olive said:

var
  CardForm:TForm;

begin

  if Dataset = dm.Customer then

     CardForm := fCustomer else

if Dataset = dm.Items then

   CardForm := fItems;

procedure TfrmGettingStarted.Button1Click(Sender: TObject);
var
  grid,
  grid2: TDBGrid; //refs to grid instances in forms`
  Pop2: TformPop; //for example purposes
begin
  grid := formPop.grdProducts; //2   //allready did 1

  grid.DataSource := dsProducts;  //3 hookup

  //grid.Show; //not working in 11.1
  grid.Parent.Show;//4

  Pop2 := TformPop.Create(Application);//1
  grid2 := Pop2.grdProducts; //2

  grid2.DataSource := dsCategories;//3

  //grid.Show;
  grid2.Parent.Show;//4

end;

My thoughts are to change the Quoted to something like the above.   

1. make the forms h
2. Add data grid references to DM at start up. 

2.1 grid2.magically adjusts to data source some how
3. Set date grid reference data source. 
4. Show using parent lets the DM to not need these forms in uses clause! It only needs to know what DBgrid is.
5. Ewe has blog articles on the nuances needed using DM with multiple edit forms~ This example just shows the data.    
6. Added to an Example in Samples to verify.
 

 

Share this post


Link to post
22 hours ago, Henry Olive said:

Thank You Stano,  Attila

 

Attila,

 CardForm := TCardForm.Create(Self)

with above code i get below err. and cant compile

i get  [DCC Error] Unit2.pas(34): E2003 Undeclared identifier: 'TCardForm'  

Show us your definition of TCardForm.

At the top of the example you declared CardForm as a TForm. The compiler is complaining that it can't find TCardForm's definition anywhere. Where is it?

Maybe you're missing a unit in the uses clause?

  • Like 1

Share this post


Link to post

Thank you so much Programmer, Pat, David

 

I'm really so sorry, i think i couldnt express my problem well cause of my unsuffient english.

 

Suppose you have Form1 (Auto Create), Form2 (NOT Auto Create) , Form3 (NOT Auto Create)   

Lets say there is a Combobox1 in Form1 and ComboBox1.Items are 'A', 'B'

Also there is a Button1 on Form1

According to above explanations here below my codes

 

procedure TForm1.ShowForm (MyText : String);
  var
  MyForm : TForm;
begin
  if MyText ='A' then
     MyForm := Form2 else
  if MyText ='B' then
     MyForm := Form3;


  if MyForm = Nil then
     MyForm := MyForm.Create(Self); // Problem is here,  even if i use  MyForm := TMyForm.Create(Self)

 MyForm.Show;
end;

 

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowForm (ComboBox1.Text);
end;

 

Again i'm so sorry for not explaining the problem well.

 

 

 

 

 

 

 

 

Share this post


Link to post

look, "MyForm" in your sample WILL BE a "instance of a Object", then, you needs a "CLASS to create this instance"!

this class can TForm, TForm2, TForm3, or same TForm1 (but needs attention here)!

for that "MyForm := MyForm.Create... does not works!!!

 

you needs some like this:

MyForm := TFormClass( X_Class_to_Forms ).Create(...);

Edited by programmerdelphi2k

Share this post


Link to post
57 minutes ago, Henry Olive said:

Thank you so much Programmer, Pat, David

 

I'm really so sorry, i think i couldnt express my problem well cause of my unsuffient english.

 

Suppose you have Form1 (Auto Create), Form2 (NOT Auto Create) , Form3 (NOT Auto Create)   

Lets say there is a Combobox1 in Form1 and ComboBox1.Items are 'A', 'B'

Also there is a Button1 on Form1

According to above explanations here below my codes

 

procedure TForm1.ShowForm (MyText : String);
  var
  MyForm : TForm;
begin
  if MyText ='A' then
     MyForm := Form2 else
  if MyText ='B' then
     MyForm := Form3;


  if MyForm = Nil then
     MyForm := MyForm.Create(Self); // Problem is here,  even if i use  MyForm := TMyForm.Create(Self)

 MyForm.Show;
end;

 

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowForm (ComboBox1.Text);
end;

 

Again i'm so sorry for not explaining the problem well.

 

If you have forms that are not autocreated the first thing you should do is to delete the form variable (form2, form3 in your example) the IDE creates in the form unit since these variables will never be initialized unless you do it in code. Such forms, when only used modally, should be created inside the method showing them modally, and destroyed after their ShowModal method has returned and any user-entered data has been retrieved from the form. In such a scenario you use a variable local to the method showing the form to hold the form instance.

 

Your problem is basically to select the correct form class to create the form identified by the string passed to your ShowForm method. If you can live with needing to add the units containing the form classes in question to the Uses clause of the TForm1-Unit (use the one in the implementation section) you can do something like this:

procedure TForm1.ShowForm (MyText : String);
var
  MyFormClass : TFormClass;
  MyForm: TForm;
begin
  if MyText ='A' then
     MyFormClass := TForm2 
  else if MyText ='B' then
     MyFormClass := TForm3
  else
     MyFormClass := nil; 

  if Assigned(MyFormClass) then begin
     MyForm := MyFormClass.Create(Self);
     try
       MyForm.ShowModal;
     finally
       MyForm.Free;
     end;   
  end
  else
    ShowMessage('Unknown form class requested: '+MyText);
end;

If you really need to show the created form modeless you need a different approach. The safest way in my opinion is to simply search for the form in the Screen.Forms collection, using the form class as the search parameter.

 

function FindOrCreateFormByClass( aFormClass: TFormClass ): TForm;
var
  i: Integer;    
begin
  for i:= 0 to Screen.formCount - 1 do begin
    Result := Screen.Forms[i];
    if Result.ClassType = aFormClass then
      Exit;
  end;
  Result := aFormClass.Create( Application );
end;  

procedure TForm1.ShowForm (MyText : String);
var
  MyFormClass : TFormClass;
  MyForm: TForm;
begin
  if MyText ='A' then
     MyFormClass := TForm2 
  else if MyText ='B' then
     MyFormClass := TForm3
  else
     MyFormClass := nil; 


  if Assigned(MyFormClass) then begin
     MyForm := FindOrCreateFormByClass(MyFormClass); 
     MyForm.Show;
  end
  else
    ShowMessage('Unknown form class requested: '+MyText);
end;

This works if you only ever need one instance of a form class. If you need access to the created form later you do not use the IDE-created form variable (if you did not delete it) but search through the screen.forms collection again.

There are  ways to eliminate the need to add the form units to the TForm1 unit uses clause but they again require a different approach. You create a "form factory" singleton object in this case (google for "factory pattern") in a separate unit. The form classes would get registered with this factory together with the string identifying the class; in the form unit's Initialization section. The TForm1 unit would the only need to add this factory unit to its uses clause, and the factory would have a public method that corresponds to your current ShowForm method.

Edited by PeterBelow

Share this post


Link to post

try this: not necessary "it's a good example of Factories usage", but it will works!

 

unit uMyFormsT;

interface

uses
  System.Classes,
  System.SysUtils,
  Vcl.Forms;

type
  TMyFactoryToForms = class
  public
    class function CreateAForm(const AClassName: string): TForm;
  end;

implementation

{ TMyFactoryToForms }

uses
  uForm3,
  uForm4;

class function TMyFactoryToForms.CreateAForm(const AClassName: string): TForm;
var
  APersistentClass: TPersistentClass;
begin
  result := nil;
  //
  APersistentClass := GetClass(AClassName);
  if APersistentClass = nil then
    exit;
  //
  result := TFormClass(APersistentClass).Create(nil);
end;

initialization

RegisterClasses([TForm3, TForm4]);

finalization

UnRegisterClasses([TForm3, TForm4]);

end.
implementation

{$R *.dfm}

uses
  uMyFormsT;

procedure TForm1.Button1Click(Sender: TObject);
var
  AForm: TForm;
begin
  if (ListBox1.ItemIndex > -1) then
    begin
      AForm := TMyFactoryToForms.CreateAForm(ListBox1.Items[ListBox1.ItemIndex]);
      //
      if (AForm <> nil) then
        try
          AForm.ShowModal;
        finally
          AForm.Free;
        end
      else
        ShowMessage('Sorry, ' + ListBox1.Items[ListBox1.ItemIndex] + ', was not registered on system');
    end;
end;

initialization

ReportMemoryLeaksOnShutdown := true;

finalization

end.

image.png.20d5191c494f0fdb9fb0c95899472156.png

Edited by programmerdelphi2k

Share this post


Link to post
3 hours ago, Henry Olive said:

if MyForm = Nil then
     MyForm := MyForm.Create(Self); // Problem is here,  even if i use  MyForm := TMyForm.Create(Self)

 MyForm.Show;
end;

   

 You could try this if you want a form without a dfm. 

     MyForm := MyForm.TCreateNew(Self);  //was  MyForm := MyForm.Create(Self);

     //

    defaultDataGrid := Tdbxx.Create and set

    //Note add alignment after pix  

 Otherwise just autocreate your cardform.  As other's have mentioned what is it.

procedure TfrmGettingStarted.Button3Click(Sender: TObject);
var
  boardForm:TForm;
  boardGrid: TDBGrid;
begin
  boardForm := TForm.CreateNew(Application);

    boardGrid:= TDBGrid.Create(boardform);
    boardGrid.Parent := boardForm;
    boardGRid.Align := alClient;
    boardGrid.DataSource := dsProducts;

  boardForm.Show;
  boardGrid.Show;
end;

 

 

new.png

Edited by Pat Foley
a Create not Typed

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×