发现链接到数据集字段的数据感知控件

And*_*lli 3 delphi

在 Delphi 中,我应该怎么做才能获取链接到任何打开表单上的数据集字段的数据感知控件列表?

谢谢

Mar*_*ynA 5

以下是基于我对这个问题的回答:如何找出哪些 DB-Aware 控件链接到 TDataSource? 其中询问如何查找哪些 db-aware 控件链接到给定的数据源。

它使用 TypInfo.Pas 中的传统 RTTI,因此几乎可以与任何版本的 Delphi 配合使用。它不需要更新的 RTTI.Pas。下面的示例是在 D7 中编写和测试的。

截至目前,这个答案还不是很完整,因为

a) 它只列出容器对象(例如 Form 或 DataModule)中的哪些组件以 db-aware 方式链接到给定的数据集,但扩展它以查找哪些控件链接到特定字段数据集;和

b) 它假定数据库感知控件遵循具有DataSource字段的 Delphi 约定,如果控件是对数据集的特定字段(例如 TDBEdit,但不是例如 TDBGrid)进行操作的控件,则为DataField一个。

内联注释中解释了代码的工作原理;基本上,它迭代容器中的组件以查找数据源,然后检查它们是否链接到给定的数据集,然后查找在其DataSource字段中指定数据源的控件(如果有),DataField 如果控件是,则提取属性的值一种类型。显而易见的待办事项是扩展代码以涵盖数据集和/或数据集位于与数据库感知控件不同的容器(例如 DataModule)中的情况。

示例项目包括一个 TClientDataSet、TDataSource、TDBGrid 和两个以您期望的方式连接并产生输出的 DBEdits

    DataSource: DataSource1 DataSet: ClientDataSet1
    DBEdit1 (Classname: TDBEdit) is linked to ClientDataSet1
     on datafield: ID
    DBEdit2 (Classname: TDBEdit) is linked to ClientDataSet1
     on datafield: Name
Run Code Online (Sandbox Code Playgroud)

所以我希望很清楚,它应该能够做更多的工作,做你所要求的。现在,我把它留给读者作为练习。

代码

  uses ... typinfo;

  procedure TForm1.Log(Msg: String);
  begin
    Memo1.Lines.Add(Msg);
  end;

  function DataSourceHasDataSet(ADataSource : TDataSource; ADataSet : TDataSet) : Boolean;
  begin
    Result := ADataSource.DataSet = ADataSet;
  end;

  procedure TForm1.FindControlsForDataSet(AContainer : TComponent; ADataSet : TDataSet);
  var
    i, j : Integer;
    ADataSource : TDataSource;
    AComponent,
    BComponent : TComponent;
    AObject : TObject;
    PInfo : PPropInfo;
    AFieldName : String;

  begin
    // iterate the container looking for datasources
    for i := 0 to AContainer.ComponentCount - 1 do begin
      AComponent := AContainer.Components[i];
      if AComponent is TDataSource then begin
        ADataSource := TDataSource(AComponent);
        //  Check that ADataSource is linked to our specifiied dataset
        if DataSourceHasDataSet(ADataSource, ADataSet) then begin
          Log('DataSource: ' + ADataSource.Name + ' DataSet: ' + ADataSet.Name);

          //  now, iterate the container looking for controls which
          //  have a DataSource property specifying the found datasource
          for j := 0 to AContainer.ComponentCount - 1 do begin
            BComponent := AContainer.Components[j];
            PInfo := GetPropInfo(BComponent, 'DataSource');
            //  PInfo will be non-NIL of the BComponent has a DataSource property
            if PInfo <> Nil then begin
              AObject := GetObjectProp(BComponent, PInfo);
              if (AObject <> Nil) then
                if (AObject is TDataSource) then begin
                  Log(BComponent.Name + ' (Classname: ' + BComponent.ClassName + ') is linked to ' + ADataSet.Name);
                  PInfo := GetPropInfo(BComponent, 'DataField');
                  if PInfo <> Nil then begin
                    AFieldName := GetStrProp(BComponent, 'DataField');
                    Log(' on datafield: ' + AFieldName);
                  end;
                end;
            end;
          end;
        end;
      end;
    end;
  end;

  procedure TForm1.btnFindClick(Sender: TObject);
  begin
    FindControlsForDataSet(Self, ClientDataSet1);
  end;
Run Code Online (Sandbox Code Playgroud)

由于感兴趣的项目可能分布在不同的表单/数据模块中,您可以使用Screen对象来列出它们

  procedure TForm1.btnFormsClick(Sender: TObject);
  var
    i : Integer;
  begin
    for i := 0 to Screen.CustomFormCount - 1 do begin
      Log(Screen.CustomForms[i].Name);
    end;
    for i := 0 to Screen.DataModuleCount - 1 do begin
      Log(Screen.DataModules[i].Name);
    end;
  end;
Run Code Online (Sandbox Code Playgroud)