Jump to content

Serge_G

Members
  • Content Count

    333
  • Joined

  • Last visited

  • Days Won

    1

Posts posted by Serge_G


  1. On 4/8/2020 at 8:34 PM, bazzer747 said:

    So a 'close' on the query does what exactly (in terms of any SQL code in the query)?

    A close no, but an unprepare should be to check. If your first SQL works, other request just changing parameter works. i.e dm.fdq.Open('',[ 2 ] );

    It's when you change the SQL and parameters the problem.

     


  2. 19 hours ago, Tntman said:

     Short answer is that I am afraid to code that by myself because I am scared of making it crappy and inefficient but I guess it is the learning curve ... 

    Well don't be so afraid. I think you can use a TFrame (somewhere TFrame is like a style) for all that filling stuff. I think it was the Paul Toth approach. 

    • Like 1

  3. Hello,

     

    This was a question I had in mind for a long time. I used to use, like ergeka

    and, even, closing the query before (old BDE comportment)
     

    dm.fdc.Close;
    
    dm.fdc.parambyname('Pc').asString:='Woolworths';
    
    dm.fdc.Open;
    

     

    So, today, I make a little test and :classic_huh: Firedac is really an amazing thing

     

    dm.fdc.Open,('',[ 'Woolworths' ]);

    works. One only line versus 2 (three in my case) and shorter than this ParambyName stuff. 

    I certainly use this for now 😉 

    By the way I test also this query

    Select * from tTable  where Company = ? order by oOrderName 

    a no named parameter. It works too 👍


  4. Hi,

    You are not alone 😉 even if BDE is largely obsolete I still have some fights with it.

    My suggestions to use it in a MS UAC environment (from Vista and more) :

    Don't use "program files" folders, install it in a root base directory (i.e. c:\borland\BDE)

    After install change some options  :

        NET DIR directory  (configuration/native/Paradox

        SHAREMEMxx values (configuration/system/init)  (check this document for values)

    Last, don't forget to put Object/Options/ save for use  with windows 3.1 and windows 95/NT << yes this can be a bit strange and prove obsolescence, as far as I understand this indicates BDE to find IDAPI32.cfg file and not in registry ,

    as you certainly knows registry, UAC and users are not very friendly :classic_laugh:

     

    Installing BDE ? I use a setup I found  with one of my older Delphi version (D2010 I think), but some installers (don't know if it's legal) can be found on the web i.e  here or there

    be aware that BDE installer from Code Central need IDE  to be installed on the PC

    I use version 5.0.1, note : last version was 5.2 I think

     

    15 hours ago, Antony Danby said:

    Oh, I think you are right about FireDAC, but the customer is a bit adverse to it at the moment and wants to spread the "risk" out a bit and I can't blame them to be honest.

    I can't understand this, Firedac is much more than BDE ! Ok, if they still use paradox, db tables but wow ...

    • Like 1

  5. 20 hours ago, Vandrovnik said:

    Thank you for helping me to get the right way!

    A pleasure 😉 .

    But this still does not satisfy me fully, so I persist.

    My goal was to have the members linked even if no columns were defined, I found a way applying the principle : "if no columns are defined then all fields of the datasource are displayed".

    Having the linked datasource is easy TLinkGridToDatasource(B).DataSource, having the member list not so but I found that TBaseObjectBindSource have an interface IScopeMemberNames

    private
    
      ColumnList : TStringList;
    
    
    procedure TForm1.Button1Click(Sender: TObject);
    var B : TContainedBindComponent;
        SL : TStringList;
        S : String;
        IMembers : IScopeMemberNames;
        ib : integer;
    begin
      for ib:=0 to BindingsList1.BindCompCount-1 do
      begin
       B:=BindingsList1.BindComps[ib];
       if (B.ControlComponent is TCustomGrid) then
       begin
          if TBaseObjectBindSource(TLinkGridToDatasource(B).DataSource).GetInterface(IScopeMemberNames,IMembers)
          then begin
          IMembers.GetMemberNames(ColumnList);
          for S in ColumnList do
           Memo1.Lines.Add(S);
          end;
       end;
    
      end;
    end;

    Now it's just a question of using a StringList to store the fieldnames :classic_happy: and to arrange it  function of the grid (defined columns, and move), more "classic code" I think even if, at this time, I have no idea (Sunday not propitious to :classic_laugh:)  

     

    P.S.

    Quote

    But does not keep column width, when user changes the width in runtime

    The only way I think about is to have a sort of SaveGridSettings / LoadGridSettings procedure

    something using ObjectBinaryToText  and reverse

    function SaveGridSettings(Component: TComponent): string;
    var
      BinStream:TMemoryStream;
      StrStream: TStringStream;
      s: string;
    begin
      BinStream := TMemoryStream.Create;
      try
        StrStream := TStringStream.Create(s);
        try
          BinStream.WriteComponent(Component);
          BinStream.Seek(0, soFromBeginning);
          ObjectBinaryToText(BinStream, StrStream);
          StrStream.Seek(0, soFromBeginning);
          Result:= StrStream.DataString;
        finally
          StrStream.Free;
        end;
      finally
        BinStream.Free
      end;
    end;

     

     

     

     


  6. Agree with NIRAV KAKU in the principle but anyway if you want to access LiveBinded fieldname of a column, fieldname is the wrong name you have to search a membername.

     

    My test in ideal conditions (only one StringGrid, only Stringgrid is Binded)  

     

    Consider this code, list of all columns linked

    procedure TForm1.Button1Click(Sender: TObject);
    var B : TContainedBindComponent;
        C : TLinkGridToDataSourceColumns;
        ib,ic : integer;
    begin
      // have to search in the whole bindingslist
      for ib:=0 to BindingsList1.BindCompCount-1 do
      begin
       B:=BindingsList1.BindComps[ib];
       // check if the component is the stringgrid  
       if (B.ControlComponent=StringGrid1) then     
       begin
         // look for all linked columns
         for ic := 0 to TLinkGridToDatasource(B).Columns.Count-1 do
          begin
           C :=TLinkGridToDataSourceColumns(TLinkGridToDatasource(B).Columns);
           Memo1.lines.add(c[ic].MemberName);
          end;
       end;
      end;
    end;

    From this  you can write a function, something like function FieldNameOfGrid(const Grid : TCustomGrid; col : integer) : String

    function TForm100.FieldNameOfGridCol(const Grid: TcustomGrid;
      const col: Integer): String;
    var B : TContainedBindComponent;
        ib : integer;
    begin
      for ib:=0 to BindingsList1.BindCompCount-1 do
      begin
       B:=BindingsList1.BindComps[ib];
       if (B.ControlComponent=Grid) then
         try
           result:=TLinkGridToDataSourceColumns(TLinkGridToDatasource(B).Columns)[col].MemberName;
           break; 
         except
           result:='';
         end;
      end;
    end;

    Perfectible I think but working, even with unlinked columns, but only if columns are defined 
    image.png.38f3cdd333b9f6921a026e88d1e92b94.png

    • Like 1

  7. Hi,

    Quote

    It works for Windows, iOS and Android but not for macOS-64

    sounds strange, but I am not an apple owner

    1 hour ago, sjordi said:

    CustomFormat to DisplayFormat

    Hum, you want to say DisplayText ?

    1 hour ago, sjordi said:

    But the CustomFormat should be set to Format('%%.2f', %s) 

    I report, I think about two times https://quality.embarcadero.com/browse/RSP-22962 , this bug. If you want to use the format of livebindings  try to use

    Format('%%.2f', 1*value)

     


  8. Hum !

    I was convinced my picture explain the whole thing :classic_unsure: 

    In my sample (pro app i'm writing) it's work, and description you gave seem to be the same goal. 

    I resume : a TListview (live)binded to a BindSourceDB, linked to a Dataset (whatever could it be Firedac, ClientDataset even TProtypeBindSource) fields of this one declared and some, here your currency field, with their DisplayFormat set.

     

    Take care one thing, you have to change those 'displaytext' in the FillExpressions collection  

     

    one or more picture to see where you encounter difficulties (even a dfm part of the form) should be a good thing :classic_dry:

    ie.

      object bndngslst1: TBindingsList
        Methods = <>
        OutputConverters = <>
        Left = 20
        Top = 5
        object LinkListControlToField1: TLinkListControlToField
          Category = 'Liaisons rapides'
          DataSource = bndQFacture
          Control = lvFactures
          FillExpressions = <
            item
              SourceMemberName = 'ANNEE'
              ControlMemberName = 'NumeroFacture'
              CustomFormat = '%s+'#39'-'#39'+DataSet.NUMERO.Text+'#39' ('#39'+DataSet.PART.Text+'#39')'#39
            end
            item
              SourceMemberName = 'NOM'
              ControlMemberName = 'Client'
            end
            item
              SourceMemberName = 'ECHEANCE'
              ControlMemberName = 'Echeance'
              CustomFormat = 'DisplayText+'#39' '#39'+Dataset.MODE_PAIEMENT.Text'
            end
            item
              SourceMemberName = 'MONTANT'
              ControlMemberName = 'Montant'
            end>
          FillHeaderExpressions = <>
          FillBreakGroups = <>
        end
      end

     

     


  9. Hi,

    in Binding expressions Customformat use DisplayText, see image attached. (Still filling DisplayFormat of the fields 😉)  

    That's the easiest way, you can also use Format bindingList method but be careful syntax is slightly different the one we use in programs 

     

    Capture_1.PNG


  10. On 1/9/2020 at 6:02 PM, Yaron said:

    I have "ListView.ItemAppearanceObject.ItemObjects.Detail.Visible = False" and "ListView.ItemAppearanceObject.ItemEditObjects.Detail.Visible = False".

    And "ListView.ItemAppearance" set to "ListItem" (which adds a ">" at the end of the line for some reason).

     

    Hi, you forgot to set image and accessory not visible.


  11. Well, sorry if it's too late, i saw this post today.

    "Yes you can" :classic_dry:, playing with the ItemHeight, alas this height is an integer and can't be lesser than 1 (0 => default size) so you will obtain a gray gap more or less high depending on items count in the group  

    I explain how in this blogpost (sorry french only)

    • Like 1

  12. You have one linked to my blog post. To see the behavior that I denounce, you only have to use livebindings editor and synchronize,accepting link change, and renaming this new link  (not fair hu ?) 

    On the other hand, i am working on another sample (using the well-known biolife.cds) but it is not ready yet, mainly because i have some other functionalities (i.e. custom search)

    Here some screenshots (capture and capture_1 without synchronization, last one with synchronization) , same code 

     

    procedure TMainForm.rdbListBoxChange(Sender: TObject);
    var AFillBreakGroup : TFillBreakGroupItem;
    begin
    LinkListBoxGroup.Active:=False;
    if TRadioButton(Sender).IsChecked then
     begin
       case TRadioButton(Sender).tag of
         0 : begin
              LinkListBoxGroup.FillBreakGroups.Clear;
              LinkListBoxGroup.FillBreakFieldName:='';
              LinkListBoxGroup.FillHeaderFieldName:='';
              ClientDataSet1.IndexFieldNames:='';
             end;
         1 : begin
              LinkListBoxGroup.FillBreakGroups.Clear;
              LinkListBoxGroup.FillBreakFieldName:='Category';
              LinkListBoxGroup.FillHeaderFieldName:='Category';
              ClientDataSet1.IndexFieldNames:='Category';
             end;
         2 : begin
              ClientDataSet1.IndexFieldNames:='Length (cm)';
              LinkListBoxGroup.FillBreakFieldName:='Length (cm)';
              LinkListBoxGroup.FillHeaderFieldName:='';
              // créer les groupes
              aFillBreakGroup:=LinkListBoxGroup.FillBreakGroups.AddItem;
              AFillBreakGroup.MinValue:='0';
              AFillBreakGroup.MaxValue:=30.ToString;
              AFillBreakGroup.DisplayText:='Petits';
    
              aFillBreakGroup:=LinkListBoxGroup.FillBreakGroups.AddItem;
              AFillBreakGroup.MinValue:=30.ToString;
              AFillBreakGroup.MaxValue:=60.toString;
              AFillBreakGroup.DisplayText:='Moyens';
    
              aFillBreakGroup:=LinkListBoxGroup.FillBreakGroups.AddItem;
              AFillBreakGroup.MinValue:=60.ToString;
              AFillBreakGroup.MaxValue:=90.ToString;
              AFillBreakGroup.DisplayText:='Gros';
    
              aFillBreakGroup:=LinkListBoxGroup.FillBreakGroups.AddItem;
              AFillBreakGroup.MinValue:=90.ToString;
              AFillBreakGroup.DisplayText:='Enormes';
             end;
       end;
     end;
    LinkListBoxGroup.Active:=True;
    end;

     

    Capture.PNG

    Capture_1.PNG

    Capture_2.PNG


  13. Hi,

    Pushing limits of TListBox and TListView I am testing FillBreakGroups collection (you can see my firsts steps here).

    Ok, that works fine was my first thoughts.

     

    Writing a new tutorial about list and livebindings, I create a new project and saw that using synchronize link and FillBreakGroups does not work :classic_sad: is this not supposed to or is this a bug ?

    note : my tests are only on 10.3.2 version


  14. If you only check for those 2 alternatives and only windows target my heart say Firebird as Dany Marmur I had no problem with since first version.

    if you want some encrypted column the choice is Interbase (native column encryption).

    Now if your targets are multi os, till now i don't access directly to Firebird database (client/server) on Android with Firedac but it works with IBDac. I don't test an embedded version of the database though.

    So for multi-os I certainly will choose IB keeping in mind Firebird .

     

    But if your project is not a multi-user one i vote for SQLite avoiding all database server deployment   

    • Thanks 1

  15. What about using TTextService ?

    I just had a (deep) look into Delphi source and found TTextServiceAndroid.DrawSingleLine

          {$IFDEF ANDROID}
          if SupportsPlatformService(IFMXTextService,aService) then
            begin
              alignement:=CheckRtl(Value.ToString,'');
              if alignement=TTextAlign.Trailing
                 then flag := [TFillTextFlag.RightToLeft]
                 else flag:=[];
    // had to get font
              aService.DrawSingleLine(Canvas,Value.ToString,Bounds,Afont,
                                      1,flag, alignement);
            end;
          {$ENDIF}

    My only problem is to get the right font though (the one in the style i presume).

     

    I don't go further with this for now.. 


  16. Hi,

    I don't write nor read RTL languages, I wrote a function to detect if the text starts with a RTL char

    function checkRtl (S : string; Exceptions : String = '' ) : TTextAlign;
    var carray : array of WideChar;
        i : int64;
        ws : String;
    begin
       for I := 0 to 9 do
          S:=StringReplace(S,i.ToString,'',[rfReplaceAll]);
      // supprime autres caractères spéciaux
        S:=StringReplace(S,'(','',[rfReplaceAll]);
        S:=StringReplace(S,')','',[rfReplaceAll]);
        S:=StringReplace(S,'"','',[rfReplaceAll]);
        S:=StringReplace(S,'''','',[rfReplaceAll]);
        S:=StringReplace(S,'-','',[rfReplaceAll]);
       if not E.IsEmpty then
         begin
            for I := 1 to Length(Exceptions) do
                    S:=StringReplace(S,Exceptions[i],'',[rfReplaceAll]);
         end;
    
       S:=Trim(S);
       // arabic + hebrew
       SetLength(carray,$6ff-$590);
       for I := $590 to $6ff do carray[i-$590]:=Char(I);
       // there are some farsi char to be added 
       
       result:=TTextAlign.Trailing;
       if S.IsEmpty then exit;
       if inOpArray(S[1],carray) then result:=TTextAlign.Leading;
    end;

    And, with Nabil's Help I test my ideas in a grid.

     

    You can find (french) discussion here and my tutorial  https://serge-girard.developpez.com/tutoriels/Delphi/Livebindings/Grilles/#LVII-C-1 

    I did not test for TEdit and TLabel though but my guess it is possible

    TextLayoutFull.PNG

    • Like 1
    • Thanks 2

  17. Fool I am with this unnecessary interface ! In fact, it does exists yet.

    So here is my steps with a TListView / DynamicAppearance without passing it in Edit mode

    There for write  the OnItemClickEvent (here my DynamicAppearance contains an TlistItemImage named 'Image'

    here is dfm part

        object YourListView: TListView
          ItemAppearanceClassName = 'TDynamicAppearance'
          ItemEditAppearanceClassName = 'TDynamicAppearance'
          HeaderAppearanceClassName = 'TListHeaderObjects'
          FooterAppearanceClassName = 'TListHeaderObjects'
          Position.X = 32.000000000000000000
          Position.Y = 360.000000000000000000
          Size.Width = 225.000000000000000000
          Size.Height = 265.000000000000000000
          Size.PlatformDefault = False
          TabOrder = 5
          ItemAppearanceObjects.ItemObjects.ObjectsCollection = <
            item
              AppearanceObjectName = 'Image'
              AppearanceClassName = 'TImageObjectAppearance'
              Appearance.ScalingMode = Stretch
            end
            item
              AppearanceObjectName = 'Text1'
              AppearanceClassName = 'TTextObjectAppearance'
            end>
          ItemAppearanceObjects.ItemEditObjects.ObjectsCollection = <
            item
              AppearanceObjectName = 'Text1'
              AppearanceClassName = 'TTextObjectAppearance'
            end>
          OnItemClick = YourListViewItemClick
        end

     

    and code part

    var AListItemBitmap : TListItemImage;
        AListItemText : TListItemText;
        AColor : TAlphaColor;
    begin
    YourListView.Items.SetChecked(AItem.Index,not Aitem.Checked);
    AListItemBitmap:=AItem.Objects.FindObjectT<TListItemImage>('Image');
    if Assigned(AListItemBitmap) then
     begin
         AListItemBitmap.OwnsBitmap:=True; 
         AListItemBitmap.Bitmap:=TBitmap.Create(40,40);
         if AItem.Checked then AColor:=TAlphaColorRec.AliceBlue
                          else AColor:=TAlphaColorRec.Null;
         AListItemBitmap.Bitmap.Clear(Acolor);
     end; 

    but you can change text font (afraid AListItemText.TextColor don't work)

    AListItemText:=AItem.Objects.FindObjectT<TListItemText>('Text1');
    if Assigned(AListItemText) then
         if AItem.Checked then AListItemText.Font.Style:=[TFontStyle.fsBold]
                          else AListItemText.Font.Style:=[];
    
     

     

    Capture.PNG


  18. Quote

    My problem is I want to skip the checkboxes.

    Well you can skip or hide :classic_wink:, putting the listview in edit mode and hiding the checkbox works "as expected". I put commas in reference to my previous post.

    Using a Dynamic appearance this is the best way because checkbox doesn't react (point 2, bug ?)

    Quote

    2- I try to do the same thing but with appearance I prefer, the TDynamicAppearance one. In this case the checkbox don't react

    But color change :classic_huh: the only thing is to find how the color is changing and set-it

    Quote

    My guess is I actually have to hook the click to the underlying database... Tag to set it on/off, but obviously it's not enough.

    Well, if you have a Boolean field to bind, yes (I am writing another tutorial about Listview and ListImage but in review/correction till now).

    I checked for event like "OnChecked"  or similar but for now I don't found one reachable, I searched in Interface IListViewCheckProvider and  IListViewPresentation but without good result.

    I am looking for the checkbox drawing in the source but it's a little hard to track !

     

    The more I check for selection the more I think there is a bug there but, "scalded cat fears cold water", I don't want to report to Bug Tracker (2 last one I report was said to be yet reported and one not reproducible)  without any proof/solution 
     

    I also work on an interface

     IListViewSelectedItems = interface
       ['{3D8B9910-A017-4A10-8260-D44E9F7129B7}']
       procedure StartSelection;
       procedure SetSelected(Value : TList<Integer>);
       function  GetSelected :  TList<Integer>;
       property  Selected :  TList<Integer> read GetSelected write SetSelected;
     end;
       TListView = class(FMX.ListView.TListView,IListViewSelectedItems)
       private
         FSelected : TList<Integer>;
       public
         constructor Create(AOwner : TObject); // <<<<<<<<<<<<
         destructor Destroy; override;
         procedure StartSelection;
         procedure SetSelected(Value : TList<Integer>);
         function  GetSelected :  TList<Integer>;
         property  Selected :  TList<Integer> read GetSelected write SetSelected;
       end;
    
    { TListView override}        
    procedure TListView.StartSelection;
    begin
    if not Assigned(FSelected) then FSelected:=TList<Integer>.Create;        
    end;
    
    function TListView.GetSelected : TList<Integer>;
    begin
    result := FSelected;       
    end;       
    
    procedure TlistView.SetSelected(value : TList<Integer>);
    begin
    FSelected:=Value;       
    end;       

    Here I can surely add an OnSelect event,(optionally a ClearSelection, SelectAll procedure).

    But I am still blocked

       1 - a way to initialize FSelected at creation time (without using StartSelection)

       2 -on painting selection (overriding  or duplicating IListViewCheckProvider ?)    


  19. Hi, sorry for delay but if it is still in actuality  here is how i make this

    with  TBindGridLink.Create(Self) do
      begin
          ControlComponent := Grid1;
          SourceComponent := AdapterBindSource1;
          // Filling Grid
          ColumnExpressions.AddExpression; // adding a right filler
          with ColumnExpressions.AddExpression do // ColumnName = 'Code', ColumnIndex = 1
            begin
              SourceMemberName := 'Code';
              with FormatCellExpressions.AddExpression do
                begin
                  ControlExpression := 'Data';
                  SourceExpression := 'Value';
                end;
            end;
    	  // an so on for columns 
    	  
    	  // MANDATORY TO NAVIGATE 
          // Position (synchronisation entre la liste et la grille)
          with PosControlExpressions.AddExpression do
            begin
              ControlExpression := 'Selected';
              SourceExpression := 'Math_Max(0,ItemIndex)';
            end;
          with PosSourceExpressions.AddExpression do
            begin
              ControlExpression := 'Math_Max(0,Selected)';
              SourceExpression := 'ItemIndex';
            end;
    		
          // Working on columns size
          with FormatControlExpressions.AddExpression do
            begin
              ControlExpression := 'Columns[0].width';
              SourceExpression := '20';
            end;
          with FormatControlExpressions.AddExpression do
            begin
              ControlExpression := 'Columns[1].width';
              SourceExpression := '140';
            end;
          // and so on ...
      end;

     

×