Recent

Author Topic: Add Function to a Form?  (Read 2713 times)

LeadGuit

  • New Member
  • *
  • Posts: 24
Add Function to a Form?
« on: March 22, 2021, 10:25:27 pm »
Hi,

I'm pretty new to Pascal/Lazarus but seasoned Programmer elsewhere ;-) I have a professional background in Python mainl y(with some Golang and others stuff mixed in - maybe that's helpful for context).

I struggle a little with the GUI aspect - namely:
 I create a procedure on a Button by double clicking, and write my code. For organisations sake, and since I'm used to it, I wanted to take the code out into a function to call from the Buttonclick procedure.

Here's abbreviated code:

Code: Pascal  [Select][+][-]
  1. unit thingie;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, Controls, Dialogs, EditBtn, FileUtil, Forms,
  9.   Menus, StdCtrls, StrUtils, SysUtils, Types;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     DirectoryEdit1: TDirectoryEdit;
  18.     Memo1: TMemo;
  19.  
  20.     procedure Button1Click(Sender: TObject);
  21.  
  22.  
  23.   private
  24.  
  25.   public
  26.   end;
  27.  
  28.  
  29.  
  30. var
  31.   Form1: TForm1;
  32.  
  33.  
  34. implementation
  35.  
  36. {$R *.lfm}
  37.  
  38.  
  39. { TForm1 }
  40.  
  41. function FunctionIWantToCall: TStringList;
  42.   var
  43.     dates: TStringList;
  44.     files: TStringList;
  45.   begin
  46.    
  47.     files := FindAllFiles(DirectoryEdit1.Directory, '*.json', True);
  48.  // Do my stuff and add stuff to the "date" list/array
  49.     Result := dates;
  50.   end;
  51.  
  52. procedure TForm1.Button1Click(Sender: TObject);
  53.   var
  54.     dates: TStringList;
  55.   begin
  56.     dates := FunctionIWantToCall;
  57.   end;
  58. end.  

The Problem is that apparently the procedure cannot find the function, and the function cannot see any Components in the Form ("Identifier not found "DirectoryEdit1"). I tried various things but can't seem to find the culprit. I moved the procedure below the function (even though I think in compiled languages it doesn't matter where something was defined, in contrast to interpreted ones, but I might be wrong - I am writing FP since like 20 hours...)

Any help is appreciated!

BTW: Another proof, Pascal isn't dead yet - another new guy joining in the fun ;-)
« Last Edit: March 22, 2021, 10:30:59 pm by LeadGuit »
Lazarus 2.0.12, FPC 3.2.0. Win 10

Computational Linguist by day, Film/TV Composer by night.

jamie

  • Hero Member
  • *****
  • Posts: 6128
Re: Add Function to a Form?
« Reply #1 on: March 22, 2021, 10:48:50 pm »
if you are outside of the Class and want to access fields ., methods etc inside a class from outside you need to prepend the call with the class name instance...

For example


Function MyOutSideFunction(….):Tstringlist;
Begin
 //get something from Form1..

 Form1.CallSomethingInSideForm1;
End;

When inside a method that belongs to a class it already can see all the identifiers within which makes the method unique to that class.
etc

The only true wisdom is knowing you know nothing

Rainbow6

  • New Member
  • *
  • Posts: 25
Re: Add Function to a Form?
« Reply #2 on: March 22, 2021, 11:10:21 pm »
if you are outside of the Class and want to access fields ., methods etc inside a class from outside you need to prepend the call with the class name instance...
Function MyOutSideFunction(….):Tstringlist;
Begin
 //get something from Form1..
 Form1.CallSomethingInSideForm1;
End;

A question of someone who never did such a thing - is this „good style“?

I learned (but that is many moons ago) that a function outside of the form class should never access form properties or anything else directly. So I always pass the parts the function needs to know as parameter to the function and get my result back.

But I‘m a typical business programmer (COBOL/RPG) who learned ObjectPascal 20+ years ago with Delphi 1 - so I‘m not up to date with typical code designs nowadays.

Thanks in advance

Kind regards,
Daniel

jamie

  • Hero Member
  • *****
  • Posts: 6128
Re: Add Function to a Form?
« Reply #3 on: March 22, 2021, 11:21:54 pm »
many ways to do it...

Function Name(AForm:TForm1):ReturnType
Begin
 With AForm do
   Begin
    …..
   End;
end;

And in the Click Event

 MyreturnType := name(Self);

etc.
The only true wisdom is knowing you know nothing

zamronypj

  • Full Member
  • ***
  • Posts: 133
    • Fano Framework, Free Pascal web application framework
Re: Add Function to a Form?
« Reply #4 on: March 23, 2021, 12:02:09 am »
Hi,

I'm pretty new to Pascal/Lazarus but seasoned Programmer elsewhere ;-) I have a professional background in Python mainl y(with some Golang and others stuff mixed in - maybe that's helpful for context).

