Recent

Author Topic: passing parameter to a form  (Read 1019 times)

vdubeau

  • New Member
  • *
  • Posts: 27
passing parameter to a form
« on: May 11, 2024, 09:36:49 pm »
Let me explain my scenario. I have a form with a DBGrid that displays basic invoice information from an SQLite datebase. if i click or double click on a grid line i want to open a new form with the invoice details. I would need to pass the invoice number from form1 to form 2. I've searched on Google and here on the forum and find all of the answers confusing. Other development environments sometimes suggested using global variables but I hate that idea.

Any good code examples would be helpful.

Thanks.

MarkMLl

  • Hero Member
  • *****
  • Posts: 7485
Re: passing parameter to a form
« Reply #1 on: May 11, 2024, 09:59:44 pm »
The easiest way is one or more public fields (i.e. variables) or properties in the object (data structure) representing the form.

Another, since you're already using SQLite, would be to have a table with rows representing actions, and to have the form collect the next action and update it on completion.

Regrettably, globals aren't completely avoidable since Lazarus (and Delphi before it) represent each form using a global variable in the unit implementing it.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

TRon

  • Hero Member
  • *****
  • Posts: 3141
Re: passing parameter to a form
« Reply #2 on: May 11, 2024, 10:30:16 pm »
if i click or double click on a grid line i want to open a new form with the invoice details. I would need to pass the invoice number from form1 to form 2.
Is that form a modal form or a 'normal' form ?

In case a modal form you could consider exposing a global function that creates and shows the modal form using your parameters.

In case a normal form I would probably consider some sort of form display/update routine accepting the parameters.

But either way more details are required on how you have organized your fields e.g. how/when do you populate them.
All software is open source (as long as you can read assembler)

alpine

  • Hero Member
  • *****
  • Posts: 1240
Re: passing parameter to a form
« Reply #3 on: May 11, 2024, 11:08:48 pm »
Since it seems to be a question of personal preferences, my way is to define a public method. It also works with public properties, but they are just proxies to the setter methods:
Code: Pascal  [Select][+][-]
  1. type
  2.   TMyForm = class(TForm)
  3.   public
  4.     // public method to show an invoice details
  5.     procedure ShowInvoice(AInvoiceNr: String);
  6.  
  7.     // you can also define a property, but actually it doesn't make much sense
  8.     property InvoiceNr: String write ShowInvoice;
  9.   end;
  10.  
  11.   procedure TMyForm.ShowInvoice(AInvoiceNr: String);
  12.   begin
  13.     ReloadInvoiceInfo(AInvoiceNr); // to update controls
  14.     ShowModal; {or Show;}
  15.     CleanUp;
  16.   end;
  17.  

Or if the form isn't created by other means (e.g. auto-created) you can define it as a class method:
Code: Pascal  [Select][+][-]
  1. type
  2.   TMyForm = class(TForm)
  3.   public
  4.     // public method to show an invoice details
  5.     class function ShowInvoice(AOwner: TComponent; AInvoiceNr: String): Integer;
  6.   end;
  7.  
  8.   class function TMyForm.ShowInvoice(AOwner: TComponent; AInvoiceNr: String): Integer;
  9.   begin
  10.     with Self.Create(AOwner) do
  11.       try
  12.         ReloadInvoiceInfo(AInvoiceNr); // to update controls
  13.         Result := ShowModal;
  14.         CleanUp;
  15.       finally
  16.         Free;
  17.       end;
  18.   end;
  19.  

That is about just 'passing parameters' question. Obviously it depends on form lifecycle management and how it will be shown (form modality).

Using database components adds the same considerations but this time for connections, tables, queries, etc.

TL;DR When you want just to show a details of the current row in a modal form, you can just pass the TDataset as a parameter and then point TDataSources to it.

Code: Pascal  [Select][+][-]
  1. type
  2.   TMyForm = class(TForm)
  3.   public
  4.     // public method to show an invoice details
  5.     class function ShowInvoice(AOwner: TComponent; ADataSet: TDataSet): Integer;
  6.   end;
  7.  
  8.   class function TMyForm.ShowInvoice(AOwner: TComponent; ADataSet: TDataSet): Integer;
  9.   begin
  10.     with Self.Create(AOwner) do
  11.       try
  12.         {DataSource is the local component to which all data controls were bound}
  13.         DataSource.DataSet := ADataSet; {this should be enough to update the form}
  14.         Result := ShowModal;
  15.       finally
  16.         Free;
  17.       end;
  18.   end;

Of course if you want a non-modal form, e.g. for editing, then you should duplicate the Grid's DataSource/DataSet chain, and most probably to deal with separate connection for transactions isolation, etc. Much more complicated.


 
"I'm sorry Dave, I'm afraid I can't do that."
—HAL 9000

