Recent

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

cdbc

  • Hero Member
  • *****
  • Posts: 1535
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #210 on: August 21, 2024, 11:23:55 am »
Howdy  :D
If some of you, are using the mvp-setup, it just got updated to version: 9.21.08.2024  8-)
Features a couple of new factories & methods in 'istrlist' and a refactored 'model.main', to use these. Ofc, it also produces the new stuff...
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: 710
Re: Best way to exchange data between a form and a unit
« Reply #211 on: August 21, 2024, 05:48:45 pm »
I already had such a suspicion.I was following this one:
Quote
https://forum.lazarus.freepascal.org/index.php/topic,67154.0.html

I'm curious what the consequences are. I had started to revive my stuck app.

cdbc

  • Hero Member
  • *****
  • Posts: 1535
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #212 on: August 21, 2024, 06:20:13 pm »
Hi Hans
The 2 new factories (constructors) in play, you can see in 'mvp-setup's 'model.main', here's the constructor:
Code: Pascal  [Select][+][-]
  1. constructor TcsuModelMain.Create(aPresenter: IcsuPresenterMain; const aRoot: shortstring);
  2. var lfn: string = '';
  3. begin
  4.   inherited Create;
  5.   fPresenter:= aPresenter;
  6.   fRoot:= IncludeTrailingPathDelimiter(aRoot);
  7.   lfn:= format(csuTexts,[aRoot]);
  8.   if FileExists(lfn) then begin { file exists, could be another language, load it! }
  9.     { below is the new factory -v- }
  10.     fTextCache:= CreStrListFromFile(lfn); ///used to be: CreateStrList; ///
  11. ///used to be: fTextCache.LoadFromFile(lfn); ///
  12.   end else begin { file doesn't exist, use failsafe in english & try to write it to disk }
  13.     fTextCache:= CreStrListFromBytes(file_mvptexts); //<- new factory
  14.     try fTextCache.SaveToFile(lfn); except end; { doesn't matter to us if it fails :o) }
  15.   end;
  16. end;
As you can see, they save me a couple of codelines ~ just sugar  ;)
then have a look at the GetStaticTexts():
Code: Pascal  [Select][+][-]
  1. function TcsuModelMain.GetStaticTexts(const aSection: string; out aTarget: integer): IStringList;
  2. begin
  3.   if aSection = '' then exit(nil);
  4.   fSection:= '['+aSection+']'; fSecId:= IndexText(fSection,sects); // iterator-search
  5.   if fTextCache.Count = 0 then begin
  6.     fPresenter.Provider.NotifySubscribers(prStatus,nil,Str2Pch('(!) ERROR: Could NOT retrieve static texts!'));
  7.     exit(nil); /// maybe we should just comment this line and return an empty list, avoid AVs ///
  8.   end;
  9.   Result:= CreateStrList;
  10. ///  fRes:= Result; // tmp placeholder while searching, bug in TStrings-> you cant send userdata along
  11.   fTextCache.ForEach(@DoEach,Result);{ iterate over the source-list calling 'doeach' for each item }
  12. ///  fRes:= nil;
  13.   aTarget:= fSecId; // for the presenter to differentiate between views
  14. end;
You can see the difference in the 'ForEach(@DoEach,Result);' call, before I had to keep a tmp(fRes) variable hanging around, just to add to my 'Result' variable in another method, now I just send it along and can use it in the 'DoEach' method. You see below how it's used:
Code: Pascal  [Select][+][-]
  1. procedure TcsuModelMain.DoEach(const aValue: string; const anIdx: ptrint;
  2.                                anObj: TObject; aData: pointer);
  3. var ls: string; lid: integer;
  4. begin
  5.   if fSecId = -1 then exit;
  6.   ls:= LeftWord(aValue);
  7.   lid:= IndexText(ls,Sects);
  8.   if lid = fSecId then begin
  9.     IStringList(aData).Append(aValue); /// <-- HERE typecast(aData)
  10.     fInSection:= true;
  11.   end else begin
  12.     if fInSection then begin
  13.       case lid of
  14.         0..1: fInSection:= false; /// remember to adjust selector-values according to 'Sects',
  15.       end;                        /// the more views = the more selectors, easy-peasy
  16.       if fInSection then IStringList(aData).Append(aValue);
  17.     end; /////////////// ^------------^ ///// just a simple typecast /////
  18.   end;
  19. end;
This makes for cleaner code... (when I get around to cleaning it up)
I think this just about explains it. The 'ForEach'es missing 'UserData' param bothered me, so I decided to just implement it. It's all about convenience, you know...  :D
I don't think they'll have any groundbreaking consequences for you, won't break stuff either  ;D
Regards Benny
« Last Edit: August 21, 2024, 06:34:47 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: 1535
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #213 on: August 21, 2024, 06:30:29 pm »
Btw. Hans I think it's cool, that you're reviving your project, sometimes it's just a little detail somewhere, that sheds a whole new light on things...
Have fun with it and if you need anything from me, just holler  :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: 710
Re: Best way to exchange data between a form and a unit
« Reply #214 on: August 21, 2024, 06:46:23 pm »
Be careful what you say:
Quote
and if you need anything from me, just holler
:D Yesterday evening I was looking at how to make an app bilingual. I had trouble with the ini file. But don't say anything yet, I still have to get a good look at it. A second file or so.

Added…
Quote
I think it's cool, that you're reviving your project
Perhaps. But maybe the idea is not good in the first place. I'm not sure yet. So I'm going for another try. That's the advantage of a bit of hobbies. If it fails, it's not a big deal. At most, a dent in my ego. :)
« Last Edit: August 21, 2024, 07:01:27 pm by Hansvb »