I struggle a little with the GUI aspect - namely:
 I create a procedure on a Button by double clicking, and write my code. For organisations sake, and since I'm used to it, I wanted to take the code out into a function to call from the Buttonclick procedure.

Here's abbreviated code:

Code: Pascal  [Select][+][-]
  1. unit thingie;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, Controls, Dialogs, EditBtn, FileUtil, Forms,
  9.   Menus, StdCtrls, StrUtils, SysUtils, Types;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     DirectoryEdit1: TDirectoryEdit;
  18.     Memo1: TMemo;
  19.  
  20.     procedure Button1Click(Sender: TObject);
  21.  
  22.  
  23.   private
  24.  
  25.   public
  26.   end;
  27.  
  28.  
  29.  
  30. var
  31.   Form1: TForm1;
  32.  
  33.  
  34. implementation
  35.  
  36. {$R *.lfm}
  37.  
  38.  
  39. { TForm1 }
  40.  
  41. function FunctionIWantToCall: TStringList;
  42.   var
  43.     dates: TStringList;
  44.     files: TStringList;
  45.   begin
  46.    
  47.     files := FindAllFiles(DirectoryEdit1.Directory, '*.json', True);
  48.  // Do my stuff and add stuff to the "date" list/array
  49.     Result := dates;
  50.   end;
  51.  
  52. procedure TForm1.Button1Click(Sender: TObject);
  53.   var
  54.     dates: TStringList;
  55.   begin
  56.     dates := FunctionIWantToCall;
  57.   end;
  58. end.  

The Problem is that apparently the procedure cannot find the function, and the function cannot see any Components in the Form ("Identifier not found "DirectoryEdit1"). I tried various things but can't seem to find the culprit. I moved the procedure below the function (even though I think in compiled languages it doesn't matter where something was defined, in contrast to interpreted ones, but I might be wrong - I am writing FP since like 20 hours...)

Any help is appreciated!

BTW: Another proof, Pascal isn't dead yet - another new guy joining in the fun ;-)

There are many ways to solve it. As your FunctionIWantToCall() function basically only needs directory name as input, pass it to function.
Code: [Select]
function FunctionIWantToCall(directoryName:string): TStringList;
  var
    dates: TStringList;
    files: TStringList;
  begin
   
    files := FindAllFiles(directoryName, '*.json', True);
 // Do my stuff and add stuff to the "date" list/array
    Result := dates;
  end;

procedure TForm1.Button1Click(Sender: TObject);
  var
    dates: TStringList;
  begin
    dates := FunctionIWantToCall(DirectoryEdit1.directory);
  end;
end.   
Fano Framework, Free Pascal web application framework https://fanoframework.github.io
Apache module executes Pascal program like scripting language https://zamronypj.github.io/mod_pascal/
Github https://github.com/zamronypj

Gustavo 'Gus' Carreno

  • Hero Member
  • *****
  • Posts: 1119
  • Professional amateur ;-P
Re: Add Function to a Form?
« Reply #5 on: March 23, 2021, 12:32:17 am »
Hey LeadGuit,

Well, if you come from a Python and Golang background I'm guessing you are aware of OOP(Object Oriented Programming), right?

One of the principles of OOP is that if you want to mess with an Objects data/fields, you use Object methods(Procedure, Functions).
First because it's good practice, second because of scope and third security. You don't want to expose your "privates", right? ;)

For all purposed, TForm1 is nothing but an Object, forget the fact that it's part of the GUI.

