Recent

Author Topic: Field-Type TDbf ftFloat seems not workly correct  (Read 7551 times)

PascalGuru

  • Newbie
  • Posts: 4
Field-Type TDbf ftFloat seems not workly correct
« on: April 26, 2017, 10:46:39 pm »
  Field-Type  TDbf ftFloat  seems not workly correct.
  The result on a create Table with this Fieldtype,
  we get a Fieldtype  'Numerical' respective  'ftInteger
  and there a no possibility to perform decimal places in it.
 
    MyDbf.FieldDefs.Add('ZAHL_FLOAT', ftFloat, 10, true). 
 
  Now I have the Piece of Code:
 
  procedure TForm1.DBF_Datei_Neu(sender : TObject);
    begin
    MyDbf := TDbf.Create(nil);
    try
   
         (* Now we use an absolute Path to "DATA"-Directory *)
      MyDbf.FilePathFull := 'C:\PROJEKTE\PASCAL\DBA\DATA' + DirectorySeparator;
     
      (* Wir want to create an compatible DBASE4 Table *)
      MyDbf.TableLevel := 4;

      MyDbf.Exclusive := true;
      MyDbf.TableName := 'testpasc.dbf';
      (* For this wie need the Unit DB *)
      with MyDbf.FieldDefs do
        begin                                    // Here are my own-named DBASE-Fieldtypes
        Add('ID',         ftInteger,  3, true);  // N  3,0  NoIdx
        Add('NAME',       ftString,  20, true);  // C  2    NoIdx
       
        Add('ZAHL_BYTE',  ftSmallInt, 3, true);  // N  3    NoIdx
        Add('ZAHL_INT',   ftInteger,  6, true);  // N  6    NoIdx
        ...
       
        Add('ZAHL_FLOAT', ftFloat,   10, true);  // G 10,3  NoIdx 
        ... 
       
        end; (* of with MyDbf.FieldDefs *)
       
      MyDbf.CreateTable;
      MyDbf.Open;
      MyDbf.AddIndex('id', 'ID', [ixPrimary, ixUnique]);
 

      (* We fill the first Record *)
      MyDbf.Append;     // Create an Record
     
      MyDbf.FieldByName('ID').AsInteger        :=  1;
      MyDbf.FieldByName('NAME').AsString       := 'Jesus Christ';
      MyDbf.FieldByName('ZAHL_BYTE').AsInteger :=  255;
      MyDbf.FieldByName('ZAHL_INT').AsInteger  :=  32767;
     
      MyDbf.FieldByName('ZAHL_FLOAT').AsFloat  :=  3.14159;
      MyDbf.Post;       // Important for Store of the Record and Continuing 
      end; (* of with MyDbf.FieldDefs *)
   
    ...
    finally
      MyDbf.Free;
    end; (* of try-finally *)
  end; (* of procedure TForm1.DBF_Datei_Neu *)
     
  If we later load the Table in originally DBASE 4 , which we created with Component  TDbf ,
  we see that the field 'ZAHL_FLOAT' is always of Type 'Numerical', not of Type 'Gleitkomma'
  (it's a german DBASE, i don't know the correct english naming of this type).
  And we see in Field ZAHL_FLOAT only the Number  3 - without decimal places.
 
  What should I do?
  Is it really a bug in the Component TDbf ?

  Thanks for your help and answers,
  PascalGuru 

GAN

  • Sr. Member
  • ****
  • Posts: 370
Re: Field-Type TDbf ftFloat seems not workly correct
« Reply #1 on: April 26, 2017, 11:41:32 pm »
From the only official guide of TDBF : https://sourceforge.net/projects/tdbf/files/TDbf%20documentation/TDbf%20documentation%201.1/

