delphi TDBGrid复制行

liwlm1x9  于 2023-03-29  发布在  其他
关注(0)|答案(2)|浏览(146)

我正在将一些软件从 Delphi 5转换到Delphi 10.2。
我们有一个TDBGrid,它链接到一个数据源,该数据源链接到一个表。所以类似于这样:

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

MemoryTable中有1条记录。然而,无论我如何尝试,TDBGrid都在复制单个记录。这种行为只发生在D10.2中。在D5中,它正常显示单个记录。我可以在表上调用RecordCount并验证其中只有1条记录。
请让我知道如果有任何其他信息,我可以提供。这是所有发生在VCL的东西,所以没有太多的代码显示。我不知道,也许是在20年之间的IDE版本的变化。
我写了一个测试应用程序来重现这个问题。
验证码:

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

我仍然得到相同的结果。我的dbgrid最终显示4 'www',它应该只显示1。我在表上执行.recordcount,它只显示1条记录。

rxztt3cl

rxztt3cl1#

下面的最小示例项目实际上完全复制了您的项目,只是它使用TClientDataSet作为数据集,而不是AddAim数据集。
它只正确地显示了一行。因此,问题在于使用了TACRTable。所以,除非你很幸运,这里有人认识到这个问题并知道如何解决它,否则你需要用AddAim解决这个问题。
验证码:

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;

当然,如果您可以通过修改上述项目来复制您的问题,那么可能会有一些值得研究的内容。

更新若要调试问题,请为网格的DrawCell事件设置一个处理程序,如下所示

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

在其中放置一个断点。当断点触发时,您应该会发现从它跟踪到VCL源代码,您最终会到达Grids.Pas.DrawCells过程中的while循环。检查while的条件应该会告诉您为什么会让行显示两次。

enxuqcxy

enxuqcxy2#

没有优化的源代码,只是工作后24小时调试...

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

相关问题