Recent

Author Topic: [SOLVED] Structuring a Program and units in Lazarus  (Read 6111 times)

Pascaluvr

  • Full Member
  • ***
  • Posts: 216
[SOLVED] Structuring a Program and units in Lazarus
« on: June 14, 2012, 07:47:28 pm »
This is a simple question but its hard to explain -

In my programs, I put GUI, DB/File access, Program specific algorithms, general utils, myvars, etc. in separate units.

My question relates to updating the GUI display. 

Take a simple application with 3 levels of info on the screen --->

1.  Customer info
2.  Invoice Header
3.  Invoice details

On the Customer level I have a Next and Prev buttons.
On the Invoice Header I have Next and Prev Buttons.

Now the question:

If my user clicks on any of the Next/Prev buttons I will call my db/file access units to fill myvars with data and then call (as required):
DisplayCustomer;
DisplayInvoiceHeader;
DisplayInvoiceDetails;

To keep my Form definition unit smaller I would like something like this

Procedure OnClickNextCustomer(....);
begin
GetNextCustomer;
DisplayCustomer;
DisplayInvoice;
DisplayInvoiceDetails;
end;

The GetNextCustomer is easy = its in my db/file access unit.

But the DisplayCustomer/Invoice/InvoiceDetails is trickier to put in a separate unit, as the form components are described at a higher level.  For many applications this would not be a problem because of the the number of fields usually displayed,   My application has hundreds of fields, and to make my units more readable, I want to isolate the 'Display' programming down to a unit.

Ideas appreciated

Thanks all
« Last Edit: June 28, 2012, 12:19:34 am by Pascaluvr »
Windows 7, Lazarus 1.0.8, FPC 2.6.2, SQLite 3

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Structuring a Program and units in Lazarus
« Reply #1 on: June 14, 2012, 08:40:21 pm »
What I usually do is:

Form's units: for visual related things.

EVERYTHING ELSE IS IN A TMyProject class which have specialized objects for EVERYTHING that the project needs like: TCustomer, TInVoice, TInVoiceDetail, etc.

In the form I may or may not use DB aware controls.
   o- If use DB aware Controls I use a TDataset owned by  TMyProject, TInVoice, etc.
   o- If not I get data from the objects in a structure or record or pointer or a TCollection, or what ever I think is better. Something like:
Code: [Select]
Procedure OnClickNextCustomer(....);
var
   ActualCustomer: TCustomerData;
   AnInVoiceCollection: TInVoiceCollection;
   AnInVoiceDetailCollection: TInVoiceDetailCollection;
begin
if not MyProject.Customer.GetNextCustomer({out param}ActualCustomer) then
   Exit;
DisplayCustomer(ActualCustomer);
if not MyProject.InVoice.GetCustomerInVoice(ActualCustomer, {out param}AnInVoiceCollection) then
   Exit;
DisplayInvoice(AnInVoiceCollection);
if not MyProject.InVoice.GetInVoiceDetails(AnInVoiceCollection, {out param}AnInVoiceDetailCollection) then
   Exit;
DisplayInvoiceDetails(AnInVoiceDetailCollection);

// Just in case.
DisplayErrors(MyProject.Errors);
end;

never mind how I build my project I always try to separate the visual part from TMyProject. Also I avoid to use an object to "handle" (do changes) to other object's RESPONSIBILITIES (the you can look but may not touch model if you need something, then ask).
Doing this Maintenance is easier.

