Jump to content

Uwe Raabe

Members
  • Content Count

    2538
  • Joined

  • Last visited

  • Days Won

    145

Posts posted by Uwe Raabe


  1. Or you try a total different approach described in this article: Dataset Enumerator Reloaded

     

    The old repository can be found on GitHub: https://github.com/UweRaabe/DataSetEnumerator, although the current development happens in https://github.com/UweRaabe/CmonLib

     

    Taking your code example from above:

    var
      LTotal: Double;
      LField1: TField;
      LField2: TField;
      LField3: TField;  
      LField4: TField;  
    begin
      LField1 := Query.FieldByName('FIELD1');
      LField2 := Query.FieldByName('FIELD1');
      LField3 := Query.FieldByName('FIELD1');
      LField4 := Query.FieldByName('FIELD1'); 
    
      Query.First;
      while not Query.Eof do
      begin
        LTotal := LTotal + LField1.AsFloat;
        // More stuff done with local field variables...
        Query.Next;
      end;

    a corresponding solution based on my unit could look like this:

    uses Cmon.DataSetHelper;
    
    type
      [DBFields(mapAuto)]  // make sure record fields are named similar to DB fields!
      TMyFields = record
        Field1: Double;
        Field2: Double;
        Field3: Double;
        Field4: Double;
      end;
    
    var
      LTotal: Double;
    begin
      LTotal := 0;
      for var rec in Query.Records<TMyFields> do begin
        LTotal := LTotal + rec.Field1;
        // More stuff done with rec
      end;

     


  2. 6 minutes ago, dummzeuch said:

    I my opinion Delphi 12 + Update 1 is a bit little more stable

    There is no Delphi 12 Update 1 (yet), only Delphi 12 with Patch 1.

     

    During times a common rule had established to wait for the first Update after an initial release before starting to use a Delphi version in production. That doesn't imply not to install and start using it - just not for production. JM2C

    • Like 2

  3. 1 hour ago, Lars Fosdal said:

    Fields[ix] := Query.FieldByName(Names[ix]);

    This will only change the TField array item, but not the local variable FieldX as expected.

     

     A const or var array of TField is no replacement for a couple of var par: TField parameters. As soon as you construct that array parameter, the addresses of the local variables are gone, while their current content (which may be undefined here) is copied to the array item.

     

    Perhaps this may be a better approach (didn't try as I am too lazy to create a fake dataset with these fields):

    procedure ConnectFields(Query: TDataSet; const Fields: TArray<^TField>; const Names: TArray<string>);
    begin
      Assert(Length(Fields) = Length(Names), 'Number of fields and number of names must match');
      for var ix := 0 to Length(Fields) - 1
      do begin
        Fields[ix]^ := Query.FindField(Names[ix]);
        if not Assigned(Fields[ix]^) then
          raise Exception.Create(Format('Field %s not found.', [Names[ix]]));
      end;
    end;
    
    procedure Test;
    var
      Field1, Field2, Field3, Field4: TField;
    begin
      ConnectFields(Query,
       [ @Field1,   @Field2,   @Field3,   @Field4],
       ['Field1', 'Field2', 'Field3', 'Field4']);
       ...
    end;

     

    • Like 1
    • Thanks 2

  4. This is indeed very instable. One would need to extend the current internals significantly to make this work. Nevertheless one can achieve some results by setting AcceptExpressions to True and override these two methods:

    type
      TNumberBox = class(Vcl.NumberBox.TNumberBox)
      protected
        function GetValidCharSet(AAcceptExpressions: Boolean): TSysCharSet; override;
        function IsNumericText(const AText: string): Boolean; overload; override;
      end;
    
    function TNumberBox.GetValidCharSet(AAcceptExpressions: Boolean): TSysCharSet;
    begin
      Result := inherited GetValidCharSet(AAcceptExpressions);
      if Mode = nbmFloat then
        Result := Result + ['e', 'E', '+', '-'];
    end;
    
    function TNumberBox.IsNumericText(const AText: string): Boolean;
    begin
      Result := inherited;
      if AText.LastIndexOfAny(['e', 'E']) = AText.Length - 1 then
        Result := False;
    end;

     

    • Like 1

  5. SetThreadDpiAwarenessContext has to be wrapped around the creation of a top level window handle to work correctly. All child windows then inherit the context of the top level one. This rules out any docked forms or frames, which explains why it is not feasible for the Embedded Designer. (Fun fact: an undocked designer window would have worked with that.)

     

    A solution for this problem could be SetThreadDpiHostingBehavior and AFAIK that is something Embarcadero is investigating in.

×