You are here:

Delphi/Delphi returning a value from a form

Advertisement


Question
QUESTION: I want to be able to call a form which will contain a dbgrid of data from a database file. The user will select data from the
dbgrid (customer no) and the called form should return the selected data back to the calling form.
What is the best way of doing this please.

ANSWER: My favorite way is to create a class function that can show the form, allow value selection, then return the value.  Here's an example:

procedure TForm1.Button1Click(Sender: TObject);
var
 SelectedItem: integer;
begin
 SelectedItem := Form2.PickItem(-1);
 
 {Note that I've changed Form2 to be an alias to TForm2 and no longer a variable reference}

 ShowMessage(IntToStr(SelectedItem));
end;



unit Unit2;

interface

uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, StdCtrls, Buttons;

type
 TForm2 = class(TForm)
   ListBox1: TListBox;
   BitBtn1: TBitBtn;
   procedure FormCreate(Sender: TObject);
 private
   function GetSelectedItem: integer;
   { Private declarations }
 public
   { Public declarations }
   property SelectedItem: integer read GetSelectedItem;
   class function PickItem(const Default: Integer): Integer;
 end;

 Form2 = TForm2;
 {Note this Form2 is an alias to TForm2 and no longer a variable reference.  It keeps
  you from accessing the form's contents from other units which I think is a good practice}

implementation

{$R *.dfm}

class function TForm2.PickItem(const Default: Integer): Integer;
begin
 Result := Default;
 with Self.Create(nil) do
 try
   if (ShowModal = mrOk) and (SelectedItem > -1) then
     Result := SelectedItem;
 finally
   Free;
 end;
end;


procedure TForm2.FormCreate(Sender: TObject);
begin
 ListBox1.Clear;
 ListBox1.AddItem('First Choice', TObject(1));
 ListBox1.AddItem('Second Choice', TObject(2));
 ListBox1.AddItem('Third Choice', TObject(3));
 ListBox1.AddItem('Fouth Choice', TObject(4));
 ListBox1.AddItem('Fifth Choice', TObject(5));
end;

function TForm2.GetSelectedItem: integer;
begin
 if ListBox1.ItemIndex > -1 then
   Result := Integer(ListBox1.Items.Objects[ListBox1.ItemIndex])
 else
   Result := -1;
end;

end.


---------- FOLLOW-UP ----------

QUESTION: Extremely clever
Is there an explanation of how it works because I haven't a clue but it does.

Answer
Sure.  It's pretty simple once explained I'd bet.  I first came up with the idea when I saw how many Delphi developers would access one form's properties from another form...sometimes even both directions (called circular references).  It can really get you into a lot of trouble, so I would always delete the var FormX: TFormX variable and make a function like:

function SelectID(Title, OldValue: string): string;

implementation

function SelectID(Title, OldValue: string): string;
begin
 with TSelectIDForm.Create(nil) do    //creates an instance of the form
 try
   if ShowModal = mrOK then          //executes instances ShowModal method, waits for Result
     Result := Edit1.Text;          //Assigns a value to the result
 finally
   Free;          //Frees the instance.  The WITH allows omitting a VAR
 end;          //of type TSelectIDForm which is clean but confusing
end;          //to some developers


Once I learned how class functions could be used, I switched to the method I sent you.  A class method is kind of static and can be called on a class without creating an instance of the class.  It's often used to create and return an instance of the class in a class factory, but certainly not the only use of a class method.

class function TMyClass.CreateCustomInstance(const Default: Integer): TMyClass;
begin
 Result := Self.Create(Default); //Self is essentially a reference back to TMyClass
         //so TMyClass.Create(Default) is the same thing
         //but when using inheritance, using Self knows the real class
end;

So then I use this static class concept to create, popup, return result, and close/free the form.

class function TForm2.PickItem(const Default: Integer): Integer;
begin
Result := Default;          //if nothing is picked, pass back something.
with Self.Create(nil) do      //create an instance of TForm2
try
  if (ShowModal = mrOk) and (SelectedItem > -1) then  //show the form waiting for ModalResult
    Result := SelectedItem;   //if an item is picked, return that result
finally
  Free;          /free the created form instance
end;
end;

The last little bit is to make it look nicer when in use.  Using the class type to reference a method seems odd like TForm2.PickItem(1) plus I want to get rid of the Form var anyway, so I make a type the same name that the form would have been.

type
 Form2 = TForm2;

So my first example above could be used like:

 NewValue := ListSelect.SelectID('Select an ID', dbSampleID.AsString);

Where ListSelect is of type TListSelect and SelectID is now a class function that does all the work.

Hopefully that clears things up ;-)

Randy

Delphi

All Answers


Answers by Expert:


Ask Experts

Volunteer


Randy Sill

Expertise

Turbo Pascal and Delphi developer since 1986. Strengths - UI, Windows API, Database, SQL, Internet, Threading, NT Services.

Experience

Turbo Pascal and Delphi developer since 1986.

Education/Credentials
Delphi 5 Certification, Borland

Awards and Honors
2005 Indiana IT/Software Million Dollar Award, Key Technical Contributor

©2016 About.com. All rights reserved.