2006. február 14., kedd
Call another form and return multiple values
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.
Feliratkozás:
Megjegyzések küldése (Atom)
Nincsenek megjegyzések:
Megjegyzés küldése