tags:

views:

130

answers:

2

I am writing a procedure to close all adoquery created and open on a (any) form, the problem is I need to do a cast on the form to identify the components. how can I make a dynamic cast like shown in the example?

I need something like this

Procedure OpenADODataSets(Form:TForm;FormType:TClass);
...
...
(Form as FormType).ComponentCount

or

Procedure OpenADODataSets(Form:TForm;FormType:TClass);
...
...
FormType(Form).ComponentCount

this is the code.

Procedure OpenADODataSets(Form:TForm;FormType:TClass);
var
  i: integer;
begin

    for i:=0 to (Form as FormType).ComponentCount-1 do
     if (Form as FormType).Components[i].ClassType=TADOQuery then
       if not TADOQuery((Form as FormType).Components[i]).Active then
        TADOQuery((Form as FormType).Components[i]).Open;

end;

UPDATE

problem solved with the answer of @Edelcom

Procedure OpenADODataSets(Form:TForm);
var
  i: integer;
begin

    for i:=0 to Form.ComponentCount-1 do
     if Form.Components[i].ClassType=TADOQuery then
       if not TADOQuery(Form.Components[i]).Active then
        TADOQuery(Form.Components[i]).Open;

end;
+2  A: 

Why do you need the (Form as FormType) (as I commented). Looked up some of my own code, which works fine :

procedure TProgSettingsVisual.FillStandardSaveFilesForForm( const pForm: TForm;);
var i : integer;
    x : string;
    thisComponent : TComponent;
begin
   With pForm do
   begin
      for i := 0 to ComponentCount-1 do
      begin
         thisComponent := Components[i];

         x := LowerCase(Components[i].ClassName);


         if x = 'tovcinifilestore'
         then begin
            TOvcIniFileStore(Components[i]).IniFileName := FormSaveFile(pForm);
         end;

         if x = 'tovdformstate'
         then begin
             ...
         end;

         if x = 'tovccomponentstate'
         then begin
              ...
Edelcom
+1, every form is a descendant of TForm therefore TForm will work fine, you don't need to cast it. Although a TDataModule doesn't derive from TForm so you might need to handle that separately.
_J_
No, J, you don't need to handle it separately. *All* descendants of `TComponent` have the requisite properties, `ComponentCount`, `Component`, and `ClassName`. Not that the latter is actually a good idea to use, though; use the **is** operator to test components' types, not string comparison. It's possible for two objects to have the same class name but to be of different types.
Rob Kennedy
+1  A: 

Type casting's purpose is to tell the compiler the type of an identifier so that it can generate correct code that uses that identifier. When your desired type is stored in a variable, the compiler can't do any type checking. It can't confirm that the run-time value of FormType will be a type that has a Components property, so it can't compile the code.

You can't type-cast to a type when you don't know what that type is. If you find yourself needing to do that, you're doing something wrong. Post a question about what you're really trying to do. (See also: "XY problem.")

In your case, what you're trying to do is write a function that works on many kinds of forms. But all the properties you're using from the form object are actually available to all form types because they're properties introduced in TForm or earlier. In fact, the properties you're using are introduced in TComponent — all components can own other components, so they all have Components and ComponentCount properties. You don't need to know which specific type the form has because your code can work equally well with any component type.

procedure OpenADODataSets(Owner: TComponent);
var
  i: Integer;
begin
  for i := 0 to Owner.ComponentCount - 1 do
    if Owner.Components[i] is TADOQuery
       and not TADOQuery(Owner.Components[i]).Active then
      TADOQuery(Owner.Components[i]).Open;
end;

Or even, as of Delphi 2005:

procedure OpenADODataSets(Owner: TComponent);
var
  comp: TComponent;
begin
  for comp in Owner do
    if comp is TADOQuery
       and not TADOQuery(comp).Active then
      TADOQuery(comp).Open;
end;

Since data sets already check whether they're active before opening themselves, you don't really have to check first:

if comp is TADOQuery then
  TADOQuery(comp).Open;
Rob Kennedy
Rob, why are you checking for the AdoQuery's active state in this code, before opening it?!Setter method for Active property already checks whether the dataset is active or not, and activates it only if it is closed.
vcldeveloper
I based my code on the code in the question. The focus of the question was not on the best way to open queries, so I opted not to vary that portion of the code so as not to distract from the point. Besides, I don't think you read to the end of my answer, or else you'd have seen that I ultimately address the very issue you're questioning me about.
Rob Kennedy
yes, you are right, I didn't read the last line of your answer between two code boxes.Thanks for the clarification.
vcldeveloper