cdbc

  • Hero Member
  • *****
  • Posts: 1535
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #215 on: August 21, 2024, 07:07:06 pm »
Hi
...uhmmm, I have though it, but I won't say nothing then  :D
It's quite easy, if you think about it  O:-)
Fingers crossed, you'll get it, I'm sure.
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: 710
Re: Best way to exchange data between a form and a unit
« Reply #216 on: August 22, 2024, 07:51:23 pm »
I'm not that fast. :D
You've already done it.

cdbc

  • Hero Member
  • *****
  • Posts: 1535
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #217 on: August 22, 2024, 08:23:12 pm »
Hi Hans
Hahaha... sorry mate, to be honest, that was an unfair contest on my side, i18n was part of the reason, I made the GetStaticTexts() the way I did  :D
Played with the idea all along and it literally took me 20 minutes, to implement the small changes, with double checks and all  ;D
The gui-stuff of managing the lot, I leave to you  :D right now it just loads the language specified in the 'i18n.cfg' @ startup, proof of concept  8)
The file 'i18n.cfg' is just because I didn't have an ini-file, the one value could just as easily be read from some existing options/settings -file...
It does show off the new features, quite nicely...
Well, now you've seen it, I hope you don't mind - too much  O:-)

Sorry, completely forgot: Have you got any questions?
Regards Benny
« Last Edit: August 22, 2024, 08:35:53 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: 710
Re: Best way to exchange data between a form and a unit
« Reply #218 on: August 22, 2024, 08:52:14 pm »
Quote
Sorry, completely forgot: Have you got any questions?
No questions yet. I hope I'll have time over the weekend to take a good look at it. Then a question will probably come up

Hansvb

  • Hero Member
  • *****
  • Posts: 710
Re: Best way to exchange data between a form and a unit
« Reply #219 on: August 23, 2024, 09:41:34 pm »
Hi,
I adopted the multilingual into an empty setup I was working on. I have that working now. Now i have to find out how and why it works. But that's what we have the debugger for.

Code: Pascal  [Select][+][-]
  1. feaLang:= CreStrListFromFile('i18n.cfg').Values['language'].Trim;
That needs to be a bit more robust. If the file does not exist you will get an access violation. Instead of the file i18n.cfg I can also look at my own settings.cfg file where language already happened to be a key. That's pretty cool.

