Jump to content

PhilPlus

Members
  • Content Count

    25
  • Joined

  • Last visited

Posts posted by PhilPlus


  1. Hello David

    Again I don't see the real problem. 

    When you call the API just send a function which parse the parameter TTABSheet and return a tstringlist (or a string or an array).

    function sendData(MyTab: TTabSheet): tstringList;
    var
      comp: TComponent;
    begin
      for comp in MyTab do
      begin
        if (comp is Tcheckbox) and  then
          Result.add('"' + comp.Name + '":"' + booltostr(Tcheckbox(comp).checked)) +'"' //or other logic
        else
        begin
        	// other comp logic;
        end;
      end;
    
    end;

    After you just have to add the TstringList.commatext into your JSON Request.

     

     

    • Like 1

  2. 10 hours ago, Anders Melander said:

    In principle, all FireDAC datasets are memory datasets. TFDMemTable is just a FireDAC dataset with no database connection.

     

    FireDAC supports both "offline mode" and cached updates, so there's really no need to use TClientDataSet in this case.

     

    However, it sounds as if the OP really just needs to set up the TFDQuery to fetch all data and then close the DB cursor.
    Something like this:

    
    Query.FetchOptions.Mode := fmAll;
    Query.FetchOptions.AutoClose := True;

     

    Ok but even with these options, when the TConnection is closed (FDConnection1.Connected := false) all the data are lost. So how to use the "offlien mode" ?


  3. On 11/13/2022 at 5:42 PM, mjustin said:

    A TClientDataSet (together with a TDataSetProvider) can be used. Even when the Connection is closed, the TClientDataSet is still showing all data.

    This briefcase-model programming style is available since around Delphi 3, where the architecture was branded as MIDAS, later renamed to Datasnap.

     

    So basically this is needed:

    * a TFDQuery

    * which is connected to a TDatasetProvider,  which in turn

    * is connected to the TClientDataSet.

     

    The TFDQuery or its connection may be closed without losing the data in the TClientDataSet

     

    Resources:

    https://docwiki.embarcadero.com/Libraries/Sydney/en/Datasnap.Provider.TDataSetProvider

    https://docwiki.embarcadero.com/Libraries/Sydney/en/Datasnap.DBClient.TClientDataSet

    Thx, but TClientDataset seems more complex than my (not very cean) solution : a copy to FDMemeryTable, but it may be more efficient (perf and memory).


  4. On 11/13/2022 at 9:49 AM, haentschman said:

    Hi...:classic_cool:

     

    That's why the components are called "data sensitive". Without a direct connection to the database you have no data.... (unless there is something new :classic_tongue:)

    You have to come up with a separation of data and database.


    Variant 1:
    1. load data with query
    2. transfer the data into objects
    3. throw away query
    4. change data in object
    5. save object with SQL (create query, throw away query)
    ... with this variant one gets along also without data-sensitive components. You can then display an object in the grid as well as a property in the edit.

     

    Variant 2:

    Copy to another dataset:

    https://docwiki.embarcadero.com/Libraries/Sydney/en/FireDAC.Comp.DataSet.TFDDataSet.CopyDataSet

     

    Imho there are other variants....

     

    :classic_smile:

    Thx I yet use these 2 variants (more  or less) but I would find a simpler way as FDDataset have all the data in memory.


  5. I typically use TFDQuery connected to a database to use with a TDBGrid.
    Everything is OK but I would sometimes need to disconnect this TFDQuery while keeping the data in the TDBGrid, just for visualization, with, of course the loss of some functions related to the data update, but it does not pose any problem.
    It seems to me that it was possible with the old library 'ADODB' : http://etutorials.org/Programming/ma...ed+Recordsets/
    Unfortunately I haven't found how to do this with the Firedac components (apart from making a copy in a TFDMemTable but this is a bit cumbersome).
    Has anyone already implemented this principle?


  6. Hello

    I'm not sure I understand your problems.

    I have an application with params used in API & VCL interface, every param is declared in a Table (from Database or Inifile) and is used dynanically to construct the param VCL Form AND the API Swagger file. 

    For xyz param the table store its name (xyz) its label ("My parm xyz") its type (integer) and osme other informations (default value...)

    If in the interface  xyz is set to '1' the API (here a GET method)  become http://127.0.0.1/api/param?xyz=1& 


  7. 3 hours ago, Alexander Elagin said:

    A more or less easy solution would be to add the destructor call to the finalization section of Unit3:

    
    ....
    initialization
      tsTest := TStringList.Create; // or wherever it must be created
    finalization
      tsTest.Free
    end.

    And make sure that Unit3 is added to the project file before any form units:

    
    program Project1;
    
    uses
      VCL.Forms,
      Unit3 in 'Unit3.pas',
      Unit1 in 'Unit1.pas', {Form1}
    ....

    Not guaranteed but will probably work.

     

    Good idea, we can be sure that Unit3 initialization is used before other, but it is less clear for finalization.

     


  8. Hello, in a VCL project I need to run some code when closing the application, after destroying all forms.

    In the next sample I try to free a tstringlist but the line 'tsTest.Free;' is executed before the Tform onDestroy 

    program Project1;
    uses
      Vcl.Forms, System.Classes,
      Unit1 in 'Unit1.pas' {Form1},
      Unit2 in 'Unit2.pas' {Form2},
      Unit3 in 'Unit3.pas'; // global contains var : tsTest : TStringList;
    {$R *.res}
    begin
      tsTest := TStringList.Create;
      Application.Initialize;
      Application.MainFormOnTaskbar := True;
      Application.CreateForm(TForm1, Form1);
      Application.CreateForm(TForm2, Form2);
      Application.Run;
      tsTest.Free;
    end.

    It is just a simple example of my problem, any idea how to do it ?


  9. Hello

    As you need  dataset 'to save data to other kind of structure' paging is not a good idea, just try  FetchOptions.Mode := fmAll; and compare timings.

    Now it would be usefull to have more informations about your software : table size, Query size...   


  10. Hello

    I am porting a project to FMX (from VCL). I use a TSaveDialog with Filter for the file extensions :

     SaveDialog1.Filter := 'Acrobat file PDF|*.pdf|'+ 'Excel file(*.xls)|*.xls|';

    As the user has choice for some extensions, I use the 'OnTypeChange' event to know the chosen extension.

    But when I change the extension this event does'nt fire, but the 'OnShow' event fires ! 

    I tried TOpenDialog with the same problem.

    Some informations :

    Delphi Pro 10.3.1 (I tried Delphi 10.3.3)

    * Event 'OnFolderChange' does'nt fire.

    Any idea ? Is there any option I missed ? Or a known bug ?

    Thx

     

       


  11. On 3/9/2021 at 9:20 PM, Mike Torrettinni said:

    To avoid Delphi's string protection that can be slow when performance is needed, but string change is rarely actually changed. See more here: https://www.delphitools.info/2009/05/06/code-optimization-go-for-the-jugular/

     

    What Delphi version are you talking about, what faster function?

    As said to Fr0sT.Brutal it is not true with latest versions, I tried with 10.3.1 and the time is more or less the same ! 


  12. On 2/8/2021 at 2:24 PM, Mike Torrettinni said:

    Just a quick update on a progress of my code:

     

    If we use Pos before StringReplace, because actual string replacement is done rarely and not every time this method is called, we can squeeze a little more performance if we move StringReplace out of the current method:

    
    procedure DoStringReplace(var aStr: string; const aOldStr, aNewStr: string);
    begin
      aStr := StringReplace(aStr, aOldStr, aNewStr, [rfReplaceAll]);
    end;
    
    function PrepareStr(const aStr: string): string;
    begin
      Result := aStr;
      ...
      if Pos(cInvalidSubStr, Result) > 0 then    
        DoStringReplace(Result, cInvalidSubStr, '');
    end;

    In this case the slow safe string handling stuff is done in DoStringReplace method. 

    I guess this is the similar optimization trick that many use by moving rare error report message to another method, instead of using string concatenation in the method where error is raised.

     

    We just need to make sure we don't make DoStringReplace inlined, then all performance gain is lost. It took me a while to find that out 😉

     

     

    I really don't understant the interest of putting StringReplace out of the current method. Just note that there are a lot of StringReplace more efficient than the RTL one, and I think usi,g it  is the best way for better performances.

×