Reputation: 147
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
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
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
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