cdbc

  • Hero Member
  • *****
  • Posts: 1535
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #220 on: August 23, 2024, 11:53:05 pm »
Hi Hans
Yeah, I admit that was a 'quickie', but it's just a /placeholder/ for _where_ it has to happen, before the mechanics run their course...  ;) In your 'settings'-file is a better place for it.
A "if Fileexist('i18n.cfg') then ..." would make it robust, because 'feaLang' is a "writable const" a.k.a. "static var" and is already rigged to fallback to 'en'  8-)
I'm happy, it works for you, that means the design is solid and after all, it is an example of how one /might/ go about, solving the 'i18n' task / problem...
I also like that, you can use 'Unitname' and 'Classname' for automatic sectioning, regarding texts in the file  8)
One thing to contemplate, would be creating a "RegisterSection();" procedure, to take care of /remembering/ to add to the 'Sects' array in 'model.main'...(I think I made a comment about 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

Hansvb

  • Hero Member
  • *****
  • Posts: 710
Re: Best way to exchange data between a form and a unit
« Reply #221 on: August 24, 2024, 06:09:36 pm »
I'm trying to understand it and use it in another place. For example, changing the language via a menu choice. I manage to do that, but I don't really understand it enough. I'm coming across too much code that I can't follow. That's going to take a while I'm afraid

What I have done and it works (but I worry if it is not too drastic).

If I change languages, this is immediately visible without having to restart the tool.

Created two menu options. English and Dutch.
Behind English it now says:
Code: Pascal  [Select][+][-]
  1.   feaLang:= 'EN';
  2.   Presenter:= CreatePresenterMain('');  


And after Dutch it now says:
Code: Pascal  [Select][+][-]
  1.   feaLang:= 'NL';
  2.   Presenter:= CreatePresenterMain('');  

Re-creating the presenter worries me. I don't think that's the intention

added: found a better way. please wait...
« Last Edit: August 24, 2024, 07:22:14 pm by Hansvb »

Hansvb

  • Hero Member
  • *****
  • Posts: 710
Re: Best way to exchange data between a form and a unit
« Reply #222 on: August 24, 2024, 07:31:26 pm »
This seems like a better way to me. Now the presenter etc. created at start-up remain intact. And switching the language still works immediately when you click in the menu. I am satisfied with this. :D

Code: Pascal  [Select][+][-]
  1. view.main
  2. procedure TfrmMain.mmiOptionsLanguageENClick(Sender: TObject);
  3. begin
  4.   feaLang:= 'EN';
  5.   fPresenter.SwitchLanguage(UnitName);
  6.   WriteSingleSetting('Language', feaLang);
  7. end;     
  8.  
  9. procedure TfrmMain.mmiOptionsLanguageENClick(Sender: TObject);
  10. begin
  11.   feaLang:= 'NL';
  12.   fPresenter.SwitchLanguage(UnitName);
  13.   WriteSingleSetting('Language', feaLang);
  14. end;     
  15.  
  16. presenter.main
  17. procedure TPresenterMain.SwitchLanguage(aSection: String);
  18. var
  19.   ldummy: integer;
  20. begin
  21.   fModel.SwitchLanguage;
  22.   fInternalMsg:= fModel.GetStaticTexts(ClassName,ldummy);
  23.   GetStaticTexts(aSection);
  24. end;
  25.  
  26. model.main
  27. procedure TModelMain.SwitchLanguage;
  28. begin
  29.   fTextCache:= CreStrListFromFile(format(mvpTexts,['',feaLang]));
  30. end;

cdbc

  • Hero Member
  • *****
  • Posts: 1535
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #223 on: August 24, 2024, 08:22:07 pm »
Hi Hans
Nah, recreating the presenter ...that would be *not* so bright, don't do that!
Instead, you could try to implement this in model.main:
Code: Pascal  [Select][+][-]
  1. procedure TfeaModelMain.ReloadTextCache;
  2. begin
  3.   fTextCache.Clear;
  4.   fTextCache.LoadFromFile(format(mvpTexts,[fRoot,feaLang]));
  5. end;  
And this in presenter.main:
Code: Pascal  [Select][+][-]
  1. procedure TfeaPresenterMain.RefreshTextCache(const aSection,aLangStr: string); //=^
  2. var
  3.   ldummy: integer;
  4. begin
  5.   feaLang:= trim(aLangStr);
  6.   fModel.ReloadTextCache;
  7.   fInternalMsg.AssignEx(fModel.GetStaticTexts(ClassName,ldummy)); /// clears first
  8.   GetStaticTexts(aSection);
  9. end;
...and remember to add them to their respective interfaces..
Then in View area just call:
Code: Pascal  [Select][+][-]
  1.  
  2. fPresenter.RefreshTextCache(UnitName,'menu-choice');
  3.  

That's how I would do it, if it has to be instantaneous and not on restart...
I'm assuming that you've saved the new value to file first.  ;)
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: 1535
    • http://www.cdbc.dk
Re: Best way to exchange data between a form and a unit
« Reply #224 on: August 24, 2024, 08:29:36 pm »
Hahaha...
This time you beat me to it  ;D
Well done =^
It's *so* nice to see, that you've really embraced this way of thinking, your solution shows this clearly, you're looking the right places for solutions  8)

edit: typo & this is a bit naughty(only work with com intf, else leaks):
Code: Pascal  [Select][+][-]
  1. fTextCache:= CreStrListFromFile(format(mvpTexts,['',feaLang]));
You're banking on the compiler free's the old one, ...it does.
The _nicer_ way is to use "AssignEx()"  ;D
Regards Benny
« Last Edit: August 24, 2024, 08:39:02 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

 

TinyPortal © 2005-2018