Code: Pascal  [Select][+][-]
  1. NewFieldDefs: TDbfFieldDefs ;
  2. NewFieldDef: TDbfFieldDef;
  3. Dbf1 : TDbf ;
  4. ...
  5. // create new field list
  6. NewFieldDefs := TDbfFieldDefs. Create ( Self );
  7. // assign current list
  8. NewFieldDefs. Assign ( Dbf1 . DbfFieldDefs);
  9. // assume first field is string , 20 wide , make larger to 40
  10. NewFieldDefs. Items [0]. Size := 40;
  11. // rename second field to ’ RENAMED ’
  12. NewFieldDefs. Items [1]. FieldName := ’ RENAMED ’;
  13. // add a float field
  14. NewFieldDef := NewFieldDefs. AddFieldDef;
  15. NewFieldDef. FieldName := ’ NEW_FLOAT ’;
  16. NewFieldDef. FieldType := ftFloat;
  17. NewFieldDef. Size := 10;
  18. NewFieldDef. Precision := 3;
  19. // restructure table and pack
  20. Dbf1 . Restructure( NewFieldDefs , true );
  21. // restructure table and not pack
  22. // Dbf1 . Restructure( NewFieldDefs , false );
  23. // free mem
  24. NewFieldDefs. Free ;

What you need:
Code: Pascal  [Select][+][-]
  1. NewFieldDef := NewFieldDefs. AddFieldDef;
  2. NewFieldDef. FieldName := ’ NEW_FLOAT ’;
  3. NewFieldDef. FieldType := ftFloat;
  4. NewFieldDef. Size := 10;
  5. NewFieldDef. Precision := 3; // <---------

Or you can try:
Code: Pascal  [Select][+][-]
  1.  Add('ZAHL_FLOAT', ftFloat,   10,  3, true);  // G 10,3  NoIdx  

Regards.
Lazarus 2.0.8 FPC 3.0.4 Linux Mint Mate 19.3
Zeos 7̶.̶2̶.̶6̶ 7.1.3a-stable - Sqlite 3.32.3 - LazReport

PascalGuru

  • Newbie
  • Posts: 4
Answer of: Field-Type TDbf ftFloat seems not workly correct
« Reply #2 on: May 03, 2017, 03:03:32 pm »
  Thank you very much for your Help.
  I had search and search and search again - but nothing find anywhere.
  Beside: The Link of the official Guide works - obviously the Website "Sourcefourge"
  are in most Cases does not work in Case of slower (and very slower) Connections.
 
  The official Guide is from 2004 and does not contain all relevant Points for Newbies.
  They should be stand in:
 
Code: Pascal  [Select][+][-]
  1.     uses db, dbf, dbf_fields, dbf_common;
  2.     var
  3.       NewFieldDefs : TDbfFieldDefs;
  4.       NewFieldDef  : TDbfFieldDef;
  5.       Dbf1         : TDbf;
  6.     begin
  7.     ...
  8.     // Create new Field-List
  9.     NewFieldDefs := TDbfFieldDefs.Create (Self);
  10.     // Assign current List
  11.     NewFieldDefs.Assign ( Dbf1.DbfFieldDefs);
  12.     // Assume first Field is string, 20 wide , make larger to 40
  13.     NewFieldDefs. Items [0].Size := 40;
  14.     // Rename second field to ’ RENAMED ’
  15.     NewFieldDefs. Items [1].FieldName := ’ RENAMED ’;
  16.     // Add a Float Field
  17.     NewFieldDef := NewFieldDefs.AddFieldDef;
  18.     NewFieldDef.FieldName := 'ZAHLFLOAT';
  19.     NewFieldDef.FieldType := ftFloat;
  20.     NewFieldDef.Size      := 10;
  21.     NewFieldDef.Precision := 3;
  22.     // Restructure Table and pack
  23.     Dbf1.Restructure(NewFieldDefs, true);
  24.     // Restructure Table and not pack
  25.     // Dbf1.Restructure(NewFieldDefs, false);
  26.     // Free mem
  27.     NewFieldDefs.Free;
  28.    
  Not all is good - the Command  Dbf1.Restructure  is not accepted.
  Which Unit for Restructure is needed ?
  I had try all: dbf_common, fpdbexport, fpdbfexport, fpfixedexport
  but nothing works!
  Like I said before - the Official Guide could be a Step better.
 
  The third suggestion with
