Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Structure of a unit/application

Status
Not open for further replies.

jjschwartz

Technical User
Feb 3, 2004
23
US
(Please bear with me; this is my first Delphi application)

I have a number of constants and global variables (variables that all my forms will need access to) to declare.

Where is the best place to do this?

Can I put them in a separate unit and, if so, do I put the 'uses unit' in the project file or my main unit?

Do I put them in my main unit? Do I put them in the project file?

TIA,
Jeff Schwartz
 
Constants: I create a unit just for constants (habitually called ProjConstants.pas). You add it to the uses clause of every unit that references it.

Global variables: Generally advise against using global variables. Instead create a global object. Either have a auto-create data-module or derive from TObject and create/free a single instance in your main form FromCreate/FormDestroy. The reference to it will be a global. You can then create globaly accessible properties and methods, enjoying all the facilities and protection of OO. Again add the unit of your global object to every unti that referenes it.

Have fun
Simon
 
Thank you for the advice but, as a Delphi newbie, I think I need a little more direction.

What is a data module and how can I use it to store/use variables accesible to all my forms? Is it just a separate unit (like ProjConstants) that has the variables declared?

I don't think creating a descendant of TObject and writing my own properties and events is a good first-time project. Am I wrong? Is this easier than it sounds?

TIA,
Jeff Schwartz
 
You have some examples about global variables in the thread


Sorry, Vintage, I need to disagree with you here. I can't see the good in using a TModule or any type of object for global variables. If you need property accesors you can hide the var in the interface section and write a shell function/procedure; furthermore, a global var needing an accesor probably is a wrong candidate to run for the position and better not having it mixed with "real" global vars.

But I'm very interested in your opinion, can you elaborate, please?

HTH, jjschwartz and TIA, Vintage.

buho (A).
 
>a global var needing an accesor probably is a wrong >candidate to run for the position.
Agree.

>you can hide the var in the interface section and write a >shell function/procedure
You can, but creating an object make code clearer and forces you to think positively about program structure.

Global variables are perfectly legit, but experience shows that programs with lots of global vars tend to be bug ridden. I recommend using them only when there really is no reasonable alternative.

Lets take some examples.
1. Most Delphi programs have a global var referencing the main form. Fine.
2. Delphi has global vars for Printer, Screen and a few others. These are references to physical things of which there are only one. (All right multiple printers, but a TPrinter is a singel access point to all of them). Works well.
3. Most of my apps have a global var referencing a data module which provides the single point of access to the database. Again, works well.
4. Many apps need some global to specify what authorities the current user has, often an array or set. I say make it a property of the global data module, not a global in its own right. It can then reference an array today but upgrade to a dataset tomorrow.
5. Status. I have often found programmers using global vars to control the status of something, justified with the claim that there is only ever one of "something". Bad news. Why?
- soon there will be 100+ global vars, with it being virtually impossible to trace when each one is updated or is valid (I've seen it)
- When your app only had three forms the purpose of "Status" was clear. Now it has 20 forms, which one did "Status" belong to? "Opps..........Status is being referenced by CustomerEdit and OrderEdit"
- Next year your customer will want two concurrent instances of "something". Oh dear, complete re-write needed.

So much for what not to do, what about what to do?

Create a helper object, containing all the data that multiple objects need and pass a reference to it to all relevant objects. That way you are in control of when the instances are created and destroyed and how many instances there are.

I'll write an example as another post. It will look long, but its actually simple. OOP tends to involve a lot of typing up front. Most of it is simple and you get less debugging later one. [I wish I hadn't started this now <g>]

 
Example of helper object (instead of using globals)

There will be a mainform which controls the creation of two sub forms, FormOne and FormTwo. How they are invoked/shown is irrelevant. All three forms need to access a chunk of data which I will represent by an integer var "Status". Status wil be wrapped in an object THelper, of which one instance will be created. Each object should go in a separate .pas file.

It is not intended that this code be created verbatum. I have omitted the required Delphi units from the uses clauses for one.

Simon


MAINFORMU.PAS

uses
FormOneU, FormTwoU, HelperU;

type
TMainForm=class(TForm)
procedure FormCreate(Sender:TObject);
procedure FormDestroy(Sender:TObject);
private
FHelper:THelper;
function CreateFormOne:TFormOne;
function CreateFormTwo:TFormTwo;
public
property Helper:THelper read FHelper;
end;

implementation

procedure TMainForm.FormCreate(Sender:TObject);
begin
FHelper:=THelper.Create;
end;

procedure TMainForm.FormDestroy(Sender:TObject);
begin
FreeAndNil(FHelper);
{Always try to free an object in a way that partners its creation}
end;

function TMainForm.CreateFormOne:TFormOne;
begin
Result:=TFormOne.Create(Self);
Result.Helper:=Helper;
{Because FormOne references the instance of Helper created by MainForm and that instance will be destroyed when MainForm is destroyed, all FormOne instances (yes, you can have more than one) must be destroyed before MainForm is destroyed. Making MainForm (Self) the owner of FormOne achieves this.}
end;

function TMainForm.CreateFormTwo:TFormTwo;
begin
Result:=TFormTwo.Create(Self);
Result.Helper:=Helper;
end;

FORMONEU.PAS

uses
HelperU;

type
TFormOne=class(TForm)
public
Helper:THelper;
end;

FORMTWOU.PAS

uses
HelperU;

type
TFormTwo=class(TForm)
public
Helper:THelper;
end;

HELPERU.PAS

type
THelper=class(TObject)
private
FStatus:integer;
procedure SetStatus(const Value:integer);
public
property Status:integer read FStatus write SetStatus;
end;

implementation

procedure THelper.SetStatus(const Value:integer);
begin
if(FStatus=Value)then
Exit;

{Can do processing here when value of status changes}

FStatus:=Value;
end;

You do not have to use the property facilities, Status could simply be a var but still part of the object, viz:

HELPERU.PAS

type
THelper=class(TObject)
public
Status:integer;
end;
 
Jeff, having got wrapped up in debate with Buho, you question has gone unanswered.

>What is a data module and how can I use it to store/use >variables accesible to all my forms? Is it just a >separate unit (like ProjConstants) that has the variables >declared?

A Data module is a non-visible form. You can put things like datasets on it, auto-create it, or manually create it like a form, but it never shows to the user.

>I don't think creating a descendant of TObject and writing >my own properties and events is a good first-time >project. Am I wrong? Is this easier than it sounds?
Create yourself a noddy one form testbed and play around with creating objects. Perhaps avoid your own events in a first project. At the end of my helper example post I show how you can get started with objects without even using properties. There are some good tutorials around in books and on the web.

Have fun
Simon
 
Vintage:

After reading your posts, I believe the difference is in the way we classify things and not in the way we use its.

I can elaborate if you want, but we will run off topic at light speed. :) It is your call, I'm at your service.

And zillion thanks for your elaborated answer.

buho (A).

 
buho,VintageWine,

both your choices are valid, hey it's a free world out there. If one really wants to stick to strict oo programming, go with vintagewine's method. it's indeed a good choice for medium to large projects but a bit "overkill" for small (quick 'n dirty) projects.

nice discussion anyway [spin]




--------------------------------------
What You See Is What You Get
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top