D.D
D.D

Reputation: 147

TDBGrid Duplicating rows

I am converting some software from Delphi 5 to Delphi 10.2.

We have a TDBGrid that is linked to a datasource that is link to a table. So something like this:

TDBGrid.DataSource := GroupDS;
GroupDS.DataSet := MemoryTable;

The MemoryTable has 1 record in it. However, no matter what I've tried the TDBGrid is duplicating the single record. This behavior only happens in D10.2. In D5 it shows the single record normally. I can call RecordCount on the table and verify that there is only 1 record present in it.

Please let me know if there is any other info I can provide. This is all taking place in VCL stuff so there isn't much code to show. I don't know if maybe something changed in the 20 years between the releases of the IDEs.

I wrote a test app to recreate this issue.

Code:

EmpGrpMember := InitializeACRTable;

EmpGrpMember.InMemory := True;
EmpGrpMember.IndexDefs.Add('GroupGUID', 'GroupGUID', [ixPrimary, ixUnique]);
EmpGrpMember.IndexDefs.Add('GroupName', 'GroupName', [ixUnique]);
EmpGrpMember.IndexName := 'GroupName';
EmpGrpMember.FieldDefs.Add('GroupGUID', ftString, 40);
EmpGrpMember.FieldDefs.Add('GroupName', ftString, 100);
EmpGrpMember.TableName := 'EmpGrpMember';

EmpGrpMemberDS.DataSet := EmpGrpMember;
DBGrid1.DataSource := EmpGrpMemberDS;
EmpGrpMember.Open;
EmpGrpMember.Insert;
EmpGrpMember.FieldByName('GroupGUID').AsString := '123';
EmpGrpMember.FieldByName('GroupName').AsString := 'wwww';
EmpGrpMember.Post;

dfm:

object Form1: TForm1
  Left = 0
  Top = 0
  Caption = 'Form1'
  ClientHeight = 336
  ClientWidth = 635
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 13
  object DBGrid1: TDBGrid
    Left = 144
    Top = 96
    Width = 225
    Height = 121
    Options = [dgTitles, dgColumnResize, dgColLines, dgRowLines, dgTabs, dgRowSelect, dgAlwaysShowSelection, dgConfirmDelete, dgCancelOnExit]
    TabOrder = 0
    TitleFont.Charset = DEFAULT_CHARSET
    TitleFont.Color = clWindowText
    TitleFont.Height = -11
    TitleFont.Name = 'Tahoma'
    TitleFont.Style = []
    Columns = <
      item
        Expanded = False
        FieldName = 'GroupName'
        Title.Caption = 'Member of Groups'
        Width = 191
        Visible = True
      end>
  end
  object EmpGrpMemberDS: TDataSource
    Left = 488
    Top = 216
  end
end

I still get the same results. My dbgrid ends up showing 4 'www' and it should only be showing 1. I do a .recordcount on the table and it only shows 1 record.

Upvotes: 2

Views: 617

Answers (3)

Stalkium
Stalkium

Reputation: 158

Your DBGrid is 121 pixels height,; that allow 4 records to fits in it, so this is the reason why you have 4 duplicate rows, if you change your dbgrid height to 200 for example you will have more row, I had the same problem and after investigating lil bit, i found that the culprit was the OnCalcField procedure, i wanted to display a currency for each row like this :

FDQueryValue.DisplayFormat:='#,##0.00'+' '+FDQueryCurrency.AsString;

Trying to get the currency from each record and append it to the value field was wrong way to do since it will only take the currency field from the current record and apply it to all, ...

I don't know what the link between oncalc and ondraw events but sure there is since it replicated record until filling the height of it, like in your case, i removed this line and everything is ok

Upvotes: 0

nzs
nzs

Reputation: 1

Not optimized source, just working after 24h debugging...

procedure TSQLMemDataSet.InternalSetToRecord(Buffer: TRecBuf);
var BookMark: Pointer;
begin
   if (FHandle = nil) then
       raise ESQLMemException.Create(10046,ErrorLNilPointer);
   if (Pointer(Buffer) = nil) then
       raise ESQLMemException.Create(10047,ErrorLNilPointer);

   //not working there was mem error at end/free
   //InternalGotoBookmark(TBookmark(aBuffer)); 

   BookMark := PAnsiChar(Buffer) + FHandle.BookmarkOffset;
   if (Pointer(Bookmark) = nil) then
       raise ESQLMemException.Create(10037,ErrorLNilPointer);
   if (FHandle = nil) then
       raise ESQLMemException.Create(10038,ErrorLNilPointer);
   FHandle.CurrentRecordID :=
       PSQLMemBookmarkInfo(Bookmark)^.BookmarkData;
   FHandle.FirstPosition := False;
   FHandle.LastPosition := False;

end; // InternalSetToRecord

Upvotes: -1

MartynA
MartynA

Reputation: 30715

The minimal sample project below virtually exactly replicates your project except that it uses a TClientDataSet as the dataset instead of the AddAim one.

It correctly shows only a single row. Ergo the problem lies with the use of a TACRTable. So, unless you get lucky and someone here recognises the problem and knows how to fix it, you'll need to take the problem up with AddAim.

Code:

  type
    TForm1 = class(TForm)
      DataSource1: TDataSource;
      DBGrid1: TDBGrid;
      EmpGrpMember: TClientDataSet;
      procedure FormCreate(Sender: TObject);
    public
    end;

  [...]
  procedure TForm1.FormCreate(Sender: TObject);
  var
    AField : TField;
  begin
    AField := TStringField.Create(Self);
    AField.FieldKind := fkData;
    AField.FieldName := 'GroupGUID';
    AField.Size := 255;
    AField.DataSet := EmpGrpMember;

    AField := TStringField.Create(Self);
    AField.FieldKind := fkData;
    AField.Size := 255;
    AField.FieldName := 'GroupName';
    AField.DataSet := EmpGrpMember;

    EmpGrpMember.IndexDefs.Add('GroupGUID', 'GroupGUID', [ixPrimary, ixUnique]);
    EmpGrpMember.IndexDefs.Add('GroupName', 'GroupName', [ixUnique]);
    EmpGrpMember.IndexName := 'GroupName';

    EmpGrpMember.CreateDataSet;
    EmpGrpMember.InsertRecord(['123', 'www']);

  end;

Of course, if you can replicate your problem by modifying the above project, there may be something worth looking into.

UpdateTo debug your problem, set up a handler for the DrawCell event of the grid, like this

procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  DataCol: Integer; Column: TColumn; State: TGridDrawState);
begin
  DataCol := DataCol;
end;

Put a breakpoint in it. When the breakpoint trips, you should find that tracing into the VCL source from it, you eventually arrive at a while loop inside the DrawCells procedure in Grids.Pas. Inspecting the while's condition should show you why you are getting the row displayed twice.

Upvotes: 4

Related Questions