egsuh

  • Hero Member
  • *****
  • Posts: 1436
Re: passing parameter to a form
« Reply #4 on: May 12, 2024, 10:39:46 am »
Only based on the your description, you can simply access form2's variables and properties if they are defined in public section.


Code: Pascal  [Select][+][-]
  1. // unit 1
  2.  
  3. TForm1 = class (TForm)
  4.  ....
  5.    InvoiceNumber: integer;
  6.  
  7.    procedure ShowDetailForm;
  8. end;
  9.  
  10. procedure TForm1.ShowDetailForm;
  11. begin
  12.     Form2.InvoiceNumber := Self.InvoiceNumber;
  13.     Form2.Show;
  14. end;  
  15.  
  16.  
  17. // unit 2
  18.  
  19. TForm2 = class(TForm)
  20.    ...
  21. public
  22.       InvoiceNumber: integer;
  23. end;
 
« Last Edit: May 12, 2024, 11:13:57 am by egsuh »

Handoko

  • Hero Member
  • *****
  • Posts: 5290
  • My goal: build my own game engine using Lazarus
Re: passing parameter to a form
« Reply #5 on: May 12, 2024, 12:52:18 pm »
Done.

For some personal reasons, I prefer using TStringGrid rather than TDBGrid. But with some modifications the code below should work on TDBGrid too.

The mainform

