3

I am developing a program that calculates the averages of some datas in different TStringGrid and I thought to use a procedure. It is called calcola.

procedure calcola(numero:ShortInt; StringGrid:TStringGrid; pbarprog:ShortInt);
var i,j,cont,num:shortint;
    avg,temp,numfl:double;
    a:string;
    Edit1:TEdit;
begin
if StringGrid.Colcount>1 then

 //other code

       avg:=temp/cont;
       TLabel(FindComponent('Label'+IntToStr(num))).Caption:=FloatToStrF(avg, ffGeneral, 1, 1);
       Edit1.Text:=FloatToStr(StrToFloat(TLabel(FindComponent('Label'+IntToStr(num))).Caption)*10);
       TProgressBar(FindComponent('ProgressBar'+IntToStr(i+pbarprog))).Position:=StrToInt(Edit1.Text);

       //other code

     end;
   end;
end; 

In this procedure Lazarus tells me "Identifier not found FindComponent". Then I cut/pasted the same code in procedure TForm1.Button1Click(Sender: TObject); and I had no errors.

I need to use FindComponent() inside calcola, how could I do it?

Alberto Miola
  • 4,643
  • 8
  • 35
  • 49
  • `FindComponent` is a `TComponent` method, not a function. – TLama Aug 10 '13 at 11:29
  • So what do I have to to? – Alberto Miola Aug 10 '13 at 11:33
  • First of all I would review the code. It's extremely unsafe. – TLama Aug 10 '13 at 11:36
  • 2
    Ok but I think he needs an answer to his question before the code review. – Alberto Rossi Aug 10 '13 at 11:39
  • @Alberto, for sure. Hence it's a comment and not the answer :-) There's a lot of ways how to answer this question with code (e.g. pass a form object as a parameter into the procedure and call `FindComponent` like `PassedForm.FindComponent` for instance). But this code calls for almost complete redesign. And if that would happen, there won't be such question. – TLama Aug 10 '13 at 11:45
  • Oh ok :) so I can do something like 'TForm1.FindComponent();' ? – Alberto Miola Aug 10 '13 at 11:48
  • 2
    Either you can access the global variable `Form1` (in your case you'd call it like `Form1.FindComponent` in your procedure). Or you can add another parameter into your procedure where you'd pass the form object and call that method over that parameter. But, it's better think of redesign in some way. – TLama Aug 10 '13 at 11:55
  • 2
    @tlama: just turn your comment into an answer. Using a reference to a a form instance fixes the immediate problem, and with the added warning or advice it's a pretty solid answer that can be voted on. – Wouter van Nifterick Aug 10 '13 at 12:43
  • 1
    Stop mixing UI code, and maths code into one unholy, unseemly gloop. Stop using FindComponent. There's no need and it's bad practise. Don't do it. – David Heffernan Aug 10 '13 at 15:29
  • Stop using FindComponent ---> The question is about FindComponent. Nice one ;) – Alberto Rossi Aug 14 '13 at 00:09

1 Answers1

6

Then I cut/pasted the same code in procedure TForm1.Button1Click(Sender: TObject); and I had no errors.

The reason the compiler stopped complaining when you made that change is that when calcola is declared as a method of TForm1, the compiler could resolve the identifier FindComponent by searching backwards through the declared methods of TForm1 and the public methods of the objects it descends from (TForm ... TObject) until it finds one declared with that name. FindComponent is declared in TComponent.

The reason the compiler complained with your original version was that calcola was declared (I assume) in your program's global scope as a stand-alone routine and for those, the compiler only searches through previously declared stand-alone procedures/functions, not ones that are declared as methods of objects.

If for whatever reason your calcola procedure absolutely has to be a stand-alone procedure, then the best thing to do is to adjust its parameters so you can pass the specific instance of TForm1 to it as a parametet, like you have with StringGrid.

MartynA
  • 30,454
  • 4
  • 32
  • 73