Jump to content

Magno

Members
  • Content Count

    62
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by Magno


  1. I read almost every topic of the internet about this, but no clue and actually I have 2 issues... My Android app, Delphi CE, needs to save a file into the shared folder and it works fine (using TPath.GetSharedDocumentsPath), but I need to eventually share it and here I have the issues, first my app can't touch that file for sharing, but I can read and write it perfectly. The error is that known " android.os.FileUriExposedException: file:///storage/emulated/0/Documents/myfile.txt exposed beyond app through ClipData.Item.getUri()".

     

    Ok, so I thought that my app can read the file I could clone a copy into the "sandbox" (TPath.GetDocumentsPath) and try to share and this is my second issue, because it seems to save the copy there but when I try to check the folder in phone the path .../files is empty. My Android is running the version 11 and SDK 26.

     

    The sharing function I am using can be the issue, of course:

    procedure ShareFile(FileName: string);
       Intent: JIntent;
       fileuri: JParcelable;
       Uri, Data: Jnet_Uri;
    begin
       Intent := TJIntent.Create;
       Intent.setAction(TJIntent.JavaClass.ACTION_SEND);
       Intent.addFlags(TJIntent.JavaClass.FLAG_GRANT_READ_URI_PERMISSION);
       Data := TJnet_Uri.JavaClass.parse(StringToJString(FileName));
       Intent.setType(StringToJString('vnd.android.cursor.dir/*'));
       fileuri := JParcelable(TJnet_Uri.JavaClass.fromFile(TJFile.JavaClass.init(StringToJString(FileName))));
       Intent.putExtra(TJIntent.JavaClass.EXTRA_STREAM, fileuri);
       TAndroidHelper.Activity.startActivity(Intent);
    end;

    I am not even sure if the vnd is correct. If someone could help I would be very glad.

     


  2. On 1/12/2021 at 11:14 PM, emailx45 said:

    review your THREAD use, maybe is there where the problem is in! look my sample about TTask RUN

    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      // Label1 is in Panel1
      if not(Label1.Parent = nil) then
      begin
        Caption := Label1.Parent.ToString; // TPanel
        //
        Label1.Parent.Repaint; // call Invalidate and Update to repaint the control
        //
        // procedure TWinControl.Invalidate; // Vcl.Controls.pas
        // Perform(CM_INVALIDATE, 0, 0);     // Vcl.Controls.pas
        // function TControl.Perform(Msg: Cardinal; WParam: WPARAM; LParam: LPARAM): LRESULT;   // Vcl.Controls.pas
        // ------
        // procedure TWinControl.Update;      // Vcl.Controls.pas
        // function UpdateWindow; external user32 name 'UpdateWindow'; // WinApi.Windows.pas
      end;
    end;

    I just saw the thread, that's a nice code, you're using TProc, I never thought about that, well I will study it and so far thank you.

     


  3. 2 hours ago, Rollo62 said:
    
    procedure Tform.OnGeocodeReverseEvent(const Address: TCivicAddress);
    begin
    end;

    You should consider that this event is triggered by separate hardware, and it may or may not occur in the mai UI thread.

    I would decouple the results, and use TThread.ForceQueue to ensure that main UI is vaild.

    Gonna give a try on that! Thanks so far


  4. Well, I have a panel with 3 labels. My app will geocode reverse (TMaps) some information and I simply need to make it happen (show the address info) after the decoding. Example:
     

    procedure Tform.OnGeocodeReverseEvent(const Address: TCivicAddress);
    begin
      // these labels are into a Panel
      labe1.Text := Address.Thoroughfare;
      labe2.Text := Address.Locality;
      labe3.Text := Address.CountryName;
    end;

    I've tried to force refresh:  Panel1.InvalidateRect(RectF(0, 0, Panel1.Width, Panel1.Height));

     

    Also tried create a new "refreshable" panel based on a Stackoverflow example I saw, using SubscribeToMessage().

     

    As expected the geo reverse occurs into a thread (TTask) and after I read the info I need to call the GeocodeReverse()

     

    That geoData var bellow simply record that carries some information I will need later, but basically what I need to send to my geoDecode function is just the position (lat/lon), as simplified code:

    procedure TForm.UpdateInfo();
    begin
      TTask.Run(
      procedure
      begin
         try
            GetGeoData();
         finally
            TThread.Synchronize(nil,
            procedure
            begin
               UpdateMap(geoData);
               geoDecode(geoData.Position);
             end);
         end;
      end);
    end;
    
    procedure TForm.geoDecode(Position: TMapCoordinate);
    var
       NewLocation: TLocationCoord2D;
    begin
    
       try
          // Setup an instance of TGeocoder
          if not Assigned(FGeocoder) then
          begin
             // ShowMessage('FGeocoder');
             if Assigned(TGeocoder.Current) then
                FGeocoder := TGeocoder.Current.Create;
             if Assigned(FGeocoder) then
                FGeocoder.OnGeocodeReverse := OnGeocodeReverseEvent;
          end;
    
          // Translate location to address
          if Assigned(FGeocoder) and not FGeocoder.Geocoding then
          begin
             // ShowMessage('NewLocation');
             NewLocation.Latitude := Position.Latitude;
             NewLocation.Longitude := Position.Longitude;
             FGeocoder.GeocodeReverse(NewLocation);
          end
       except
          ShowMessage('Erro ao acessar serviço de geocoder');
       end;
    
    end;

    So, after all the OnGeocodeReverse is triggered nicely but the labels themselves will only update if I, e.g. change to another tab, open close the multiviewer, something that force the redraw of the panel.

     

     


  5. My aab file is getting rejected because of that message in the title, the full Google message is:

     

    Quote

     

    "This release is not compliant with the Google Play 64-bit requirement.
    The following APKs or App Bundles are available to 64-bit devices, but they only have 32-bit native code: [4]
    Include 64-bit and 32-bit native code in your app. Use the Android App Bundle publishing format to automatically ensure that each device architecture receives only the native code it needs. This avoids increasing the overall size of your app."


     

    I have compiled, checked everything. Should any obligatory lib be always present? I ask because some of them where removed as they are not really needed. If I open the AAB file I see the 64 and 32 bit file version there.

     

    What more should I verify?

     


  6. I have such class:

    type
       TmyNetHTTPClient = class(TNetHTTPClient)
       private
          FileName: String;
          Index: Integer;
          Downloaded: Boolean;
          FileStream: TFileStream;
       public
          procedure ReceiveData(const Sender: TObject; AContentLength, AReadCount: Int64; var Abort: Boolean);
          procedure RequestCompleted(const Sender: TObject; const AResponse: IHTTPResponse);
       end;

    Now I create my object and have some similar:
     

    // consider filestream already created and other needs for the sake of this example
    begin
      myNetHTTPClient := TmyNetHTTPClient.Create(self);
      myNetHTTPClient.Get('http://localhost/file.txt', FileStream);
      //myNetHTTPClient.onReceiveData; // error, so commented
    end;

     

    Now, what is I am doing wrong here? The ReceiveData(), and also RequestCompleted() are never triggered 😕

     

    procedure TDownloader.ReceiveData(const Sender: TObject; AContentLength, AReadCount: Int64; var Abort: Boolean);
    begin
       doSomething();
    end;
    

    What should I do to make it work?

     

     

     

     


  7. Thank you guys for all these information! Very useful and one who need can dig on this to make it work for he needs. Remy I will check the Indy approach.

    My awesome component needs no more than a label informing the version or a ShowMessage() kind of dialog. Thanks again!


  8. 26 minutes ago, Anders Melander said:

    Okay. What you need is a component editor. With this you can specify what happens when the user double clicks your component (at design time) and you can add menu items to the context menu. For example a "About My Awesome Component..." menu item.

    The help is a bit sparse on how to implement a component editor for VCL (there's a good example for FireMonkey though) but there's plenty of examples available on the net: https://www.google.com/search?q=delphi+component+editor

    There might also be an example installed with Delphi.

    Thank you!! This is the path I needed.

     


  9. 1 hour ago, Anders Melander said:

    I think you need to explain a little bit better what you are trying to do.

    Start with an example of how you would like to use your component. Once we understand that we can better help you with how to implement it.

    I want that one of the Published properties show an About, with that I can show the user the component version once it get installed in the Delphi IDE.

     

    uses uAbout;

    type
       TMyComponent = class(TComponent)
       private
          { Private declarations }
          fsAbout: TAbout;

          FUser: String;
       protected
          { Protected declarations }
       public
          { Public declarations }
       published
          { Published declarations }
          property About: TAbout Read fsAbout Write fsAbout Stored False;

          property User: String read FUser write FUser;
       end;

     

    I am stuck here. The TAbout is an external unit, like I show in the OP. So, when installed the User property shows on the IDE and the About, but I don't even know what technique to make it show a dialog or become a read only text.

     

    Thanks for the reply!

     

     


  10. I never had the real need for this but now I faced I really dunno how, making components are not my real business so here is my doubt, if one would like to help.

    Well, I have an unit (about.pas) that my compo will use, but this is everything I could do. I have no clue how do go forward.

     

       TAbout = Class(TComponent)
       Private
          fsAbout: TAbout;
       Public
          Procedure AboutDialog; //really? I dunno
       Published
          Property About: TAbout Read fsAbout Write fsAbout Stored False;
       End;

     

    procedure TAbout.AboutDialog;
    begin
       ShowMessage('Made by me =)');
    end;

    -----

    Now, my component has such:

     

       private
          { Private declarations }
          fsAbout: TAbout;

    ...

       published
          { Published declarations }
          property About: TAbout Read fsAbout Write fsAbout Stored False;

    end;

     

    And from here I don't know what to do. I would be happy with a read only label on my component too.

     

    Thank you for any help! 😃


  11. On 6/15/2020 at 2:12 PM, Kas Ob. said:

    OK , you lost me here as i don't understand to what FMX change you are referring to, and i think you didn't understand what was the suggestion to try.

     

    to try :

    Don't change anything except than the declaration of DrawArcAA , make it like this

    
    procedure TframeGauge.DrawArcAA(const AParams: TAAArcSettings);

    3) const 

    
    begin
      Params.AStart := 5;
      DrawArcAA(Params);
    end;
    
    procedure TTframeGauge.DrawArcAA(const AParams: TAAArcSettings);
    ..
    begin
      ..
      AParams.AStart := 6;          // error ! will not compile as the AParams will considered and handled as constant by the compiler 
      ..
    end;

    Your are better with const in that function because you are not changing any of its fields, consts and var are slightly faster than the default ( without const or var ) 

    Yes, I understand that. Well, using const did not solved. 

     

    Well, as I said, with Windows it works correctly. With Android once I draw it will replicate the value to any other gauge there. I think it somehow related to the painting method, I really dunno yet.

     


  12. 23 hours ago, Kas Ob. said:

    I think Mahdi here was asking about if you are sure in passing AParams by value, meaning AParams is been copied every time to the stack before been passed to DrawArcAA, there is no point in that function to be used like that, also this is slow and may be somehow causing the problem, try changing the DrawArcAA declaration to :

    
    procedure TframeGauge.DrawArcAA(const AParams: TAAArcSettings);
    //  or 
    procedure TframeGauge.DrawArcAA(var AParams: TAAArcSettings);

     

    There was no change on FMX. Maybe if I move to object component I could have more success but for this project I dunno...


  13. 1 hour ago, Mahdi Safsafi said:

    I'm not very well experienced on FM, but possibly you're passing settings by value ! those could be a very hard source of bug to detect !

    
    procedure TframeGauge.DrawArcAA(AParams: TAAArcSettings);

     

    I will try move it, thanks but as they are different frames so one should not touch the other...


  14. 6 hours ago, Kas Ob. said:

    Sorry, i don't have an answer to your problem, but i can't help myself with commenting on that screenshot, that is beautiful !

     

    Is it your doing ?

    If yes then "excellent work mate!"

    Yes it is, thank you. I thinking to release it all source code later. The idea behind is simple and it is a quarantine project: I was thinking to monitor some of my computer sensors using WMI queries, but quickly I realise the information about GPU is device dependent on drivers and the time I would expend to accomplish won't be wort. I found a software called Open Hardware Monitor (https://github.com/openhardwaremonitor/openhardwaremonitor) that you can keep it running in background and expands the WMI. Now I have a server that read temps and loads so I can choose what I want to monitor. My computer case has a glass so I could put an old tablet or phone there inside 😄 

     

    Here's more decent screenshot of both client and server (still a WIP).

     

    Screenshot.jpg

    • Like 1

  15. What I have: a frame with a semi-arc that represents a gauge for information like temperature. See the attached image. Each of these controls are into a frame which I create in runtime depending from what I receive from my server. 

    The structure is: TFrame->TRectangle->TPaintBox. 

    The issue: when I run with Windows the arcs are correctly drawn, I sent the Value so it draws fine the correct gauge. When I run with Android, using the example attached with 3 gauges, all the 3 gauges will get redraw with the same value, even I am pointing to only one. 

    I am using a code I found a modified later, but most of it is close to the original, it will use anti-aliasing to draw the arc, the code is bellow:

    type
       TAAArcSettings = record
          AStart, AEnd, Opacity: single;
          AThickStart, AThinkEnd: integer;
          Color: TAlphaColor;
       end;
    
    procedure TframeGauge.DrawArcAA(AParams: TAAArcSettings);
    var
       path: TPathData;
       poly: TPolygon;
    begin
    
       path := TPathData.Create;
       path.AddArc(rect.CenterPoint, TPointF.Create(rw, rh), AParams.AStart, AParams.AEnd);
       path.AddArc(rect.CenterPoint(), TPointF.Create(rw - AParams.AThickStart, rh - AParams.AThinkEnd), AParams.AStart + AParams.AEnd,
         -AParams.AEnd);
       path.ClosePath();
       path.FlattenToPolygon(poly);
    
       APaintBox.Canvas.Fill.DefaultColor := TAlphaColorRec.Blue;
       APaintBox.Canvas.Stroke.Kind := TBrushKind.Solid;
       APaintBox.Canvas.Fill.Color := AParams.Color;
       APaintBox.Canvas.FillPolygon(poly, AParams.Opacity);
    
       path.DisposeOf;
    
    end;

     

    I make some calculations to define the initial and final angle plus the percent for the value representation. To intent set a value the code below is used:

     

       ArcSetting.AEnd := AEndAngle;
       ArcSetting.AStart := START_ANGLE;
       Rectangle1.BeginUpdate;
       APaintBox.Canvas.BeginScene;
       APaintBox.Repaint; // this will trigger the PaintBoxPaint() method and there inside I can the DrawArcAAA()
       APaintBox.Canvas.EndScene; 
       Rectangle1.EndUpdate;


    There is a procedure TframeGauge.setGaugeValue(Value: integer) which will make the code above. In the main form it detects the frame and will call this procedure, but as I say all of any gauges will be drawn with the new value. This won't happen with Windows (both 32 and 64 bit).

     

    Maybe FMX for Android it is required something else beyond I know 😞

     

    Thanks for reading and any clue where I could search for?

     

    Anotação 2020-06-13 230221.jpg

    • Like 1

  16. On 4/24/2020 at 7:03 PM, aehimself said:

    And this is something I will never EVER argue about. For me it also makes the code harder to read, as I already got used to Create - Try - Finally - Free - End. I'll always be alarmed if this pattern is not followed. In my case unfortunately it's a bit different, as we have (I'd call them as) protocol descriptors in our custom dataset descendants, no direct SQL queries.

     

    But I hate setting the variables to nil before.

    Yep, but I think the helper with setting nil before is not so handy, but it is ok. This is the way, as I have spoken.


  17. On 4/23/2020 at 9:40 AM, Gustav Schubert said:

    MyQuery should be initialized to nil.

     

    I thought that Delphi could initialize it by default, like strings are null, integers are 0 and so on. Thank you

    
    //procedure createMyQuery(query: TFDQuery; const Sql: String='');
    procedure createMyQuery(var query: TFDQuery; const Sql: String='');
    begin
      if query = nil then
        query := TFDQuery.Create(nil);
      query.Connection := myDatabase;
      query.SQL.Text := Sql;
    end;
    
    var
      myQuery: TFDQuery;
    
    begin
      myQuery := nil;
      createMyQuery(myQuery,'select * from table');
    
    end;

     

     


  18. The code bellow uses FireDac to create a new query object. The if not Assigned() sometimes will bring garbage and make the routine fail because as it reads something, so the "query" won't be created and crashes.

     

    procedure createMyQuery(var query: TFDQuery; Sql: String='');
    begin
      if not Assigned(query) then // fail
         query := TFDQuery.Create(nil);
      query.Connection := myDatabase;
      query.SQL.Text := Sql;
    end;

     

    var

       myQuery: TFDQuery;

    begin

        createMyQuery(myQuery,'select * from table');

       ...

    end;

     

    Anything I could make it ? The Delphi version is 10.2 update 3.

     


  19. I tried a simple new project, drop the required, following this example: http://docwiki.embarcadero.com/RADStudio/Rio/en/Tutorial:_Using_a_REST_DataSnap_Server_with_an_Application_and_FireDAC (same above)

     

    So I get an error (as the title of this thread suggests) when running the following method: 

    function TServerMethods1.GetDepartmentNames: TFDJSONDataSets;
    begin
      // Clear active so that query will reexecute.
      FDQueryDepartmentNames.Active := False;
      Result := TFDJSONDataSets.Create;
      // The "TFDJSONDataSetsWriter" class provides static "ListAdd" method.
      // It uses reflection to convert results of the query into "TFDJSONDataSets".
      TFDJSONDataSetsWriter.ListAdd(Result, FDQueryDepartmentNames);
    end;

     The unique difference is that the FDQueryDepartmentNames has another name and points to a similar very simple table with a "select * from users".

     

×