Code: Pascal  [Select][+][-]
  1. unit Mainform;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, StdCtrls, Grids, SQLDB, SQLite3Conn, Info;
  9.  
  10. type
  11.  
  12.   { TfrmMainform }
  13.  
  14.   TfrmMainform = class(TForm)
  15.     Label1: TLabel;
  16.     StringGrid1: TStringGrid;
  17.     procedure FormCreate(Sender: TObject);
  18.     procedure StringGrid1DblClick(Sender: TObject);
  19.   end;
  20.  
  21. var
  22.   frmMainform: TfrmMainform;
  23.  
  24. implementation
  25.  
  26. {$R *.lfm}
  27.  
  28. const
  29.   DataFileName = 'Data.sqlite';
  30.  
  31. { TfrmMainform }
  32.  
  33. procedure TfrmMainform.FormCreate(Sender: TObject);
  34. var
  35.   Connection:  TSQLite3Connection;
  36.   Transaction: TSQLTransaction;
  37.   Query:       TSQLQuery;
  38.   i, j:        Integer;
  39. begin
  40.  
  41.   Label1.Caption        := 'Please double click an item in the grid below:';
  42.   StringGrid1.Anchors   := [akTop, akBottom, akLeft, akRight];
  43.   StringGrid1.FixedCols := 0;
  44.   StringGrid1.FixedRows := 0;
  45.   StringGrid1.Options   := StringGrid1.Options + [goRowSelect];
  46.   Constraints.MinHeight := 240;
  47.   Constraints.MinWidth  := 320;
  48.  
  49.   // Prepare connection
  50.   Connection              := TSQLite3Connection.Create(nil);
  51.   Connection.DatabaseName := ExtractFilePath(ParamStr(0)) + DataFileName;
  52.   Transaction             := TSQLTransaction.Create(nil);
  53.   Query                   := TSQLQuery.Create(nil);
  54.   Connection.Transaction  := Transaction;
  55.   Query.DataBase          := Connection;
  56.  
  57.   // Generate some data
  58.   if not(FileExists(Connection.DatabaseName)) then
  59.   begin
  60.     Connection.CreateDB;
  61.     Transaction.StartTransaction;
  62.     Query.SQL.Text :=
  63.       'CREATE TABLE tblUser ( '                         +
  64.       'ID INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, ' +
  65.       'Name TEXT NOT NULL UNIQUE, '                     +
  66.       'Email TEXT, '                                    +
  67.       'CHECK (LENGTH(Name) <= 20 AND LENGTH(Email) <= 30) );';
  68.     Query.ExecSQL;
  69.     Query.SQL.Text :=
  70.       'INSERT INTO tblUser (Name, Email) VALUES ' +
  71.       '(''' + 'Handoko' + ''', ''' + 'me@myemail.com'    + '''), ' +
  72.       '(''' + 'Harry'   + ''', ''' + 'harry@myemail.com' + '''), ' +
  73.       '(''' + 'Susan'   + ''', ''' + 'susan@myemail.com' + '''), ' +
  74.       '(''' + 'Andy'    + ''', ''' + 'andy@myemail.com'  + ''');';
  75.     Query.ExecSQL;
  76.     Transaction.Commit;
  77.   end;
  78.  
  79.   // Read data and put them into the grid
  80.   Transaction.StartTransaction;
  81.   Query.SQL.Text := 'SELECT COUNT(*) FROM tblUser;';
  82.   Query.Open;
  83.   StringGrid1.RowCount := Query.Fields[0].AsInteger;
  84.   Query.Close;
  85.   Query.SQL.Text := 'SELECT * FROM tblUser;';
  86.   Query.Open;
  87.   StringGrid1.ColCount := Query.FieldCount;
  88.   i := 0;
  89.   while not(Query.EOF) do
  90.   begin
  91.     Inc(i);
  92.     for j := 0 to Query.FieldCount-1 do
  93.       StringGrid1.Cells[j, i-1] := Query.Fields[j].AsString;
  94.     Query.Next;
  95.   end;
  96.   Query.Close;
  97.   Transaction.Commit;
  98.  
  99.   // Close the connection
  100.   Query.Free;
  101.   Transaction.Free;
  102.   Connection.Free;
  103.  
  104. end;
  105.  
  106. procedure TfrmMainform.StringGrid1DblClick(Sender: TObject);
  107. var
  108.   ID: string;
  109. begin
  110.   ID := StringGrid1.Cells[0, StringGrid1.Row];
  111.   if not(ID = '') then
  112.     frmInfo.ShowInfo(DataFileName, ID);
  113. end;
  114.  
  115. end.

Passing the data to the sub form is done on the line #112.

The sub form

Code: Pascal  [Select][+][-]
  1. unit Info;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, StdCtrls, SQLDB, SQLite3Conn;
  9.  
  10. type
  11.  
  12.   { TfrmInfo }
  13.  
  14.   TfrmInfo = class(TForm)
  15.     Button1: TButton;
  16.     Memo1: TMemo;
  17.     procedure Button1Click(Sender: TObject);
  18.     procedure FormCreate(Sender: TObject);
  19.   private
  20.     FDataFileName: string;
  21.     FID:           string;
  22.   public
  23.     procedure ShowInfo(const DataFileName, ID: string);
  24.   end;
  25.  
  26. var
  27.   frmInfo: TfrmInfo;
  28.  
  29. implementation
  30.  
  31. {$R *.lfm}
  32.  
  33. { TfrmInfo }
  34.  
  35. procedure TfrmInfo.Button1Click(Sender: TObject);
  36. var
  37.   Connection:  TSQLite3Connection;
  38.   Transaction: TSQLTransaction;
  39.   Query:       TSQLQuery;
  40.   S:           string;
  41. begin
  42.  
  43.   if (FDataFileName = '') or (FID = '') then Exit;
  44.   S := ExtractFilePath(ParamStr(0)) + FDataFileName;
  45.   if not(FileExists(S)) then Exit;
  46.  
  47.   Connection              := TSQLite3Connection.Create(nil);
  48.   Connection.DatabaseName := S;
  49.   Transaction             := TSQLTransaction.Create(nil);
  50.   Query                   := TSQLQuery.Create(nil);
  51.   Connection.Transaction  := Transaction;
  52.   Query.DataBase          := Connection;
  53.   Transaction.StartTransaction;
  54.   Query.SQL.Text := 'SELECT * FROM tblUser WHERE ID=''' + FID + ''';';
  55.   Query.Open;
  56.   S := 'User ID: ' + Query.FieldByName('ID').AsString   + LineEnding +
  57.        'Name: '    + Query.FieldByName('Name').AsString + LineEnding +
  58.        'Email: '   + Query.FieldByName('Email').AsString;
  59.   Query.Close;
  60.   Transaction.Commit;
  61.   Query.Free;
  62.   Transaction.Free;
  63.   Connection.Free;
  64.   Memo1.Lines.Clear;
  65.   Memo1.Lines.Add(S);
  66.  
  67. end;
  68.  
  69. procedure TfrmInfo.FormCreate(Sender: TObject);
  70. begin
  71.   FDataFileName := '';
  72.   FID           := '';
  73. end;
  74.  
  75. procedure TfrmInfo.ShowInfo(const DataFileName, ID: string);
  76. begin
  77.   FDataFileName := DataFileName;
  78.   FID           := ID;
  79.   Memo1.Clear;
  80.   Show;
  81. end;
  82.  
  83. end.

Handoko

  • Hero Member
  • *****
  • Posts: 5290
  • My goal: build my own game engine using Lazarus
Re: passing parameter to a form
« Reply #6 on: May 12, 2024, 08:45:32 pm »
I forgot to mention, to be able to run the code in the reply #5, you need SQLite installed or have the SQLite3.dll put in the program folder.

 

TinyPortal © 2005-2018