Henry Olive 5 Posted December 10, 2022 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
Stano 143 Posted December 10, 2022 (edited) How can you create something that is nil? More specifically, cast nil to something. Edited December 10, 2022 by Stano Share this post Link to post
Attila Kovacs 629 Posted December 10, 2022 CardForm := TCardForm.Create(Self) Share this post Link to post
Henry Olive 5 Posted December 10, 2022 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
programmerdelphi2k 237 Posted December 10, 2022 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
programmerdelphi2k 237 Posted December 10, 2022 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
programmerdelphi2k 237 Posted December 10, 2022 (edited) 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 December 10, 2022 by programmerdelphi2k Share this post Link to post
FPiette 383 Posted December 10, 2022 Try this: if CardForm = Nil then CardForm := TForm.Create(Self); Share this post Link to post
Stano 143 Posted December 10, 2022 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
programmerdelphi2k 237 Posted December 10, 2022 (edited) 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 December 10, 2022 by programmerdelphi2k Share this post Link to post
Pat Foley 51 Posted December 10, 2022 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
David Schwartz 426 Posted December 11, 2022 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? 1 Share this post Link to post
Henry Olive 5 Posted December 12, 2022 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
programmerdelphi2k 237 Posted December 12, 2022 (edited) 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 December 12, 2022 by programmerdelphi2k Share this post Link to post
PeterBelow 238 Posted December 12, 2022 (edited) 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 December 12, 2022 by PeterBelow Share this post Link to post
programmerdelphi2k 237 Posted December 12, 2022 (edited) 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. Edited December 12, 2022 by programmerdelphi2k Share this post Link to post
Pat Foley 51 Posted December 12, 2022 (edited) 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; Edited December 12, 2022 by Pat Foley a Create not Typed Share this post Link to post
Henry Olive 5 Posted December 14, 2022 Thank you SO much Peter, Programmer, Pat Share this post Link to post