Call another form and return multiple values (Views: 27)
Problem/Question/Abstract: I have a main form that will call a second form to use for searching on different criteria. How can I return multiple values retrieved in the second form to the main form? Answer: Solve 1: Well, you need to add the second forms Unit to the first ones Uses clause, so you can call up the form. This gives you access to the forms controls and methods. It is usually bad design to access the forms controls from outside, since this tightly couples the outside code to the form. Any change you make to the form may require a change to the code accessing the form. So decouple them. One way to do that is to add properties (public section of the form) for each data item you may need to access from outside. This way the form controls how the data is fetched from the controls or internal fields of the form, usually via Set and Get methods for the properties. The form is then used like this (assuming it is not autocreated): with TSearchform.create(application) do try {... assign start values to the forms properties here, if required} if ShowModal = mrOK then begin {... read values from the form properties here} end else {... user aborted, take appropriate action} finally free; end; This can be taken a step further to avoid the necessity for public properties in the first place (which exposes a kind of working contract to the outside world, which may reveal too much about the form or limit how you could modify it later too much). For that you create a non-visible class, derived from TPersistent, which holds the data items you need to transfer in and out of the form. The form is given overriden Assign and Assignto methods, which, when fed an instance of this data container, will copy the data between the form and the data container. Now all knowledge of how the forms handles the data is internal to the form, all the outside world needs to know is that it can assign a data container to it and vice versa: datacontainer := TDataContainer.Create; {... set up datacontainers data to fed into the form} searchform := TSearchform.create(application); try searchform.Assign(datacontainer); if searchform.ShowModal = mrOK then datacontainer.Assign(searchform) else {... user aborted, take appropriate action} finally searchform.free end; {... use datacontainer if user entered data and free it when done} The TDatacontainer class would reside in its own Unit, which is used by both form units. Solve 2: You have a variety of options: 1. Use "var" parameters: procedure TForm2.DoSomething(var Return1, Return2, Return3: Integer); begin Return1 := 1; Return2 := 2; Return3 := 3; end; procedure TForm1.Button1Click(Sender: TObject); var X, Y, Z: Integer; begin Form2.DoSomething(X, Y, Z); ShowMessage(IntToStr(X)); end; 2. Declare a record which aggregates your return values: type TReturnRecord = record Value1: Integer; Value2: Integer; Value3: Integer; end; function TForm2.DoSomething: TReturnRecord; begin Result.Value1 := 1; Result.Value2 := 2; Result.Value3 := 3; end; procedure TForm1.Button1Click(Sender: TObject); var R: TReturnRecord; begin R := Form2.DoSomething; ShowMessage(IntToStr(R.Value1)); end; 3. Declare a class which aggregates your return values: type TReturnClass = class Value1: Integer; Value2: Integer; Value3: Integer; end; function TForm2.DoSomething(AReturn: TReturnClass); begin AReturn.Value1 := 1; AReturn.Value2 := 2; AReturn.Value3 := 3; end; procedure TForm1.Button1Click(Sender: TObject); var R: TReturnClass; begin R := TReturnClass.Create; try Form2.DoSomething(R); ShowMessage(R.Value1); finally R.Free; end; end; Or you could use a list or array structure, or you could use an open array parameter. |