Solved

3 level software architecture

Posted on 2010-08-17
13
309 Views
Last Modified: 2012-05-10
what is the best way to move progress information from a 3rd. level routine to the GU level ???

procedure button1.click (......)
begin
         
         MyClass.DoSomeAction (...;  aGuiProgressBar; ......);

end;


procedure TMyClass.DoSomeAction (........aGuiProgressBar : TProgressbar...);
begin
   
          ExecuteComplexCalc( ...aGuiProgressBar .... ...);
end;



procedure  ExecuteComplexCalc (........ .aGuiProgressBar : TProgressbar   .....................  )
begin
         

            aGuiProgressBar.value := i;       //  set the value here

end;
0
Comment
Question by:BdLm
  • 6
  • 3
  • 2
  • +1
13 Comments
 
LVL 36

Expert Comment

by:Geert Gruwez
ID: 33455606
1 way: read my article on this site
probably not the best, but it shows independance of a class towards a form using a callback procedure

a lot of solutions i see, have the name of the form or the progress inside the thread
which is useless if using the same unit in a other unit/form with a different name
0
 
LVL 8

Author Comment

by:BdLm
ID: 33455685
you refer to http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/A_239-Displaying-progress-in-the-main-form-from-a-thread-in-Delphi.html  ??  

from design style level 3 should only talk to level 2 but never to level 1, but this is much more coding instead of the dirty way .....

I need the reuse design as I use the level 3 libraries for many different projects
0
 
LVL 25

Assisted Solution

by:epasquier
epasquier earned 71 total points
ID: 33456371
I'm not sure what your problem is. Your way could work, with just the addition of something to tell the progressbar to update itself once set to a new value. Otherwise, passing the reference to the progressbar from one level to the next is not a problem.

In fact, you can use a SetProgress global function that will do that, and other things very much needed regularly during lengthy calculations, like treating pending windows events
For a Cancel button for example, that would break the current calculation.
procedure SetProgress(aGuiProgressBar : TProgressbar; Val:Integer);

begin

 aGuiProgressBar.value := i;       //  set the value here

 Application.ProcessMessages; // treat all pending system messages NOW

// among them, redraw the progress bar, and a cancel button event

 if Canceled Then Abort; // raise a silent exception that will break all the process

end;



procedure TForm.btnCancelClick(Sender:TObject);

begin

 Canceled:=True; // Canceled is a public variable set to false at start

 // this will abort the process next time its progress is supdated

end;



procedure  ExecuteComplexCalc (........ .aGuiProgressBar : TProgressbar   .....................  );

Var

 i:integer;

begin

 for i:=0 to 1000 do 

  begin

   SetProgress(aGuiProgressBar , i);

   sleep(1000);

  end;

end;





procedure TMyClass.DoSomeAction (........aGuiProgressBar : TProgressbar...);

begin

 Canceled:=False;

 ExecuteComplexCalc( ...aGuiProgressBar .... ...);

end;

Open in new window

0
 
LVL 32

Accepted Solution

by:
ewangoya earned 143 total points
ID: 33456942
Always try as much as possible to separate your GUI controls from your backend controls. This way if you need to change your progress bar at some time in the future, you only do so in the interface part of your program

Heres what I would do

  TUpdateProgressEvent = procedure(Sender: TObject; const AProgress: Int64);

  TMyObject = class(TSomething)
  private
    FOnUpdateProgressEvent: TUpdateProgressEvent;
    procedure DoProgressEvent(const AProgress: Int64);
  public
    procedure DoSomeAction;
    property OnUpdateProgressEvent: TUpdateProgressEvent read FOnUpdateProgressEvent write FOnUpdateProgressEvent;
  end;

  TForm1 = class(TForm)
  private
    procedure OnUpdateProgress(Sender: TObject; const AProgress: Int64);
  public
    procedure DoSomething;
  end;

......

{ TMyObject }

procedure TMyObject.DoProgressEvent(const AProgress: Int64);
begin
  if Assigned(FOnUpdateProgressEvent) then
    FOnUpdateProgressEvent(Self, AProgress);
end;

procedure TMyObject.DoSomeAction;
var
  I: Integer;
begin
  for I := 0 to 1000 do
    DoProgressEvent(I);
end;

{ TForm1 }

procedure TForm1.DoSomething;
var
  MyObject: TMyObject;
begin
  MyObject := TMyObject.Create;
  try
    //initialize your progress bar
    MyObject.OnUpdateProgressEvent := OnUpdateProgress;
    MyObject.DoSomeAction;
  finally
    FreeAndNil(MyObject);
  end;
end;

procedure TForm1.OnUpdateProgress(Sender: TObject; const AProgress: Int64);
begin
  ProgressBar1.Value := AProgress;
  //Application.ProcessMessages;
end;
0
 
LVL 36

Assisted Solution

by:Geert Gruwez
Geert Gruwez earned 286 total points
ID: 33457459
um, ewangoya,
that's what that article is about ...

and the reason i wrote it, was to reference it
try reading it ...

you're almost there, you still need to let the progressbar update it's on screen display
ProgressBar.Value := aProgress;
ProgressBar.Update;

ow ... the TSomething ... descending from TThread ?
0
 
