Recent

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

cdbc

  • Hero Member
  • *****
  • Posts: 1649
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #195 on: August 05, 2024, 06:01:17 pm »
Hi Hans  :)
No worries, here goes:
1) for each component you put on the form, you have to, name it e.g.:
    'lblSurname', then copy that name to clipboard and open the
    "mvptexts.ini" in some text-editor ...or lazarus, and find the section for
    your form's [name].
2) in this /msg/file you now make a new line and paste the label-name from
    the clipboard into it. Now you type '=' and the text you want in the
    components caption. *It has to be in the right [section] or you won't
    see it*

Then in view.main in the following proc, do like my example below:
Code: Pascal  [Select][+][-]
  1. procedure TfrmMain.DoStaticTexts(Texts: IStrings);
  2. var i: integer; lc: TComponent;
  3. begin
  4.   { here we set the form caption }
  5.   Caption:= Texts.Values[Name];
  6.   { now we iterate all the components on the form, to set each's caption }
  7.   for i:= 0 to ComponentCount-1 do begin
  8.     lc:= Components[i];
  9.     if (lc is TButton) then
  10.       TButton(lc).Caption:= Texts.Values[TButton(lc).Name];
  11.     /// add the following to DoStaticTexts ///
  12.     if (lc is TLabel) then
  13.       TLabel(lc).Caption:= Texts.Values[TLabel(lc).Name];
  14.     /// and for the rest of your panels, edits, statusbars,
  15.     /// just copy the 2 lines for each control  etc...
  16.   end;
  17. end;
Completely flexible, this solution, you just write the component-caption in another file, to be loaded at runtime... This "mvptexts.ini" can be easily translated to other languages, you know...  ;)
It's instead of having /fixed/ messages in the model...
HTH
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

cdbc

  • Hero Member
  • *****
  • Posts: 1649
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #196 on: August 05, 2024, 06:06:34 pm »
...If in doubt, look in the ini-file for the mvp-setup application ...and ofc the correlating view.main. (there are 2 forms in that program)
Keep the faith mate, it's just a plunge into the deep end  O:-) 8-)
Keep asking questions, I will answer all of them(if I can).
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 #197 on: August 05, 2024, 07:42:50 pm »
Aha, that works great. Now i have a place to start and explore the code with F7/F8 and "find in files".

I hardly dare to say it, but there was an error in your code and I was able to solve it. When the program runs in debug mode then there is an error in the while...:

Code: Pascal  [Select][+][-]
  1. function TModelMain.LeftWord(const aStr: string): string;
  2. var li: integer = 1;
  3. begin { pick the left-most word in a string }
  4.   Result:= aStr;
  5.  
  6.   if Result = '' then exit;
  7.   //while ((not (Result[li] in [#9,#13,#10,' '])) and (li <= Length(aStr))) do inc(li);  <<=== gives a range check error.
  8.   //changed to:
  9.   while ((li <= Length(aStr)) and ((not (Result[li] in [#9,#13,#10,' '])))) do begin <<=== this works with no error
  10.  
  11.   SetLength(Result,li-1);
  12. end;    


in my case li became 12 and that was out of the range for Result[12].

cdbc

  • Hero Member
  • *****
  • Posts: 1649
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #198 on: August 06, 2024, 01:13:10 am »
Hi Hans
Quote
I hardly dare to say it, but there was an error in your code and I was able to solve it.
COOL  8-) Thank you ...and I just made you famous  ;D
I've fixed it, with your code! Both the program & the product it produces...
Just pull the new bugfixed model.main from gitlab  8)
I'm glad it works for you \o/
Regards Benny
« Last Edit: August 06, 2024, 01:15:59 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 #199 on: August 07, 2024, 08:31:25 pm »
As far as I can tell from the setup program... Is it correct that I can put my own records for the transaction manager in
Code: Pascal  [Select][+][-]
  1. presenter.trax
in the types section? And regular records in
Code: Pascal  [Select][+][-]
  1. model.base
should be put after the
Code: Pascal  [Select][+][-]
  1.  end line; { TTransaction }
and for
Code: Pascal  [Select][+][-]
  1. implementation
?

cdbc

  • Hero Member
  • *****
  • Posts: 1649
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #200 on: August 08, 2024, 12:50:47 am »
Hi Hans
Yes to all the questions or yes you understand it correctly 😉
Although, the/records/ you define and implement in 'trax' should all be classes and descend from 'TxxxTransaction' and perhaps implement 'IxxxTrxExec'.
That's because you can't use records with 'TrxManager', only classes.
Note: 'base' is a/super/ unit, don't over-use it, if you can use 'decl', then that's better...
Hth 😊
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 #201 on: August 09, 2024, 04:06:23 pm »
hi,

It took me almost all afternoon to make 2 transactions. 1 according to the "old" way and a self-committing transaction. (I need to get familiar with the locations for everything again).

The old way: view.main menuItem.click opens a dialog box, (created in the menuitem function so not hidden away in a separate unit  :D).
I take the name you enter in the dialog box and put it in a property of the transaction class and then start committransaction. The commit transaction starts a commit function, which then starts a function in the model. Model returns a result to the transaction which then executes the NotifySubscribers(). Then I can start a DOsomething function in the view.main. So that's actually how it worked in the old model. What bothers me is that I immediately put my first record in model.base, while you indicate that I should keep it as clean as possible. I put my record in model.base so that I can access it from model.decl, model.int, model.main, view.main. In model.decl I have set an alias to model.base
Can that be done better?

I also have a self commit transaction working, but I doubt whether that is good. I created a new interface for this in model.decl. If that is necessary for every self-committing transaction, then you can get quite a lot of interfaces. Is that the intention? I was also thinking about using the existing interface, but then the execute function would probably be large. I don't think that's the intention.

When is it wise to use a self-committing transaction and when not?


cdbc

  • Hero Member
  • *****
  • Posts: 1649
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #202 on: August 09, 2024, 11:18:55 pm »
Hi Hans
I will start my lappy tomorrow at siesta time, because it's so damn hot here. We are climbing towards 39 degrees here in Novigrad Croatia ☀️😎👍
Then I can checkout a fresh MVP-setup and run it...
The idea is that 'Execute' is an entry point to the trx-class, no extra interfaces needed...
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 #203 on: August 10, 2024, 09:11:12 am »
Hi,
There's no rush. Holidays come first. (And also...It's just a hobby for me so there's no rush at all). I saw that we will have warm weather tomorrow.


This is pretty much what I did as a test so far:

view.main
Code: Pascal  [Select][+][-]
  1. procedure TfrmMain.Button1Click(Sender: TObject);
  2. var
  3.   SaveDialog: TSaveDialog;
  4.   lcdbt : TCreateDbFileTransaction;  // Local Create Database Transaction
  5. begin
  6.   SaveDialog := TSaveDialog.Create(nil);
  7.   try
  8.     with saveDialog do begin
  9.       Title := 'Create new database file.';  // Maak nieuw database bestand.
  10.       InitialDir := ExtractFilePath(Application.ExeName) + adDatabase;
  11.       Filter := 'SQLite db file|*.db';
  12.       DefaultExt := 'db';
  13.       Options := saveDialog.Options + [ofOverwritePrompt, ofNoTestFileCreate];
  14.  
  15.       if Execute then begin
  16.         lcdbt:= fPresenter.TrxMan.StartTransaction(prCreDatabaseFile_SelfExecuteTest) as TCreateDbFileTransaction;
  17.         lcdbt.FullFileName:= FileName;
  18.         fPresenter.TrxMan.CommitTransaction;
  19.       end;
  20.     end;
  21.   finally
  22.     SaveDialog.Free;
  23.   end;  
  24. end;  
  25.  

model.decl
Code: Pascal  [Select][+][-]
  1. const
  2.   //added a new guid for testing self committing transaction  
  3.   SGUIDICreDir = '{E45DB442-EDF5-4894-ADA8-78D2D90427C0}';
  4.        
  5.   { aliased (p)rovider (r)easons for observer action/reaction }  
  6.   prCreDatabaseFile_SelfExecuteTest = model.base.prCreDatabaseFile_SelfExecuteTest;     // new for testing self committing transaction
  7.  
  8.   ...
  9. procedure TTransactionManager.CommitTransaction;
  10. var
  11.   lte: ITrxExec; { when you use "self-committing" transactions. in doubt? ask me in forum }  
  12. begin
  13.   if InTransaction then begin
  14.     case fTrx.ModReason of
  15.       prNone: raise Exception.Create('Error! TTransactionManager.CommitTransaction: "ModReason = prNone"'); // failsafe
  16.       prDataAdded: ;      // 2  
  17.       { example of using the trxExec interface, "TTextEdit" implements it (if you write the code) }
  18.       prDataChanged: if fTrx.GetInterface(SGUIDITrxExec,lte) then begin
  19.                        if lte.Execute(Self) then
  20.                          fOwner.Provider.NotifySubscribers(prStatus,nil,Str2Pch(' (i) Textfile "'+lte.Title+'" changed successfully'));
  21.                      end;      // 3
  22.       prDataDeleted: ;    // 4
  23.  
  24.       // just testing for now
  25.       prCreDatabaseFile: CommitCreateDbFile;  // "old fashioned" way
  26.  
  27.      // try the self committing transaction
  28.       prCreDatabaseFile_SelfExecuteTest: if fTrx.GetInterface(SGUIDICreDir,lte) then begin  // <<==  the new sguid
  29.                                            if lte.Execute(Self) then
  30.                                              fOwner.Provider.NotifySubscribers(prStatus,nil,Str2Pch('Self commit is a success.'));
  31.       end;
  32.     end;
  33.     FreeAndNil(fTrx); // done, free and make sure it's nil again!  
  34. end;
  35.  
  36. ...
  37.  
  38. function TTransactionManager.StartTransaction(aModReason: word): TTransaction;
  39. begin
  40.   if not InTransaction then case aModReason of
  41.     prCustom: fTrx:= TTransaction.Create(aModReason); // 1 ~ doen't cause an exception, 0 does!
  42.     prDataChanged: fTrx:= TTextEdit.Create(aModReason); // 1
  43.     prCreDatabaseFile: fTrx:= TCreateDbFileTransaction.Create(aModReason); // "old fashioned" way
  44.     prCreDatabaseFile_SelfExecuteTest: fTrx:= TCreateDbFileTransaction.Create(aModReason);  // test self committing transaction
  45.     /// etc...
  46.     else fTrx:= TTransaction.Create(aModReason); // 0 or anything undefined by us
  47.   end;
  48.   Result:= fTrx;
  49. end;
  50.  

presenter.trax
Code: Pascal  [Select][+][-]
  1.   { TCreateDbFileTransaction }
  2.  
  3. // can by used for the "old fashioned way" and with the execute function also used for self committing transaction
  4.   TCreateDbFileTransaction = Class(TTransaction, ItrxCreNewFile)
  5. private
  6.   FFullFileName: String;
  7.   function Get_FullFileName: String;
  8.   procedure Set_FullFileName(AValue: String);
  9. public
  10.   function Execute(aMgr: ITransactionManager): boolean;  // Needed for the self committing transaction
  11.   property FullFileName : String read Get_FullFileName write Set_FullFileName;
  12. end;
  13.  
  14.  
  15. function TCreateDbFileTransaction.Execute(aMgr: ITransactionManager): boolean;
  16. var
  17.   lRec: TCreDbFileRec;
  18. begin
  19.   lRec:= aMgr.Owner.Model.CreateDbFile(FullFileName);    // Works now a a test
  20.   Result:= lRec.cdbfSucces;  // needed for the statusbartext
  21.  
  22.   // also still worrks here
  23.   aMgr.Owner.Provider.NotifySubscribers(prCreDatabaseFile_SelfExecuteTest, Self, @lRec);// you can even pick it up in view.main with a DOsomething...
  24. end;  
  25.  

cdbc

  • Hero Member
  • *****
  • Posts: 1649
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #204 on: August 10, 2024, 02:30:51 pm »
Hi Hans
Damn good, if not perfect! Good on you mate, and you've realized that the interface is only needed in the 'TrxManager' for 'Committing'.  8)
Actually you can get away with just using the 'built-in' 'ItrxExec' interface, as it provides the /execute-through-owner/ mechanism, namely: 'Execute(TrxMgr)'.
You don't need to create new interfaces in 'model.intf', for each new little 'wrinkle' in your app, just create a transaction that implements 'ItrxExec', thats it. 'Cause in the rest of its lifetime, you'll use the class-part of it... I think it saves us a /hellofalot/ of typing  :D
I'm assuming that 'ItrxCreNewFile' descends from 'ItrxExec'...
Then you can:
Code: Pascal  [Select][+][-]
  1.      // try the self committing transaction
  2.       prCreDatabaseFile_SelfExecuteTest: if fTrx.GetInterface(SGUIDItrxExec,lte) then begin  // <<= use exec sguid
  3.                                            if lte.Execute(Self) then
  4.                                              fOwner.Provider.NotifySubscribers(prStatus,nil,Str2Pch('Self commit is a success.'));
  5.       end;
Use the 'built-in' "SGUIDItrxExec" in TrxManager, i.e.: only 1 local variable in 'CommitTransaction' -> lte; The fTrx transaction *knows* which type it is, so it will call the right 'Execute' method.
For Convenience, I just reference the 'presenter.trax', in the view I'm using it in, it's a 'minion' of the presenter, so that's perfectly legal and saves me a couple of aliases  :D
It's all about scope and what the different /components/ need to do their job...
In short, you did the correct and longer version =^ The above explanation is just to show you the "Shorthand" or easier way... (which corners you can cut)  ;D
Warm and sunny regards Benny  8-)
« Last Edit: August 10, 2024, 02:33:21 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 #205 on: August 10, 2024, 05:57:44 pm »
Good, then I've spent my afternoon well. I still haven't seen everything in the new setup I notice. I just saw the blank dostatus in view.main. It comes in handy.

added (19:47):
The short version works. I now jump to the Exceute function without creating a new interface. Cool.
« Last Edit: August 10, 2024, 07:48:20 pm by Hansvb »

Hansvb

  • Hero Member
  • *****
  • Posts: 715
Re: Best way to exchange data between a form and a unit
« Reply #206 on: August 16, 2024, 09:47:30 pm »
... still discovering new things in your "mvp_setup_tool".

This one took me an hour before I found my mistake.  :-[ but now I won't forget it anymore

Code: Pascal  [Select][+][-]
  1. model.main
  2. Sects: TStringArray = ('[view.main]', '[view.configure]'); { remember to add your views to this array }

Forward functions in the interface part are new to me. Never used it. (works great).
I still have to google / read because using Singleton is new to me. :-X

cdbc

  • Hero Member
  • *****
  • Posts: 1649
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #207 on: August 16, 2024, 10:07:32 pm »
Hi Hans
Hehehe... I thought there might be "some flesh on them bones" for you  :D
Have fun mate, there are a lot of small tricks /sprinkled/ around that little app  :P
:: I might even have commented some of them  ;D
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 #208 on: August 16, 2024, 11:08:17 pm »
I'm having fun. It feels like I'm finally learning to program a little bit, even though it's still a hobby

cdbc

  • Hero Member
  • *****
  • Posts: 1649
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #209 on: August 16, 2024, 11:13:02 pm »
Hi
Great, that sounds good to me, I'm happy for you  :)
It's good fun, isn't it... :-X
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