chrisbray
asked on
How can I determine whether a variable exists on a specified form?
I am trying to create a generic test routine to determine whether a form meets specified criteria. At the moment I have to list each form that contains a particular variable in order to typecast the form to the correct type to allow the check...
// Check ID match
if Length(FormIDString) = 0 then // Any instance will do
IDMatch := True
else
begin
if f is TListEditDialog then // For ListEditDialog
begin
IDMatch := (TListEditDialog(f).FormID String = FormIDString);
end;
if f is TBillForm then // For BillFormDialog
begin
IDMatch := (TBillForm(f).FormIDString = FormIDString);
end;
// other forms here, if the form is not listed the IDMatch default value of false is retained
end;
I need to check whether the variable FormIDString exists in the form (f) that has been passed, and check its value if it does. Can anyone suggest a better way that does not require the code to be modified any time a form is added to the project?
Chris Bray.
// Check ID match
if Length(FormIDString) = 0 then // Any instance will do
IDMatch := True
else
begin
if f is TListEditDialog then // For ListEditDialog
begin
IDMatch := (TListEditDialog(f).FormID
end;
if f is TBillForm then // For BillFormDialog
begin
IDMatch := (TBillForm(f).FormIDString
end;
// other forms here, if the form is not listed the IDMatch default value of false is retained
end;
I need to check whether the variable FormIDString exists in the form (f) that has been passed, and check its value if it does. Can anyone suggest a better way that does not require the code to be modified any time a form is added to the project?
Chris Bray.
ASKER
Hi Mike,
No. The whole point of the question is that the determination of existence has to be done at runtime - hence the code!!
This is a modular application and the forms that are available will vary depending on the specification the customer has chosen. Being modular, other forms are likely to be added at a later date as additional options, plug-ins and functionality are added. Therefore a design time check is pointless, not least because I already know whether the variable exists in the forms I have created and I can (as you can see from the code) hard code which ones do and do not.
I need to turn this into a generic routine that will work with any form...
If I were looking for a button I would use FindComponent, if that gives you any pointer?
Chris Bray.
No. The whole point of the question is that the determination of existence has to be done at runtime - hence the code!!
This is a modular application and the forms that are available will vary depending on the specification the customer has chosen. Being modular, other forms are likely to be added at a later date as additional options, plug-ins and functionality are added. Therefore a design time check is pointless, not least because I already know whether the variable exists in the forms I have created and I can (as you can see from the code) hard code which ones do and do not.
I need to turn this into a generic routine that will work with any form...
If I were looking for a button I would use FindComponent, if that gives you any pointer?
Chris Bray.
Ok I see.
I must admit Im unsure if you could write anything so generic to handle this as you are specifically trying to find certain classes. If the application does not know the definitions of the class to start with, it cant check for any variables on the actual form itself. You cant assume that the application would suddenly be able to pass in a form its never heard of before and know what to be casting against.
I would say that the way you are doing it at the moment is possibly the only way that would do it.
I could be wrong, and if so Id like to hear an alternate answer myself so Ill watch the thread.
I must admit Im unsure if you could write anything so generic to handle this as you are specifically trying to find certain classes. If the application does not know the definitions of the class to start with, it cant check for any variables on the actual form itself. You cant assume that the application would suddenly be able to pass in a form its never heard of before and know what to be casting against.
I would say that the way you are doing it at the moment is possibly the only way that would do it.
I could be wrong, and if so Id like to hear an alternate answer myself so Ill watch the thread.
Well, if it needs to be done at run-time, you can still convert the form you want to test to text, using the ObjectBinaryToText() function. Then (in code) you can locate the FormIDString in the text, and even check it's value.
hth, pritaeas.
hth, pritaeas.
polymorphism?
TMyForm = Class(tform)
FormIDString : TString;
derive all forms from TMyForm
Set FormIDString in constructor
function IDMatch(f : TMyForm; FormIDstring : TString) : Boolean
begin
IDMatch := (f.FormIDString = FormIDString);
end;
TMyForm = Class(tform)
FormIDString : TString;
derive all forms from TMyForm
Set FormIDString in constructor
function IDMatch(f : TMyForm; FormIDstring : TString) : Boolean
begin
IDMatch := (f.FormIDString = FormIDString);
end;
ASKER
Hi guys,
Thanks for your input. However...
Priteas: A VERY long way of finding out something incredibly simple which the system must already know! Doing that literally hundreds of times during the operation of a program is *way* too much of a processing overhead particularly considering that as it is a variable it must be added to the stack at some point, and therefore Delphi must already know whether it exists or not...
Philipjc: I could just as easily add the variable to all forms, which would ensure that it always exists but is not the point and is a waste of time for forms that don't need it. If I were to use your method I would also have to change every form in a very large application including multiple ancestor forms - not something that I want to embark upon to deal with a simple question of whether or not a particular variable exists.
I could also assign to the variable and trap any error that arises, but that would give rise to hundreds of entries in any error log that are unnecessary and unhelpful as well as being bad programming practice.
I am convinced that there is a simple way to do this with a minimum overhead, and am looking to find that method.
Chris Bray.
Thanks for your input. However...
Priteas: A VERY long way of finding out something incredibly simple which the system must already know! Doing that literally hundreds of times during the operation of a program is *way* too much of a processing overhead particularly considering that as it is a variable it must be added to the stack at some point, and therefore Delphi must already know whether it exists or not...
Philipjc: I could just as easily add the variable to all forms, which would ensure that it always exists but is not the point and is a waste of time for forms that don't need it. If I were to use your method I would also have to change every form in a very large application including multiple ancestor forms - not something that I want to embark upon to deal with a simple question of whether or not a particular variable exists.
I could also assign to the variable and trap any error that arises, but that would give rise to hundreds of entries in any error log that are unnecessary and unhelpful as well as being bad programming practice.
I am convinced that there is a simple way to do this with a minimum overhead, and am looking to find that method.
Chris Bray.
ASKER
I have found the answer for myself, and it is Properties that provide it:
(* In the form to be checked *)
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
fFormIDString: String;
published
property IDFieldString: String read fFormIDString write fFormIDString;
public
{ Public declarations }
end;
(* The check routine in a separate unit *)
// add var PropInfo: PPropInfo to routine
// add TypInfo to uses clause
begin
// ................
// other code here
// ...............
// Check ID match
if Length(FormIDString) = 0 then // Any instance will do
IDMatch := True
else
begin
IDMatch := False;
PropInfo := GetPropInfo(f.ClassInfo, 'FormIDString');
if Assigned(PropInfo) then
IDMatch := GetStrProp(f, PropInfo) = FormIDString;
end;
Existing := TagMatch and IDMatch;
// ................
// other code here
// ...............
So, add a property to the ancestor form (or to the form itself if unique or
based on TForm) and away we go! None of the existing code or post form
creation assignments are affected, so I have only had to add the property to
two forms to convert the entire application... Almost couldn't be better :-)
Having found the answer for myself I intend to request a points refund.
Chris Bray.
(* In the form to be checked *)
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
fFormIDString: String;
published
property IDFieldString: String read fFormIDString write fFormIDString;
public
{ Public declarations }
end;
(* The check routine in a separate unit *)
// add var PropInfo: PPropInfo to routine
// add TypInfo to uses clause
begin
// ................
// other code here
// ...............
// Check ID match
if Length(FormIDString) = 0 then // Any instance will do
IDMatch := True
else
begin
IDMatch := False;
PropInfo := GetPropInfo(f.ClassInfo, 'FormIDString');
if Assigned(PropInfo) then
IDMatch := GetStrProp(f, PropInfo) = FormIDString;
end;
Existing := TagMatch and IDMatch;
// ................
// other code here
// ...............
So, add a property to the ancestor form (or to the form itself if unique or
based on TForm) and away we go! None of the existing code or post form
creation assignments are affected, so I have only had to add the property to
two forms to convert the entire application... Almost couldn't be better :-)
Having found the answer for myself I intend to request a points refund.
Chris Bray.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Convert all your files to text (including forms) using the Convert.exe application that comes with Delphi,
Then just use the standard find in files tool and point it at *.DPR, *.pas, *.txt.