LVL 36

Expert Comment

by:Geert Gruwez
ID: 33457473
I agree with the separation,
but in this case consider the observer pattern

even for multiple levels

i'll show a sample in a minute with different  levels and the observer pattern
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 36

Assisted Solution

by:Geert Gruwez
Geert Gruwez earned 286 total points
ID: 33457566
well i was going to create a sample, but then i bumped into this
http://tdelphihobbyist.blogspot.com/2009/11/observer-design-pattern-in-delphi-pull.html

if you think about levels in coding then you should certainly look at design patterns
you might want to think about mvc (model-view-controller) ...
0
 
LVL 32

Assisted Solution

by:ewangoya
ewangoya earned 143 total points
ID: 33460548
@Geert_Gruwez

I should have read your article first. Same thing only you pass the procedure pointer on create.
0
 
LVL 36

Assisted Solution

by:Geert Gruwez
Geert Gruwez earned 286 total points
ID: 33461939
yes, passing parameters gives total indepedence to the lower level
0
 
LVL 8

Author Comment

by:BdLm
ID: 33461955
what about for level 3 :

function heavyCalcLevel3(.......;  aFeedBackElement : TObject);
begin


        if  ( aFeedBackElement  is TProgresslbar then  
                    begin

                      ......

                   end;


end;

Thanks for your discussion
0
 
LVL 36

Assisted Solution

by:Geert Gruwez
Geert Gruwez earned 286 total points
ID: 33462237
you are expecting inside the thread that you are working with a progressbar
this limits the GUI to giving a progressbar to your thread

what if someone invented this really cool amazing TCalcStatus object which had a PercentDone value as a property

if you want to take a general approach to a problem then don't pin it down on using a TProgressbar

in nearly all calculations which have a indication with feedback
it's up to the gui how to display the progress or percentdone, not the thread
the thread is there to do the hard work, not the fancy screen work

a sample: lets consider something like bit torrent > this can download several files with different threads

level 1: download x number of files
level 2: download 1 specific file out of this list
level 3: download a chunk of this specific file

so:
in level 3: you have x number of bytes out of a total of Y >> translate to x/y*100 for percent done of this thread
in level 2: you could have 10 threads running, each downloading a chunk
  > the total of downloaded bytes / total file size * 100 for percent done of this file
in level 1: you could show the percentage of total bytes downloaded / total files size > total percent done

this is allways passing x number out of y number to do
i didn't talk about a progressbars yet in these threads

and there is the problem ... you could have a progressbar for each individual percentage
so you would need to report the individual progress to the higher level using x,y
it's allways up to the higher level what it does with this value ...

and how display it ?
i would do this within a devexpress TcxProgressbar within a devexpress TcxGrid
Off course it would have a progressbar for each level


so i would use this as feedback

type 
  TFeedbackProgressEvent = 
    procedure (Sender: TObject; WorkDone, WorkToDo: integer) of object;

function heavyCalcLevel3(.......;  FeedBack : TFeedbackProgressEvent);
var x, y: integer;
begin
  x := 0;
  y := FileSize('x.zip');
  Feedback(Self, x, y);
  repeat
    file.ReadByte;
    x := x +1;
    Feedback(Self, x, y);
  until x >= y;
  Feedback(Self, y, y);
end;

type
  THeavyCalc2 = class
  private
    fFilesToProcess: TList;
    fTotalFilesSize: Cardinal;
    fTotalWorkDone: Cardinal;
    Calc3Threads: TList;
    procedure FeebackEvent(Sender: TObject; WorkDone, WorkToDo: integer);  
    
  end;

procedure THeavyCalc2.FeebackEvent(Sender: TObject; WorkDone, WorkToDo: integer);
begin
  if WorkDone = WorkToDo then 
  begin
    fTotalWorkDone := fTotalWorkDone + WorkToDo;
    Feeback(Self, fTotalWorkDone,  fTotalFileSize);
  end; 
end;

Open in new window

0
 
LVL 25

Expert Comment

by:epasquier
ID: 33462446
BdLm, Thanks for giving me some points, Geert has done a great job helping you with this topic where I only added stone to the building. I was ready to accept I would get no credit.

BUT :
When you select multiple answers, please do not select everything without consideration of the value of the answers. And you can change the amount of points each answers is worth, not just let the automatic division calculate it for you. With your way, it gives the impression that it is only needed to post a maximum of comments whatever the quality, and if more than one is selected then you will have better reward than a single complete explanation.

for example, you selected ewangoya #33460548 and geert response about it. They bring no value to the discussion.

Next time, select only the real answers to the question and change the value of the ones that helped you most (geert last post in this case is the main one and is worth by itself 300-400 pts). This will also ensure that the 'ACCEPTED SOLUTION' is the one with most points, so the one that really deserves it.
0
 
LVL 8

Author Comment

by:BdLm
ID: 33462498
Thanks for the inputs, my intension was to honor the complete discusssion, even geert again made a great job with very useful inputs for me. Should increase to points to 1000 :-)  

btw:

is there any language forcing people to develop software in 3 levels of architecture ? getting contributions to my software project from different people I get crazy if the violate the 3 level design style ....  
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now