Recent

Author Topic: Best way to exchange data between a form and a unit  (Read 52039 times)

Hansvb

  • Hero Member
  • *****
  • Posts: 715
Re: Best way to exchange data between a form and a unit
« Reply #135 on: February 19, 2024, 07:38:07 pm »
Quote
The important thing is: "Keep the visual stuff separated from data & logic"
I never did that and now i find forms and dialog a lot in the uses section of my units. At least I see that now.
I have a tool that I want to create so now i have a good reason to practice the new things.

Thaddy

  • Hero Member
  • *****
  • Posts: 16201
  • Censorship about opinions does not belong here.
Re: Best way to exchange data between a form and a unit
« Reply #136 on: February 19, 2024, 08:57:45 pm »
I told you so very early and Benny did a great job to help you. You will succeed....
If I smell bad code it usually is bad code and that includes my own code.

cdbc

  • Hero Member
  • *****
  • Posts: 1678
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #137 on: February 19, 2024, 09:32:50 pm »
Hi
Quote
At least I see that now.
YiPeehh, Yes that's the 'light' you're seeing  ;)
Good on you mate, then I wish you 'happy practicing' and fair wind with your project... got questions... Just holler  :D
I too believe, you will succeed =^ (that's a thumbs up)
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

Hansvb

  • Hero Member
  • *****
  • Posts: 715
Re: Best way to exchange data between a form and a unit
« Reply #138 on: February 26, 2024, 07:51:32 pm »
Hi,

If I open a second view (form) from my main view (form). Is it then allowed to link the presenter of the main view to this second view or should the second view have its own presenter?

The second view is only used briefly to retrieve some data that I enter into TEdits.

cdbc

  • Hero Member
  • *****
  • Posts: 1678
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #139 on: February 26, 2024, 08:59:43 pm »
Hi
Both are allowed, that comes down to personal taste...
I'd say, that if the data in question are related, I'd just use the same Presenter.
The extendable possibilities comes into play with higher complexity...
The good ol' KISS*) principle still holds true, i.e.: don't over-complicate things(just because you can)  8-)
*) Keep It Simple (Stupid)
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

Hansvb

  • Hero Member
  • *****
  • Posts: 715
Re: Best way to exchange data between a form and a unit
« Reply #140 on: February 27, 2024, 06:31:01 pm »
Aha. Thanks.

Hansvb

  • Hero Member
  • *****
  • Posts: 715
Re: Best way to exchange data between a form and a unit
« Reply #141 on: March 17, 2024, 09:12:19 pm »
Hi,

I'm trying to save a settings setting to an ini file.
The function below works but doesn't seem right to me.

Code: Pascal  [Select][+][-]
  1. procedure TfrmViewMain.CheckBoxActivateLoggingChange(Sender: TObject);
  2. var
  3.   lStrx : TSettingsTransaction;
  4.   lPrepareRec : TSettingsRec;
  5. begin
  6.   // onderstaande werkt maar deugt niet.
  7.   lStrx := FPresenter.TrxMan.StartTransaction(msUpdateSettings) as TSettingsTransaction;
  8.   try  
  9.     //Settings object has a record that contains the current data. That will be picked up here.
  10.     lPrepareRec := FPresenter.GetSettingsrecord;  // function GetSettingsrecord: TSettingsRec;
  11.        
  12.     // Adjust a field in the settings record:
  13.     lPrepareRec.setActivateLogging := CheckBoxActivateLogging.Checked;
  14.        
  15.     // put the changed record into the transaction:
  16.     lStrx.AllAppSettings := lPrepareRec;
  17.        
  18.         // Commit the transaction. This will work with the changed record and saves the change. so it works but this can't be right....
  19.     FPresenter.TrxMan.CommitTransaction;
  20.   except
  21.     fPresenter.TrxMan.RollbackTransaction;
  22.   end;
  23. end;
  24.  

Maybe my settings unit is wrong or the reference to the settings class in the model is not useful. I don't really know where to look. (time to stop today).