So in any OOP condition you would have something like this:
Code: Pascal  [Select][+][-]
  1. type
  2.   TSomeClass = class(TObject)
  3.   private
  4.     FFirstName: String;
  5.     FLastName: String
  6.  
  7.     function FullName: String;
  8.   public
  9.     procedure PrintFullName;
  10.  
  11.     property FirstName: String read FFirstName wite FirstName // <-- getter and setter
  12.     property LastName: String read FLastName wite FLastName // <-- getter and setter
  13.   end;
  14.  
  15. implementation
  16.  
  17. function TSomeClass.FullName: String;
  18. begin
  19.   Result:= Format('%s %s', [FFirstName, FLastName]);
  20. end;
  21.  
  22. procedure TSomeClass.PrintFullName;
  23. begin
  24.   WriteLN('Full name is ', FullName);
  25. end;

So if you declare function FunctionIWantToCall under the private section of TForm1, all is good.
All this to explain that whatever component you drop on a form, it's scoped inside the protected section of the TForm1, I think. I may be shootin' outta my arse here, sorry if I am. But it basically behave like they are in protected.

Cheers,
Gus
« Last Edit: March 23, 2021, 12:35:37 am by gcarreno »
Lazarus 3.99(main) FPC 3.3.1(main) Ubuntu 23.10 64b Dark Theme
Lazarus 3.0.0(stable) FPC 3.2.2(stable) Ubuntu 23.10 64b Dark Theme
http://github.com/gcarreno

Gustavo 'Gus' Carreno

  • Hero Member
  • *****
  • Posts: 1119
  • Professional amateur ;-P
Re: Add Function to a Form?
« Reply #6 on: March 23, 2021, 12:41:10 am »
Hey LeadGuit,

Ohh, ohhh, and I completely forgot to mention that when you add any declaration on the interface side of an object, if you press CTRL+SHIFT+C inside said declaration, the IDE will create the empty procedure or function body on the implementation, neat hein?!?!

And it will even reflect any changes you make on the params of the procedures/functions.

Cheers,
Gus
Lazarus 3.99(main) FPC 3.3.1(main) Ubuntu 23.10 64b Dark Theme
Lazarus 3.0.0(stable) FPC 3.2.2(stable) Ubuntu 23.10 64b Dark Theme
http://github.com/gcarreno

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Add Function to a Form?
« Reply #7 on: March 23, 2021, 01:21:32 am »
All this to explain that whatever component you drop on a form, it's scoped inside the protected section of the TForm1, I think. I may be shootin' outta my arse here, sorry if I am. But it basically behave like they are in protected.

Not quite, sorry. They are public and they need to be so for the streaming system to work. Of course, this has nothing to do with adding a function as a method of the form object.

Quote from: gcarreno
First because it's good practice, second because of scope and third security. You don't want to expose your "privates", right? ;)

That last can be easily solved without adding a method to any object: e.g. don't declare the function in the  interface but simply define it in the implementation. The most useful reason to declare it as a method is either when it needs to access private/protected fields/methods or when you don't want to pass the object instance as a parameter. That is, basically scope-related reasons.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Gustavo 'Gus' Carreno

  • Hero Member
  • *****
  • Posts: 1119
  • Professional amateur ;-P
Re: Add Function to a Form?
« Reply #8 on: March 23, 2021, 01:38:01 am »
Hey Lucamar,

Not quite, sorry. They are public and they need to be so for the streaming system to work. Of course, this has nothing to do with adding a function as a method of the form object.

Oh crap, you are completely right, The hell was I thinking?!?!? Man, I've been doing this for quite a while, I should'a remember that I can access the components from other units, hence public.
Many thanks for the, well deserved, slap of reality!!

That last can be easily solved without adding a method to any object: e.g. don't declare the function in the  interface but simply define it in the implementation. The most useful reason to declare it as a method is either when it needs to access private/protected fields/methods or when you don't want to pass the object instance as a parameter. That is, basically scope-related reasons.

Yeah, I'll agree with you on those methods. But I'm still gonna put my foot down that if you're messing with an Object's fields, it should be inside the object and not outside. It's just my mind say to me: Use good OOP practices, Luke ... :P

