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

时间:2019-03-01 22:40:43

标签: delphi

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

谢谢

1 个答案:

答案 0 :(得分:4)

以下内容基于我对此问题的回答:How to find out which DB-Aware controls are linked to a TDataSource? 哪个询问如何找到将哪些数据库感知控件链接到给定的数据源。

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

截至目前,该答案还不够完整,因为

a)仅涉及列出容器对象中的哪些组件 (例如Form或DataModule)以db感知的方式链接到给定的数据集,但对其进行了扩展 查找哪些控件链接到数据集的特定字段;和

b)假定db-aware控件遵循Delphi约定 DataSource字段,如果控件是在特定字段上运行的控件 数据集(例如TDBEdit,而不是TDBGrid)中的一个DataField

内联注释中解释了代码的工作方式;基本上,迭代 容器中的组件查找数据源,然后检查它们是否为 链接到给定的数据集,然后查找指定数据源的控件 在其DataSource字段中(如果有),并提取DataField的值 属性,如果控件是具有一个控件的类型。在明显的待办事项上 扩展代码以覆盖数据集和/或数据集的情况 与支持db的控件位于不同的容器(例如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

所以我希望很明显它应该有能力,还有更多 工作,做您想要的。现在,我将其留给读者练习。

代码

  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;

由于感兴趣的项目可能分散在不同的表单/数据模块中, 您可以使用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;