cdbc

  • Hero Member
  • *****
  • Posts: 1678
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #142 on: March 17, 2024, 11:23:33 pm »
Hi Hans
Nice to see you again and you've been at it I see  :)
Well, with the code you provide, you could try this:
Code: Pascal  [Select][+][-]
  1. (* I assume, that the transaction has a copy of the TSettingsRec, so you can skip the local one *)
  2. procedure TfrmViewMain.CheckBoxActivateLoggingChange(Sender: TObject);
  3. var
  4.   lStrx : TSettingsTransaction;
  5. begin
  6.   // onderstaande werkt maar deugt niet.
  7.   lStrx := FPresenter.TrxMan.StartTransaction(msUpdateSettings) as TSettingsTransaction;
  8.   try  
  9.     //Settings object has a record that contains the current data. That will be picked up here.
  10.     (* why not put it directly in the transaction object, that way you save the local record *)
  11.     lStrx.AllAppSettings := FPresenter.GetSettingsrecord;  // function GetSettingsrecord: TSettingsRec;
  12.     (* ^ - - - ^ here *)  
  13.     // Adjust a field in the settings record:
  14.     lStrx.AllAppSettings.setActivateLogging := CheckBoxActivateLogging.Checked;
  15.     (* ^ - - - ^ and here *)
  16.     // Commit the transaction. This will work with the changed record and saves the change. so it works but this can't be right....
  17.     FPresenter.TrxMan.CommitTransaction;
  18.   except
  19.     fPresenter.TrxMan.RollbackTransaction;
  20.   end;
  21. end;
As you can see from my notes in the code, I can only save you a local record... You note that it works, that's good enough for me... 8)
What doesn't look right to you?!?
edit: Had another look and I might have an idea, that involves pointers & {$modeswitch advancedrecords}, but I think it best, to keep it simple... for now anyway, let me know if you feel adventurous.  :D
Regards Benny
« Last Edit: March 17, 2024, 11:31:48 pm by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

Hansvb

  • Hero Member
  • *****
  • Posts: 715
Re: Best way to exchange data between a form and a unit
« Reply #143 on: March 18, 2024, 10:24:54 pm »
Thanks.
Yes I have been at it for a little, even though I currently have a kind of love-hate relationship with it. I hadn't started Lazarus for about 2 or 3 weeks and last week the penny suddenly dropped I thought. (Google translation). So I finally started working on a new tool.

I thought the checkbox onchange couldn't be good because when I use a few checkboxes I get a lot of almost duplicate code just to remember a few checkmarks.  When that happens, I usually make a mistake.

Park the adventurous code for a while.  ::)

cdbc

  • Hero Member
  • *****
  • Posts: 1678
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #144 on: March 19, 2024, 03:00:24 am »
Hi
That's the spirit  ;)
Nice to hear, your efforts now, _will_ pay you back  8)
Remember, that if you have a field/member of the transaction, say e.g.: "TSettingsTransaction.Sender : TObject", then you are able to send the /offending/ checkbox along, throug the observer mechanism in i.e.: "procedure HandleObsNotify(aReason: TProviderReason;aNotifyClass: TObject;UserData: pointer);" and then check for it in the /common/ handler e.g.:
Code: Pascal  [Select][+][-]
  1. TSomeView.DoSetChecks(anObj: TObject;aSettingsRec: PSettingsRec);
  2. begin
  3.   ...
  4.   with aSettingsRec^ do begin
  5.     if anObj is TCheckBox then begin
  6.       if TCheckBox(anObj).Name = 'chbActiveLogging' then TCheckBox(anObj).Checked:= srActiveLog; // field of record
  7.       ...
  8.       etc...
  9.     end;
  10.   end;
  11. end;
That should alleviate duplicate code...  :D
Just a thought, anyway, best keep it simple.
Regards Benny
« Last Edit: March 19, 2024, 03:18:10 am by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

Hansvb

  • Hero Member
  • *****
  • Posts: 715
Re: Best way to exchange data between a form and a unit
« Reply #145 on: March 30, 2024, 01:43:24 pm »
Hi,
I'm moving very slowly.
For those who are interested. I now have a second view (menu: Options, settings) that uses the same presenter as the first view. And that seems to work.

cdbc

  • Hero Member
  • *****
  • Posts: 1678
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #146 on: March 30, 2024, 02:22:08 pm »
Hi
Cool  8-)
Let's have a 'LookSee'  :)
edit:
Me Likey, good on you Hans  8)
Keep on going, like this...