Cheers,
Gus
Lazarus 3.99(main) FPC 3.3.1(main) Ubuntu 23.10 64b Dark Theme
Lazarus 3.0.0(stable) FPC 3.2.2(stable) Ubuntu 23.10 64b Dark Theme
http://github.com/gcarreno

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Add Function to a Form?
« Reply #9 on: March 23, 2021, 01:58:42 am »
But I'm still gonna put my foot down that if you're messing with an Object's fields, it should be inside the object and not outside. It's just my mind say to me: Use good OOP practices, Luke ... :P

I can whole heartedly agree with the "use good OOP practices" but ... you're almost always "messing" with objects's fields without adding a method. Agreed, most of the time you'll do that through properties/methods but if, say, a property simply reads/writes the field and will never do otherwise? Declare the field as public and get rid of the property: one less level of indirection and avoids some of the limitations of properties. Every norm has its exceptions, you know ;)
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Gustavo 'Gus' Carreno

  • Hero Member
  • *****
  • Posts: 1119
  • Professional amateur ;-P
Re: Add Function to a Form?
« Reply #10 on: March 23, 2021, 02:45:50 am »
Hey Lucamar,

I can whole heartedly agree with the "use good OOP practices" but ... you're almost always "messing" with objects's fields without adding a method. Agreed, most of the time you'll do that through properties/methods but if, say, a property simply reads/writes the field and will never do otherwise? Declare the field as public and get rid of the property: one less level of indirection and avoids some of the limitations of properties. Every norm has its exceptions, you know ;)

Yeah I see your point, and I do understand it and yes it makes sense.

I think it's me being a bit of a puritan that showing it's dreaded head.
I always declare all my fields private/protected and I always have a property pointing at them.
Sometimes I do this because I never know if I want to have a setter/getter in between and not a direct read FField write FField.
I guess I'm stuck in that thing where you stick to what you've been thought early on.

But I do agree with all your argument on the quote. I guess I need to relax the sphincter and be less anal?! :D

Cheers,
Gus
Lazarus 3.99(main) FPC 3.3.1(main) Ubuntu 23.10 64b Dark Theme
Lazarus 3.0.0(stable) FPC 3.2.2(stable) Ubuntu 23.10 64b Dark Theme
http://github.com/gcarreno

LeadGuit

  • New Member
  • *
  • Posts: 24
Re: Add Function to a Form?
« Reply #11 on: March 23, 2021, 05:36:59 am »
Thank you guys for the many helpful responses!

Since I'm not aware of "good style" yet, I'll follow first what makes sense to the old scripter. I added a "Form1." to the respective Form Components that I want to access.

I somehow seemed to have tried every other combination of that all  ::)

