Jump to content

Keesver

Members
  • Content Count

    89
  • Joined

  • Last visited

  • Days Won

    2

Posts posted by Keesver


  1. As a last resort you can define your own TDataset type with a public 'FDatasource' member and then cast the TDataset to this type. Design wise this is a clear 'hack' but it will do the job: 

     

    unit Unit1;
    
    interface
    
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, Datasnap.DBClient,
      Vcl.StdCtrls, System.Generics.Collections;
    
    type
      TForm1 = class(TForm)
        ClientDataSet1: TClientDataSet;
        Button1: TButton;
        DataSource1: TDataSource;
        DataSource2: TDataSource;
        procedure Button1Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;
    
      THackedDataSet = class(TComponent)
      public
        FFields: TFields;
        FAggFields: TFields;
        FFieldDefs: TFieldDefs;
        FFieldDefList: TFieldDefList;
        FFieldList: TFieldList;
        FDataSources: TList<TDataSource>;
      end;
    
      PHackedDataSet = ^THackedDataSet;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      var ds := PHackedDataSet(@ClientDataSet1)^;
    
      ShowMessage(ds.Name);
    
      for var src in ds.FDataSources do
        ShowMessage(src.Name);
    end;
    
    end.

     


  2. For the diagrams: take a look at Graphviz. This is an open source project with a lot of traction. It works like an engine, you pass your data to the 'engine' and get a description of the diagram in return. The 'description' can be an SVG document that you can display using a browser or it can be a json document that you parse in your code and paint onto a canvas. The engine can be a dll, executable or external service. Graphiz can handle a many different diagrams.


  3. Please check out a-dato/FMX-GRID:

     

    image.thumb.png.3c9a869f36a1b13b8eb5328c652e1209.png

     

    This library includes visual grid control, data models, binding system. Data models are extendible at runtime so that users can add/remove properties from objects.

    I can share a link to our demo application so that you can test it yourself.

     

     

    • Like 1

  4. Hello,

    I learned something new as I didn't know such types do not have RTTI. Any property of such type is hidden when you try to get the properties from a object. This makes it impossible to do automatic marshaling.

     

    Delphi does support custom marshalling using TJSONMarshal (Serializing User Objects - RAD Studio (embarcadero.com)) that allows registration of marshaling functions: procedure RegisterConverter(clazz: TClass; const func: TTypeObjectConverter);

     

    Another option would be to add attributes to your classes to identify these properties and then write your own marshaller that looks at these attributes:

     

    Something like this should work:

      TEnum1 = (Value1=20, Value2=40);
    
      TEnum1Helper = record helper for TEnum1
        function ToString() : string;
      end;
    
      [TJsonEnumproperty('En', UnmarshalFunc, MarshalFunc)]
      TObjectWithhEnum = class
      private
        _id: Integer;
        _en: TEnum1;
    
      published
        property ID: Integer read _id write _id;
        property En: TEnum1 read _en write _en;
      end;

    Your marshal method then looks at the attributes defined for the class and then call the MarshalFunc/UnmarshalFunc.

     

    Alternatively you can use interfaces to achieve the same. 

      ICustomMarshalling = interface
        ['{E799D069-66B8-464D-B718-78D5D4DB6747}']
        procedure Marshal(M: TJsonMarshal);
        procedure UnMarshal(M: TJsonUnMarshal);
      end;
    
      TObjectWithhEnum = class(TObject, ICustomMarshalling)
      private
        _id: Integer;
        _en: TEnum1;
    
      proteced
        procedure Marshal(M: TJsonMarshal);
        procedure UnMarshal(M: TJsonUnMarshal);
    
      published
        property ID: Integer read _id write _id;
        property En: TEnum1 read _en write _en;
      end;

    In this scenario your custom marshaller checks if your class implements the ICustomMarshalling interface and calls the appropriate methods.

     

    Like to see what solution you come up with...

     

     


  5. You can encode the image using Base64 encoding. ChatGPT came up with this sample code. Calling TNetEncoding.Base64.EncodeBytesToString(Bytes) will do the actual conversion:

     

    uses
      System.JSON, System.SysUtils, System.Classes, System.NetEncoding;
    
    function ImageToBase64(const FilePath: string): string;
    var
      FileStream: TFileStream;
      Bytes: TBytes;
    begin
      FileStream := TFileStream.Create(FilePath, fmOpenRead);
      try
        SetLength(Bytes, FileStream.Size);
        FileStream.ReadBuffer(Pointer(Bytes)^, FileStream.Size);
        Result := TNetEncoding.Base64.EncodeBytesToString(Bytes);
      finally
        FileStream.Free;
      end;
    end;
    
    procedure SaveImageBase64ToJson;
    var
      JSONObject: TJSONObject;
      Base64String: string;
      JSONString: string;
      JSONFile: TStringList;
    begin
      Base64String := ImageToBase64('path/to/image.jpg');
    
      JSONObject := TJSONObject.Create;
      try
        JSONObject.AddPair('name', 'Example Image');
        JSONObject.AddPair('image_data', 'data:image/jpeg;base64,' + Base64String);
        
        JSONString := JSONObject.ToString;
        
        JSONFile := TStringList.Create;
        try
          JSONFile.Text := JSONString;
          JSONFile.SaveToFile('image_base64.json');
        finally
          JSONFile.Free;
        end;
      finally
        JSONObject.Free;
      end;
    end;

     

    • Like 1

  6. This problem has more side effects than expected, after moving a form to a screen with different DPI, the whole form will be re-styled every time a drop down is opened. We filled a report for it:

    https://embt.atlassian.net/servicedesk/customer/portal/1/RSS-824?sda_source=notification-email

     

    Workaround, copy file FMX.Platform.Win to your project then update this method:

     

    function TWinWindowHandle.GetScale: Single;
    begin
      if not SameValue(FForcedScale, 0, TEpsilon.Scale) then
        Result := FForcedScale
      else if not SameValue(FCurrentScale, 0, TEpsilon.Scale) then
        Result := FCurrentScale
    
      // Add these lines, this will force the scale of the popup control to be the same as the scale of the parent
      else if (Form <> nil) and (Form.FormStyle = TFormStyle.Popup) and (Form.ParentForm <> nil) then
        Result := Form.ParentForm.Handle.Scale
      else
        Result := GetWndScale(FWnd);
    
      FCurrentScale := Result;
    end;

     


  7. Hello,

     

    I'm using class TLocalReceiver from a Kastri sample application. When I create a new instance from this class I run into an exception:

     

    Project BroadCast.apk raised exception class EJNIFatal with message 'Java type com/delphiworlds/kastri/DWMultiBroadcastReceiverDelegate could not be found'.

    In the source code I find this:

     [JavaSignature('com/delphiworlds/kastri/DWMultiBroadcastReceiverDelegate')]
      JDWMultiBroadcastReceiverDelegate = interface(IJavaInstance)
        ['{1AD78992-D81F-48A4-B341-F82B43094B67}']
        procedure onReceive(context: JContext; intent: JIntent); cdecl;
      end;

    which tells me the type should have been be registered (I have this file included in the uses of my test application).

    What am I missing here, do I have to add code to my application to register this class?


  8. Hello,

     

    I'm trying to get the Foreground service demo application to work in Delphi 12. Therefore I copied the files to a new project, checked the manifest files and I got everything set as it should. However when I start the service, an exception is raised inside the service create method:

     

    constructor TServiceModule.Create(AOwner: TComponent);
    begin
      inherited;
      TOSLog.d('TServiceModule.Create - 1');
      FLocalReceiver := TLocalReceiver.Create(Self);  <-- java.lang.IllegalArgumentException: Receiver not registered: null
      TOSLog.d('TServiceModule.Create - 2');
      FService := TJService.Wrap(System.JavaContext);
      TOSLog.d('TServiceModule.Create - 3');
      CreateNotificationChannel;
      TOSLog.d('TServiceModule.Create - 4');
    end;

    I think I'm missing something, what should be done to 'Register' a receiver?

     

    Thanks


  9. ## Free version

    A free version is available which is actually quite capable. The free version is named FMX-GRID. This version can be used by any number of developers and offers royalty free distribution of applications.

    The free version is published under the MIT license

    ## Commercial version
    FMX-GRID-MODEL is a commercial product. It adds model support and property binding for easy creation of user interfaces. A license is required per developer. Licenses are valid for 12 months, a subscription is required to keep licenses valid. Subscriptons must be renewed after the end date. If you are renewing your license before (or up to 30 days after) the current expiration date, the new expiration date will be calculated based on the original order date. Updates are only available to users with a valid license.
     


  10. We are in a similar situation and support a desktop, mobile, web and MacOs application from a single code base. We use a grid control written by our company which is also publicly available at Git-hub (GitHub - a-dato/FMX-GRID). This is more than just a grid control, as it supports light weight data binding and custom collections, sorting and more. You are welcome to check it out.


  11. Delphi 12 Version 29.0.50491.5718:

    I just did a small test on a fast MSSql server with a similar query on a very large table and I do not see such a delay. The data is shown quickly. I'm just using FDConnection and FDQuery. Probably your setup is different or your table contains some (big) blob's that are fetched?

     

    Also tried ADOConnection/ADOQuery, this was actually a little bit faster.

     

    Please provide a sample.

     

    image.thumb.png.8ba67f5280d26ada64defa6bf98fee2a.png


  12. Hello all,

     

    We are pleased to anounce the availability of a new Delphi grid control specifically designed for FMX. This control runs on all platforms, is easy on the memory, updatess fast and has smooth scrolling. There is a free version available that includes the following features:

    • Connects to different data sources (Lists, List<T>, TDataset)
    • Smart row caching results in low memory usage
    • Fast scrolling
    • Hierarchical views
    • Extendable property model based on .Net type system (object properties can be modified at runtime)
    • Development backed up by a professional team of FMX developers
    • Components used in professional software (Lynx/Lynx-x) by a large user community

     

    We also provide a commercial version, this version adds model support and property binding to visual controls. You can easily bind properties to editors for advanced two way syncing.

    Please go to https://github.com/a-dato/FMX-GRID.git to download the free version.

     

    Community site: https://community.a-dato.com

    • Like 5
    • Thanks 2

  13. ApplyStyleLookup should be called only once when a control is about to be painted. However, when a TDateEdit control is put on a form and the application is moved to a second monitor with a different DPI, ApplyStyleLookup is called every time the drop down of the date editor is opened. The same happens with a TComboBox control. See test application.

     

    We will create a bug report for this at Embarcadero, but maybe someone knows a fix or workaround?

     

    Thanks

    ApplyStyleLookup.zip


  14. procedure TFMXPrintForm.btnMakePDFClick(Sender: TObject);
    var
      r: TRect;
      LCanvas: ISkCanvas;
      LDocument: ISkDocument;
      LDocumentStream: TStream;
      LSVGDOM: ISkSVGDOM;
      LSize: TSizeF;
    
    begin
      LSVGDOM := TSkSVGDOM.MakeFromFile('Delphi.svg');
      LSize := TSizeF.Create(300, 300);
      r.Left := 0;
      r.Top := 0;
      r.Width := Round(treeControl.Width);
      r.Height := Round(treeControl.Height);
      LSVGDOM.SetContainerSize(LSize);
    
      LDocumentStream := TFileStream.Create('Delphi.pdf', fmCreate);
      try
        LDocument := TSkDocument.MakePDF(LDocumentStream);
        try
          LCanvas := LDocument.BeginPage(r.Width, r.Height);
          try
            LSVGDOM.Render(LCanvas);
          finally
            LDocument.EndPage;
          end;
        finally
          LDocument.Close;
        end;
      finally
        LDocumentStream.Free;
      end;
    end;

    Also see: Using Skia's PDF Backend | Skia

×