I also create a unit with basic Classes with special skills for THIS project to increase re-usability and decrease the repeated code.
Another one for constants, and use TMyProject to hold global variables if needed (usually I don't use global variables).

Pascaluvr

  • Full Member
  • ***
  • Posts: 216
Re: Structuring a Program and units in Lazarus
« Reply #2 on: June 14, 2012, 11:46:24 pm »
I truly thank you for your reply but you have totally lost me :(

I am a real noob at OOP so I don't see how tMyProject (with tCustomer, etc) is related to the Form.
Windows 7, Lazarus 1.0.8, FPC 2.6.2, SQLite 3

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Structuring a Program and units in Lazarus
« Reply #3 on: June 15, 2012, 02:31:48 pm »
Quote
I don't see how tMyProject (with tCustomer, etc) is related to the Form.
Sorry, I forgot that..

Code: [Select]
unit UnitMainForm;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
  MyProject;

type
  { TMainForm }

  TMainForm = class(TForm)
     Button1: TButton;
     procedure Button1Click(Sender: TObject);
     procedure FormCreate(Sender: TObject);
  private
    { private declarations }
    MyProject: TMyProject;
  public
    { public declarations }
  end;

var
  MainForm: TMainForm;

implementation

uses
   MyProjectTypes, UnitClientForm;

{$R *.lfm}

{ TMainForm }

procedure TMainForm.FormCreate(Sender: TObject);
begin
   MyProject.Create.
   // Do any thing you need here
end;

procedure TMainForm.Button1Click(Sender: TObject);
begin
   ShowClientsForm(MyProject.Clients);
end;

end.

Then you have

Code: [Select]
unit UnitClientForm;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  MyClient;

type

  { TClientsForm }

  TClientsForm = class(TForm)
     btnViewInvoice: TButton;
     btnAddClient: TButton;
     procedure btnAddClientClick(Sender: TObject);
     procedure btnViewInvoiceClick(Sender: TObject);
     procedure FormCreate(Sender: TObject);
  private
    { private declarations }
     FMyClients: TMyClient;
  public
    { public declarations }
     procedure LoadData;
  end;

  procedure ShowClientsForm(TheClients: TMyClient);

//var
//  ClientsForm: TClientsForm;

implementation

uses
   MyProjectTypes, UnitFormInvoiceList;
procedure ShowClientsForm(TheClients: TMyClient);
var
   ClientsForm: TClientsForm;
begin
   ClientsForm := TClientsForm.Create(nil);
   try
      FMyClient := TheClient;
      ClientsForm.LoadData;
      ClientsForm.ShowModal;
   finally
      ClientsForm.Free;
   end;
end;

{$R *.lfm}

{ TClientsForm }

procedure TClientsForm.FormCreate(Sender: TObject);
begin
   // put code here if needed
end;

procedure TClientsForm.LoadData;
begin
   // Load FMyClient object's Data here
end;

procedure TClientsForm.btnViewInvoiceClick(Sender: TObject);
begin
   // you can open another form here to show a client's In Voice
   ShowFormInvoiceList(FMyClient.InvoiceCollection);
end;

procedure TClientsForm.btnAddClientClick(Sender: TObject);
var
   NewClientData: TClientData;
begin
   // you collect the new client data from some controls in the form an put it in a record defined in MyProjectTypes unit.
   NewClientData.ID := ....;
   NewClientData.Name := ....;
   NewClientData.Address := ....;
   if not FMyClient.Add(NewClientData) then begin
      ShowMessage(FMyClient.Errors.Get);
   end;
end;

end.

maybe I should build a very small project to explain it better. I will try to upload it tomorrow.

garlar27

  • Hero Member
  • *****
  • Posts: 652
Re: Structuring a Program and units in Lazarus
« Reply #4 on: June 18, 2012, 09:15:00 pm »
 :-[ Sorry Pascaluvr. I had complicated weekend and I couldn't make a small example of how I normally structure a program. On thursday I'll have time to build it.

Pascaluvr

  • Full Member
  • ***
  • Posts: 216
Re: Structuring a Program and units in Lazarus
« Reply #5 on: June 21, 2012, 03:29:52 am »
:-[ Sorry Pascaluvr. I had complicated weekend and I couldn't make a small example of how I normally structure a program. On thursday I'll have time to build it.

No need to apologize - I've had a hectic week myself, so I wouldn't have got very far with it anyway.

From the additional code you posted, its making a bit more sense, but its still a bit vague - so if you do find the time for a small simple example it would be truly appreciated.

Thank you for your efforts
Windows 7, Lazarus 1.0.8, FPC 2.6.2, SQLite 3

Pascaluvr

  • Full Member
  • ***
  • Posts: 216
Re: Structuring a Program and units in Lazarus
« Reply #6 on: June 28, 2012, 12:18:43 am »
Thanks to your code garlar, I have figured it out.  The part I had completely forgotten about was allowing circular references to units by putting a Uses clause after the Implementation statement.

Thanks again for your effort.
Windows 7, Lazarus 1.0.8, FPC 2.6.2, SQLite 3

 

TinyPortal © 2005-2018