In my logic, the function would be a good (or reasonable) method for an Object - but I would create a separate object (for I'm doing I would guess a Record?) and add it to it there.
I never did GUI programming, If I needed to have a that, I chose the easy way out via WebView and rendered HTML. For those who maybe are unaware, I would have an HTML-Form and send those values in the form to the backend and "do stuff with it". In my head, the Directory Edit is such a Formfield - and the Form doesn't exist as Object, but is "just the Frontend" :)

Declare the field as public and get rid of the property: one less level of indirection and avoids some of the limitations of properties.

For that, I would do insert this line in the "public" section of the type declaration of the form like so, right? And add "TForm1l." to the function name in the implementation, since now it's a method.
Code: Pascal  [Select][+][-]
  1. type
  2.  
  3.   { TForm1 }
  4.  
  5.   TForm1 = class(TForm)
  6.     Button1: TButton;
  7.     DirectoryEdit1: TDirectoryEdit;
  8.     procedure Button1Click(Sender: TObject);
  9.   private
  10.  
  11.   public
  12.     function FunctionIWantToCall: TStringList
  13.   end;      

What pops in my head/logic there is - this shouldn't be a method - it doesn't do anything with the Form, the function takes values from components on the form and creates something new with it? Maybe I just think more procedural than OO...The damage of writing a scripting language for a living xD
« Last Edit: March 23, 2021, 05:41:28 am by LeadGuit »
Lazarus 2.0.12, FPC 3.2.0. Win 10

Computational Linguist by day, Film/TV Composer by night.

Gustavo 'Gus' Carreno

  • Hero Member
  • *****
  • Posts: 1119
  • Professional amateur ;-P
Re: Add Function to a Form?
« Reply #12 on: March 23, 2021, 05:53:33 am »
Hey LeadGuit,

For that, I would do insert this line in the "public" section of the type declaration of the form like so, right? And add "TForm1l." to the function name in the implementation, since now it's a method.
Code: Pascal  [Select][+][-]
  1. type
  2.  
  3.   { TForm1 }
  4.  
  5.   TForm1 = class(TForm)
  6.     Button1: TButton;
  7.     DirectoryEdit1: TDirectoryEdit;
  8.     procedure Button1Click(Sender: TObject);
  9.   private
  10.  
  11.   public
  12.     function FunctionIWantToCall: TStringList
  13.   end;      


I'm sorry if I wasn't clear/helpful when I explained the OOP way, but your piece of code is exactly what I meant.

What pops in my head/logic there is - this shouldn't be a method - it doesn't do anything with the Form, the function takes values from components on the form and creates something new with it? Maybe I just think more procedural than OO...The damage of writing a scripting language for a living xD

The only thing you need to internalize now is the fact that all components inside a TForm are like it's fields/methods. The scope is that they are "inside" the TForm just like the fields/methods are "inside" a Class.
So, without this last piece of the puzzle, yes you would be right to assume that the components have nothing to do with the Form, but since they do, well scope wise that is, then when you are messing with components and their values, the scope is inside or belonging to the form.
And no, that rationale is quite in line with good OOP and not procedural at all.

I hope I got it in a way that makes a bit more sense now. If not please tell me and I'll try ans rephrase.

Cheers,
Gus
Lazarus 3.99(main) FPC 3.3.1(main) Ubuntu 23.10 64b Dark Theme
Lazarus 3.0.0(stable) FPC 3.2.2(stable) Ubuntu 23.10 64b Dark Theme
http://github.com/gcarreno

LeadGuit

  • New Member
  • *
  • Posts: 24
Re: Add Function to a Form?
« Reply #13 on: March 23, 2021, 06:07:11 am »
Hey LeadGuit,

For that, I would do insert this line in the "public" section of the type declaration of the form like so, right? And add "TForm1l." to the function name in the implementation, since now it's a method.
Code: Pascal  [Select][+][-]
  1. type
  2.  
  3.   { TForm1 }
  4.  
  5.   TForm1 = class(TForm)
  6.     Button1: TButton;
  7.     DirectoryEdit1: TDirectoryEdit;
  8.     procedure Button1Click(Sender: TObject);
  9.   private
  10.  
  11.   public
  12.     function FunctionIWantToCall: TStringList
  13.   end;      


I'm sorry if I wasn't clear/helpful when I explained the OOP way, but your piece of code is exactly what I meant.

What pops in my head/logic there is - this shouldn't be a method - it doesn't do anything with the Form, the function takes values from components on the form and creates something new with it? Maybe I just think more procedural than OO...The damage of writing a scripting language for a living xD

The only thing you need to internalize now is the fact that all components inside a TForm are like it's fields/methods. The scope is that they are "inside" the TForm just like the fields/methods are "inside" a Class.
So, without this last piece of the puzzle, yes you would be right to assume that the components have nothing to do with the Form, but since they do, well scope wise that is, then when you are messing with components and their values, the scope is inside or belonging to the form.
And no, that rationale is quite in line with good OOP and not procedural at all.

I hope I got it in a way that makes a bit more sense now. If not please tell me and I'll try ans rephrase.

Cheers,
Gus

Thanks for the clarification, yes. Makes sense.
By procedural vs OOP, I meant my own thinking ;-)
Lazarus 2.0.12, FPC 3.2.0. Win 10

Computational Linguist by day, Film/TV Composer by night.

JuhaManninen

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 4467
  • I like bugs.
Re: Add Function to a Form?
« Reply #14 on: March 23, 2021, 06:16:37 am »
Not quite, sorry. They are public and they need to be so for the streaming system to work.
No, actually they are published, exactly for the streaming system.
Mostly Lazarus trunk and FPC 3.2 on Manjaro Linux 64-bit.

 

TinyPortal © 2005-2018