Code: Pascal  [Select][+][-]
  1.     Dbf1.Add('ZAHL_FLOAT', ftFloat, 10, 3, true);
  2.  

 is not accepted without any more things. (This I had try as First.)
   
  The Single Apostroph on the Documentation is a wrong Sign -
  it doesn't accepted from LAZARUS/FREE-PASCAL/TURBO PASCAL/...  (only ' works!)
 
  Thank you for your Help again!
  PascalGuru
« Last Edit: May 03, 2017, 03:10:34 pm by PascalGuru »

PascalGuru

  • Newbie
  • Posts: 4
Re: Field-Type TDbf ftFloat seems not workly correct
« Reply #3 on: May 11, 2017, 04:49:06 pm »
Thank you, People, for your Helps.

The Code above is not correct.
  1. Instead of  "Restructure"  you must take the correct  "RestructureTable"
      In full Description is the correct Writing: 
        // Restructure Table and not pack
        Dbf1.RestructureTable(NewFieldDefs, false);
 
  2. After the Commands
       
Code: Pascal  [Select][+][-]
  1.         //Create new Field-List
  2.         Dbf1FieldDefs := tDbfFieldDefs.Create(Self);  
  3.         // Assign current List
  4.         Dbf1FieldDefs.Assign(Dbf1.DbfFieldDefs);  
  5.        
  6.         // Assume first Field is String, 20 wide, make larger to 40
  7.         Dbf1FieldDefs.Items[0].Size := 40;
  8.         // Rename second Field to 'ZAHLFLOAT'
  9.         Dbf1FieldDefs.Items[1].FieldName := 'ZAHLFLOAT';
  10.        
   
   The first Command behind  Assign I get an Runtime-Error:
   Projekt XXX has an Exception of "EConvertError"
   with the Message.  "Cannot assign a Nil to a TDbfFieldDefs"
   at Adress  43A177 

There are any Comments, Hints or Suggests ? 

Thank you for your Helping.
PascalGuru

Handoko

  • Hero Member
  • *****
  • Posts: 5122
  • My goal: build my own game engine using Lazarus
Re: Field-Type TDbf ftFloat seems not workly correct
« Reply #4 on: June 16, 2017, 05:40:07 pm »
I think you need this below before you can use the items because Items.Count = 0.

Code: Pascal  [Select][+][-]
  1.      NewFieldDef := Dbf1FieldDefs.AddFieldDef;

PascalGuru

  • Newbie
  • Posts: 4