Regards Benny
« Last Edit: March 30, 2024, 05:13:16 pm by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

Hansvb

  • Hero Member
  • *****
  • Posts: 715
Re: Best way to exchange data between a form and a unit
« Reply #147 on: March 30, 2024, 04:56:16 pm »
i think there is at least one mistake. the model is destroyed when closing the configview. :-[
« Last Edit: March 30, 2024, 05:00:50 pm by Hansvb »

cdbc

  • Hero Member
  • *****
  • Posts: 1678
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #148 on: March 30, 2024, 05:26:53 pm »
Hi
Hmmm, well yes  ...you should practice more "borrowing".
Why not just use the presenter, you already have...?!? Like this:
Code: Pascal  [Select][+][-]
  1.   TfrmViewConfigure = class(TForm, IView)  // same View interface as the MainView
  2.     btnClose: TButton;
  3.     chkActiveLogging: TCheckBox;
  4.     chkAppenLogging: TCheckBox;
  5.     gbLogging: TGroupBox;
  6.     PageControlConfigure: TPageControl;
  7.     TabSheetMiscellaneous: TTabSheet;
  8.     TabSheetAppDb: TTabSheet;
  9.     procedure btnCloseClick(Sender: TObject);
  10.     procedure chkActiveLoggingChange(Sender: TObject);
  11.     procedure chkAppenLoggingChange(Sender: TObject);
  12.     procedure FormCreate(Sender: TObject);
  13.     procedure FormDestroy(Sender: TObject);
  14.     procedure FormShow(Sender: TObject);
  15.   private
  16.     FSubscriber : TobsSubscriber;  // Holds the Observer.
  17.     ////////////// v
  18.     FPresenter : IPresenter;       // Holds the (I)Presenter.
  19.     ////////////// ^
  20.     function get_Presenter: IPresenter;
  21.     function get_Subscriber: IobsSubscriber;
  22.     procedure set_Presenter(AValue: IPresenter);
  23.     function Obj: TObject;
  24.     procedure DoSetChecks(Sender: TObject);
  25.   protected
  26.     procedure HandleObsNotify(aReason: TProviderReason;aNotifyClass: TObject;UserData: pointer);
  27.     procedure DoSetStaticTexts(aTextRec: PStaticTextsAll);
  28.     procedure ReadSettings;
  29.     procedure DoReadSettings({%H-}aSender: TObject; aData: Pointer);
  30.   public
  31.     ////////////// v
  32.     constructor CreateWith(anOwner: TComponent;aPresenter: IPresenter);
  33.     ////////////// ^
  34.     property Subscriber: IobsSubscriber read get_Subscriber;
  35.     property Presenter: IPresenter read get_Presenter write set_Presenter;
  36.   end;
and then implement it:
Code: Pascal  [Select][+][-]
  1. constructor TfrmViewConfigure.CreateWith(anOwner: TComponent; aPresenter: IPresenter);
  2. begin
  3.   Create(anOwner);
  4.   FPresenter:= aPresenter; { it's an interface, NO need to free :-) }
  5. end;
...And then change the class to use it like this e.g.:
Code: Pascal  [Select][+][-]
  1. procedure TfrmViewMain.mmiOptionsOptionsClick(Sender: TObject);
  2. var
  3.   frm : TfrmViewConfigure;
  4. begin  // use the same presenter as the MainView v  (AS AN INTERFACE)
  5.   frm := TfrmViewConfigure.CreateWith(Self,FPresenter);
  6.   try  
  7.     frm.ShowModal;
  8.   finally
  9.     frm.Free;
  10.   end;
  11. end;
I'll leave it up to you to figure out, what NOT to Create / Free
in the 'SettingsForm', but try to make this example work...  %)
Got questions... Just holler  ;)
edit: Important--->
  Don't Free the Presenter in the SettingsForm... EVER!!!
  You are just /borrowing/ it ;D
  Only the 'MainForm' owns the presenter!

Regards Benny
« Last Edit: March 30, 2024, 05:39:33 pm by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

