Recent

Author Topic: Using classes to encapsulate data  (Read 589 times)

TBMan

  • Sr. Member
  • ****
  • Posts: 355
Using classes to encapsulate data
« on: September 28, 2025, 10:09:08 pm »
I coded a simple file listing dialog using ptcgraph. I want to wrap the entire code that the dialog box uses - the file list data types, the painting procedures the whole thing. I don't want any external records used except my "trect" which just defines a rectangle. I think using a class is best? I've never used them before (but I do ok with objects).

Basically what I want to do is create the dialog and then have a boolean "rundialog(filemask, returnfilename)" function that returns true if a filename is selected (passed back by rundialog).

Do I have the right idea?
Barry

Newest game (clone),
Missile Commander:
https://www.youtube.com/watch?v=tgKz0cxog-k

cdbc

  • Hero Member
  • *****
  • Posts: 2814
    • http://www.cdbc.dk
Re: Using classes to encapsulate data
« Reply #1 on: September 28, 2025, 11:09:44 pm »
Hi
If you're comfortable with Objects then you might have a look in unit 'UDialogs', which is the dialog section of 'FreeVision', good inspiration in there.
Otherwise you might take a look at Lazarus' 'Dialogs' unit, which implements the LCL-Dialogs...
Your description sounds a lot like the standard dialog in Lazarus, e.g:
Code: Pascal  [Select][+][-]
  1. OpenDialog1.Directory:= '/home/youser/tmp/'; // or maybe '~/tmp/';
  2. if OpenDialog1.execute then begin
  3.   fs:= TFilestream.Create(OpenDialog1.Filename,fmOpenRead or fmShareDenyNone);
  4.   try
  5.     /// use the filestream ///
  6.   finally fs.Free; end;
  7. end;
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

Warfley

  • Hero Member
  • *****
  • Posts: 2066
Re: Using classes to encapsulate data
« Reply #2 on: September 29, 2025, 10:43:54 am »
Why not just use a unit? Units are perfectly well suited for encapsulating functionality. They have two sections, the interface is what is visible to the outside, and the implementation is only visible inside the unit.
Code: Pascal  [Select][+][-]
  1. unit MyDialog;
  2.  
  3. {$Mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses ...;
  8.  
  9. function runDialog(const fileMask: String; out returnFilename: String): Boolean;
  10.  
  11. implementation
  12.  
  13. procedure DrawDialog(...)...
  14.  
  15. procedure OtherHelperFunc(...)...
  16.  
  17. function runDialog(const fileMask: String; out returnFilename: String): Boolean;
  18. begin
  19.   // Implement and use the helper functions defined above
  20. end;

TBMan

  • Sr. Member
  • ****
  • Posts: 355
Re: Using classes to encapsulate data
« Reply #3 on: September 29, 2025, 03:40:52 pm »
Why not just use a unit? Units are perfectly well suited for encapsulating functionality. They have two sections, the interface is what is visible to the outside, and the implementation is only visible inside the unit.
....

Yes, thanks. I did use a unit, but in case I develop other class based GUI elements I wanted the list dialog variables to be self contained. I finished it this morning, here's a short video and the class declaration code:

https://youtu.be/MC-tlEiMX2Y

Code: Pascal  [Select][+][-]
  1. type
  2.   LGC_FileDialog = class
  3.   private
  4.   const
  5.     MaxItems = 300;  // limit for file list - needs more error checking
  6.     Maxbuttons = 2;
  7.     max = 14;
  8.     ev_ok = 1000;
  9.     ev_cancel = 2000;
  10.  
  11.   type
  12.     buttonType = record
  13.       event: integer;
  14.       Rect: Trect;
  15.       Txt: string;
  16.     end;
  17.  
  18.     ItemType = record
  19.       Id: integer;
  20.       Info: string;
  21.     end;
  22.  
  23.     ListType = record
  24.       List: array[1..maxitems] of itemtype;
  25.       Items: integer;
  26.     end;
  27.  
  28.     ContentType = record
  29.       IdRef: integer;  // reference to List item
  30.       Rect: Trect;
  31.     end;
  32.   var
  33.     bitmap: pointer;
  34.     sz: longint;
  35.  
  36.     uprect, downrect, scrollrect, ScrollButton, outerRect,
  37.     DisplayRect: Trect;
  38.  
  39.     ScrollButtonSize: integer;
  40.     Contents: array[1..Max] of ContentType;
  41.     ListContents: ListType;
  42.  
  43.     EventCode: integer;
  44.     EndResult: boolean;
  45.     Buttons: array[1..2] of buttontype;
  46.     ScrollPercentage: double;
  47.     Rowlimit, ScrollDownLimit: integer;
  48.     changed: boolean;
  49.     mx, my, mb: longint;
  50.     key: char;
  51.     x, y, spot, xx, yy, w, d: integer;
  52.     currentrow: integer;
  53.  
  54.  
  55.   public
  56.   var
  57.     ErrorCode, Steelblue, Gray: integer;
  58.     constructor Create(xxx, yyy: integer; Fmask: string);
  59.     destructor Destroy; override;
  60.     procedure drawbutton(IB: integer; Up: boolean);
  61.     procedure SetButtons;
  62.     procedure UpDateScroll;
  63.     procedure highlight(fc, bc: integer; Yes: boolean);
  64.     procedure scrolldisplay(startRow, Endrow: integer);
  65.     function createList(filemask: string): boolean;
  66.     function run(var returnstring: string): boolean;
  67.     procedure paint;
  68.     procedure scrollbuttonactive(TheRect: Trect);
  69.   end;
  70.  
  71.  

And it gets called as (after graph mode initialized by PTCGraph):

Code: Pascal  [Select][+][-]
  1. filedialog := lgc_filedialog.create(400,200,'*.arr');
  2.  if filedialog.errorcode=0 then
  3.   begin
  4.   if filedialog.run(ts) then
  5.    begin
  6.      setcolor(white);
  7.      outtextxy(400,100,'Returned file name:'+ts);
  8.    end;
  9.   end
  10.   ELSE
  11.      BEGIN
  12.      SETCOLOR(15);
  13.      outtextxy(600,100,'ERROR!');
  14.  
  15.      end;
  16.  
  17.  filedialog.destroy;                
  18.  

In the video I'm showing the scroll action using the scroll button controls, but you can also click on
the list to select a item as well. I'm just going to group my variables by type in the code and it's done.)
I'm happy with how it came out, but now I want to be able to change directories within the dialog as well
to add full functionality. For my game asset tools though it's fine as I stay in one folder for each project usually.

I'll probably have to add a file attrib field to the "itemtype" record and then if it isn't "archive" then change directories and  rebuild the list.....  or something like that :)

I also modified it now to allow me to change all the colors used by the filedialog so I can change palettes from the default ptcgraph palette.
« Last Edit: September 29, 2025, 06:56:31 pm by TBMan »
Barry

Newest game (clone),
Missile Commander:
https://www.youtube.com/watch?v=tgKz0cxog-k

 

TinyPortal © 2005-2018