Re: Field-Type TDbf ftFloat seems not workly correct
« Reply #5 on: November 22, 2018, 05:47:18 pm »
 :'(  Are there no any Comments or Suggestions ?  :'( 

(Or is the offical Guide would be a little Bit more helpful or better ?  :(  )

PascalGuru

wp

  • Hero Member
  • *****
  • Posts: 11830
Re: Field-Type TDbf ftFloat seems not workly correct
« Reply #6 on: November 23, 2018, 12:14:14 am »
I tested your code and it works correctly if I assign the precision to the float flield in the table-creation step or set the Size parameter to 0. The following code uses four methods to add a float field def:
  • your method - does not work
  • use function AddFieldDef (as proposed by others above) - this gives access to all elements of TFieldDef, in particular to the property Precision
  • use procedure Add and extract the added FieldDef from the list of all FieldDefs as being the last item. Then you have access to property Precision again.
  • use procedure Add, but set the Size parameter to zero.
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   MyDbf: TDbf;
  4.   fd: TFieldDef;
  5.   i: Integer;
  6. begin
  7.   MyDbf := TDbf.Create(nil);
  8.   try
  9.  
  10.     MyDbf.FilepathFull := ExtractFilePath(Application.ExeName);
  11. //    MyDbf.FilePathFull := 'C:\PROJEKTE\PASCAL\DBA\DATA' + DirectorySeparator;
  12.  
  13.     (* Wir want to create an compatible DBASE4 Table *)
  14.     MyDbf.TableLevel := 4;
  15.  
  16.     MyDbf.Exclusive := true;
  17.     DeleteFile('testpasc.dbf');
  18.     MyDbf.TableName := 'testpasc.dbf';
  19.  
  20.     (* For this wie need the Unit DB *)
  21.     with MyDbf.FieldDefs do
  22.       begin                                    // Here are my own-named DBASE-Fieldtypes
  23.       Add('ID',         ftInteger,  3, true);  // N  3,0  NoIdx
  24.       Add('NAME',       ftString,  20, true);  // C  2    NoIdx
  25.  
  26.       Add('ZAHL_BYTE',  ftSmallInt, 3, true);  // N  3    NoIdx
  27.       Add('ZAHL_INT',   ftInteger,  6, true);  // N  6    NoIdx
  28.  
  29.       // Method #1
  30.       Add('ZAHL_FLOAT', ftFloat,   10, true);  // G 10,3  NoIdx
  31.  
  32.       // Method #2
  33.       with AddFieldDef do begin
  34.         Name := 'ZAHL_FLOAT2';
  35.         Datatype := ftFloat;
  36.         Size := 10;
  37.         Precision := 4;
  38.       end;
  39.  
  40.       // Method #3
  41.       Add('ZAHL_FLOAT3', ftFloat,   10, true);
  42.       fd := Items[Count-1];
  43.       fd.Precision := 4;
  44.  
  45.       // Method #4
  46.       Add('ZAHL_FLOAT4', ftFloat,   0, true);  // G 10,3  NoIdx
  47.     end; (* of with MyDbf.FieldDefs *)
  48.  
  49.     MyDbf.CreateTable;
  50.     MyDbf.Open;
  51.  
  52.     for i:=0 to MyDbf.FieldCount-1 do
  53.       Memo1.Lines.Add(MyDbf.fields[i].FieldName);
  54.  
  55.     MyDbf.AddIndex('id', 'ID', [ixPrimary, ixUnique]);
  56.  
  57.     (* We fill the first Record *)
  58.     MyDbf.Append;     // Create an Record
  59.  
  60.     MyDbf.FieldByName('ID').AsInteger        :=  1;
  61.     MyDbf.FieldByName('NAME').AsString       := 'Jesus Christ';
  62.     MyDbf.FieldByName('ZAHL_BYTE').AsInteger :=  255;
  63.     MyDbf.FieldByName('ZAHL_INT').AsInteger  :=  32767;
  64.  
  65.     MyDbf.FieldByName('ZAHL_FLOAT').AsFloat  := 3.141592;
  66.     MyDbf.FieldByName('ZAHL_FLOAT2').AsFloat := 3.141592;
  67.     MyDbf.FieldByName('ZAHL_FLOAT3').AsFloat := 3.141592;
  68.     MyDbf.FieldByName('ZAHL_FLOAT4').AsFloat := 3.141592;
  69.     MyDbf.Post;       // Important for Store of the Record and Continuing
  70.   finally
  71.     MyDbf.Free;
  72.   end; (* of try-finally *)
  73. end; (* of procedure TForm1.DBF_Datei_Neu *)
  74.  
The attached screenshot of the LazDataDesktop shows that Method 1 adds the field def as an integer field while the other three methods are correct.

I don't know if the behavior in method 1 (your method) is a bug. The conversion from float to integer field is probably made on the assumption that if Precision is zero the float effectively is an integer. On the other hand, you requested a float field, not an integer field. The problem maybe is in the default value of the Precision which should not be 0 (well, I assume that) but maybe 2 or 3.

As for the documentation: What you call "official documentation" seems to be the documentation of the Delphi version. Here you have the Lazarus port, which may be different or not - I don't know. When reading Delphi documentation in connection with Lazarus you should always be careful and should not take the text too literal - the basic idea usually is correct, but there are differences in details here and there.

A better documentation is our wiki: http://wiki.freepascal.org/Lazarus_Tdbf_Tutorial. I did not read it, but it looks fairly competent when I scrolled through it. And it has the advantage: if there is something wrong we can change it - we cannot change Delphi-related documentation, in particular when it is on a site we don't have access to.
« Last Edit: November 23, 2018, 12:55:44 am by wp »

 

TinyPortal © 2005-2018