cdbc

  • Hero Member
  • *****
  • Posts: 1678
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #149 on: March 30, 2024, 07:54:05 pm »
Hi
Here's my take on 'ViewConfigure' unit:
Code: Pascal  [Select][+][-]
  1. unit ViewConfigure;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ComCtrls, StdCtrls,
  9.   obs_prosu, vwmain.intf, vwmain.decl, vwmain.presenter, vwmain.types;
  10.  
  11. type
  12.  
  13.   { TfrmViewConfigure }
  14.  
  15.   TfrmViewConfigure = class(TForm, IView)  // same View interface as the MainView
  16.     btnClose: TButton;
  17.     chkActiveLogging: TCheckBox;
  18.     chkAppenLogging: TCheckBox;
  19.     gbLogging: TGroupBox;
  20.     PageControlConfigure: TPageControl;
  21.     TabSheetMiscellaneous: TTabSheet;
  22.     TabSheetAppDb: TTabSheet;
  23.     procedure btnCloseClick(Sender: TObject);
  24.     procedure chkActiveLoggingChange(Sender: TObject);
  25.     procedure chkAppenLoggingChange(Sender: TObject);
  26.     procedure FormCreate(Sender: TObject);
  27.     procedure FormDestroy(Sender: TObject);
  28.     procedure FormShow(Sender: TObject);
  29.   private
  30.     FSubscriber : TobsSubscriber;  // Holds the Observer.
  31.     FPresenter : IPresenter;       // Holds the Presenter.
  32.  
  33.     function get_Presenter: IPresenter;
  34.     function get_Subscriber: IobsSubscriber;
  35.     procedure set_Presenter(AValue: IPresenter);
  36.     function Obj: TObject;
  37.     procedure DoSetChecks(Sender: TObject);
  38.   protected
  39.     procedure HandleObsNotify(aReason: TProviderReason;aNotifyClass: TObject;UserData: pointer);
  40.     procedure DoSetStaticTexts(aTextRec: PStaticTextsAll);
  41.     procedure ReadSettings;
  42.     procedure DoReadSettings({%H-}aSender: TObject; aData: Pointer);
  43.   public
  44.     constructor CreateWith(anOwner: TComponent;aPresenter: IPresenter);
  45.     property Subscriber: IobsSubscriber read get_Subscriber;
  46.     property Presenter: IPresenter read get_Presenter write set_Presenter;
  47.   end;
  48.  
  49. var
  50.   frmViewConfigure: TfrmViewConfigure;
  51.  
  52. implementation
  53.  
  54. {$R *.lfm}
  55.  
  56. { TfrmViewConfigure }
  57.  
  58. procedure TfrmViewConfigure.btnCloseClick(Sender: TObject);
  59. begin
  60.   Close;
  61. end;
  62.  
  63. procedure TfrmViewConfigure.chkActiveLoggingChange(Sender: TObject);
  64. begin
  65.   DoSetChecks(Sender);
  66. end;
  67.  
  68. procedure TfrmViewConfigure.chkAppenLoggingChange(Sender: TObject);
  69. begin
  70.   DoSetChecks(Sender);
  71. end;
  72.  
  73. procedure TfrmViewConfigure.FormCreate(Sender: TObject);
  74. begin
  75.   // at the moment it's not in use
  76. end;
  77.  
  78. procedure TfrmViewConfigure.FormDestroy(Sender: TObject);
  79. begin
  80.   if Assigned(FPresenter) then begin
  81.     FPresenter.Provider.UnSubscribe(FSubscriber);
  82.     FSubscriber.Free;
  83.     FPresenter:= nil;
  84.   end;
  85. end;
  86.  
  87. procedure TfrmViewConfigure.FormShow(Sender: TObject);
  88. begin
  89.   FPresenter.ReadSettings;
  90. end;
  91.  
  92. function TfrmViewConfigure.get_Presenter: IPresenter;
  93. begin
  94.   Result := FPresenter;
  95. end;
  96.  
  97. function TfrmViewConfigure.get_Subscriber: IobsSubscriber;
  98. begin
  99.   Result := FSubscriber;
  100. end;
  101.  
  102. procedure TfrmViewConfigure.set_Presenter(AValue: IPresenter);
  103. begin
  104.   { This is called when the view is created. }
  105.   if aValue = nil then begin
  106.     if Assigned(fPresenter) then FPresenter.Provider.UnSubscribe(FSubscriber);    // ==> Provider = property from TPresenter. LET OP: Hier koppel je de  HandleObsNotify
  107.     FPresenter:= nil;
  108.     exit;
  109.   end;
  110.   if aValue <> fPresenter then begin
  111.     if Assigned(FPresenter) then fPresenter.Provider.UnSubscribe(FSubscriber); { we can't detach nil }
  112.     if Assigned(aValue) then begin
  113.       FPresenter:= aValue;
  114.       FPresenter.Provider.Subscribe(FSubscriber);
  115.       FPresenter.GetStaticTexts(gstAll);  // Get All static texts
  116.     end;
  117.   end;
  118. end;
  119.  
  120. function TfrmViewConfigure.Obj: TObject;
  121. begin
  122.   Result := self;
  123. end;
  124.  
  125. procedure TfrmViewConfigure.DoSetChecks(Sender: TObject);
  126. var
  127.   lStrx : TSettingsTransaction;
  128.   lPrepareRec : TSettingsRec;
  129. begin
  130.   lStrx := FPresenter.TrxMan.StartTransaction(msUpdateSettings) as TSettingsTransaction;
  131.   try
  132.     lPrepareRec := FPresenter.GetSettingsrecord;  // Get the current record.
  133.  
  134.     if (Sender as TCheckBox).Name = 'chkActiveLogging' then
  135.       lPrepareRec.setActivateLogging := chkActiveLogging.Checked
  136.     else if (Sender as TCheckBox).Name = 'chkAppenLogging' then
  137.       lPrepareRec.setAppendLogFile := chkAppenLogging.Checked;
  138.     //..
  139.  
  140.     lStrx.AllAppSettings := lPrepareRec;
  141.     FPresenter.TrxMan.CommitTransaction;
  142.   except
  143.     fPresenter.TrxMan.RollbackTransaction;
  144.   end;
  145. end;
  146.  
  147. procedure TfrmViewConfigure.HandleObsNotify(aReason: TProviderReason;
  148.   aNotifyClass: TObject; UserData: pointer);
  149. begin
  150.   case aReason of
  151.     prStaticTexts: DoSetStaticTexts(UserData);
  152.     prAppSettings: DoReadSettings(aNotifyClass,UserData);
  153.   end;
  154. end;
  155.  
  156. procedure TfrmViewConfigure.DoSetStaticTexts(aTextRec: PStaticTextsAll);
  157. begin
  158.   with aTextRec^ do begin
  159.     Caption := staVwConfigure;
  160.     btnClose.caption := staOptionsBtnCloseCaption;
  161.     TabSheetAppDb.Caption := staTbsAppDdCaption;
  162.     TabSheetMiscellaneous.Caption := staTbsMiscellaneousCaption;
  163.     gbLogging.Caption := staGbLoggingCaption;
  164.     chkActiveLogging.Caption := staChkActiveLoggingCaption;
  165.     chkAppenLogging.Caption := staChkAppendLoggingCaption;
  166.   end;
  167. end;
  168.  
  169. procedure TfrmViewConfigure.ReadSettings;
  170. begin
  171.  
  172. end;
  173.  
  174. procedure TfrmViewConfigure.DoReadSettings(aSender: TObject; aData: Pointer);
  175. begin
  176.   with PSettingsRec(aData)^ do begin
  177. //    if setSucces then begin
  178.         chkActiveLogging.Checked := setActivateLogging;
  179.         chkAppenLogging.Checked := setAppendLogFile;
  180.  
  181.   //  end else begin
  182.   //    Caption := 'read setting: failed';
  183.   //  end;
  184.  
  185.   end;
  186. end;
  187.  
  188. constructor TfrmViewConfigure.CreateWith(anOwner: TComponent; aPresenter: IPresenter);
  189. begin
  190.   Create(anOwner);
  191.   FSubscriber := CreateObsSubscriber(@HandleObsNotify); { here's just fine }
  192.   Presenter:= aPresenter; { it's an interface, NO need to free :-) }
  193. end;
  194.  
  195. end.
  196.  
you also need to change the presenter: >> be back in a little while with that <<
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

 

TinyPortal © 2005-2018