Как узнать, какие элементы управления с поддержкой DB связаны с TDataSource?

#delphi #delphi-7

#delphi #delphi-7

Вопрос:

У меня есть DataSource1 (TDataSource) , и есть некоторые элементы управления с поддержкой DB, связанные с ним (через SomeDBControl.DataSource=DataSource1 )

Как я могу узнать (перечислить) в коде, какие элементы управления связаны с данным TDataSource?

Комментарии:

1. @TLama, ссылки на данные — это список TDataLink. и VisualControl является логическим. но что это за элемент управления?

2. @TLama, очень приятно, с помощью TFieldDataLink я могу получить доступ к свойству «Control», НО с помощью TGridDataLink. FGrid является закрытым участником: (Если никто не даст лучшего ответа (который включает TDBGrids), я приму ваш комментарий.

3. @TLama, я это пропустил. пожалуйста, отправьте ответ, и я с радостью приму!

4. Извините, забираю все свои комментарии отсюда… С DataLinks , нет надежного способа получить доступ к экземплярам для всех типов связанных элементов управления. Единственный оставшийся способ, который я могу придумать, — это перебрать все элементы управления и запросить их DataSource свойство. @MartynA, к сожалению, не было…

5. @TLama: Ну что ж. Не мог бы OP сделать это, используя старый стиль RTTI, путем поиска свойств DataSource и MasterSource компонентов?

Ответ №1:

Приведенный ниже код, который использует RTTI, работает для меня в D7, чтобы перечислить компоненты, которые имеют свойство DataSource или MasterSource, путем рекурсивного поиска объекта контейнера (т. Е. Формы и ее компонентов).

(Очевидно, вы могли бы сделать подобное для любых других интересующих вас форм / модулей данных)

Обновление # 1: в исходной версии этого ответа был создан список каждого компонента в форме и имя его источника данных / основного источника, если таковой имеется. Я изменил его, чтобы обеспечить лучшее соответствие тому, что вы задаете в теле вашего вопроса).

Обновление # 2: это исправляет пару ошибок в версии обновления # 1 и повторно реализует функцию HasDataSource таким образом, чтобы избежать генерации исключения при проверке компонентов, у которых нет свойства DataSource / MasterSource .

 function HasDataSource(AComponent : TComponent; var ADataSource : TDataSource) : Boolean;

  function GetDataSource(APropName : String) : TDataSource;
  var
    AObject : TObject;
    PInfo : PPropInfo;
  begin
    Result :=  Nil;
    PInfo := GetPropInfo(AComponent, APropName);
    if PInfo = Nil then
      exit;
    AObject := GetObjectProp(AComponent, PInfo);
    Result := TDataSource(AObject);
  end;

begin
  Result :=  False;
  ADataSource := GetDataSource('DataSource');
  if ADataSource <> Nil then
    Result := True;
  if Result then exit;

  ADataSource := GetDataSource('MasterSource');
  if ADataSource <> Nil then
    Result := True;
end;


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

procedure TForm1.FindDataSourceObjects(AContainer : TComponent);
var
  i : Integer;
  ADataSource : TDataSource;

  procedure LogDataSourceName(AContainer : TComponent);
  begin
    Log(AContainer.Name   ' Datasource: '   ADataSource.Name);
  end;

begin
  if HasDataSource(AContainer, ADataSource) then
    LogDataSourceName(AContainer);

  for i := 0 to AContainer.ComponentCount - 1 do begin
    FindDataSourceObjects(AContainer.Components[i]);
  end;
end;

procedure TForm1.btnFindClick(Sender: TObject);
begin
  FindDataSourceObjects(Self);
end;
  

DFM моей формы

 object Form1: TForm1
  Left = 195
  Top = 124
  Width = 623
  Height = 303
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object DBText1: TDBText
    Left = 307
    Top = 56
    Width = 65
    Height = 17
    DataSource = DataSource1
  end
  object Panel1: TPanel
    Left = 307
    Top = 80
    Width = 281
    Height = 161
    Caption = 'Panel1'
    TabOrder = 0
    object DBText2: TDBText
      Left = 24
      Top = 64
      Width = 65
      Height = 17
      DataSource = DataSource2
    end
  end
  object Memo1: TMemo
    Left = 8
    Top = 16
    Width = 281
    Height = 225
    TabOrder = 1
  end
  object btnFind: TButton
    Left = 307
    Top = 16
    Width = 75
    Height = 25
    Caption = 'Find'
    TabOrder = 2
    OnClick = btnFindClick
  end
  object DataSource1: TDataSource
    DataSet = ClientDataSet1
    Left = 448
    Top = 16
  end
  object DataSource2: TDataSource
    DataSet = ClientDataSet2
    Left = 544
    Top = 16
  end
  object ClientDataSet1: TClientDataSet
    Aggregates = <>
    Params = <>
    Left = 408
    Top = 16
  end
  object ClientDataSet2: TClientDataSet
    Aggregates = <>
    MasterSource = DataSource1
    PacketRecords = 0
    Params = <>
    Left = 496
    Top = 16
  end
end
  

Комментарии:

1. Вы могли бы спокойно писать Result := (IsPublishedProp(AComponent, 'DataSource') and PropIsType(AComponent, 'DataSource', tkClass) and (GetObjectProp(AComponent, 'DataSource', TDataSource) = ADataSource)) or... . Как я любил этот старый стиль RTTI 🙂

2. @TLama: Спасибо. Меня беспокоило, что моя предыдущая версия будет генерировать исключения для компонентов, у которых нет источника данных / мастер-источника, а их может быть сотни в проекте. Я перекодировал свою функцию HasDataSource таким образом, чтобы избежать этого, в то время как для каждого имени свойства требуется только один доступ к информации о свойстве.

3. Параноический подход также проверил бы, содержит ли свойство object ( if PInfo^.PropType^^.Kind = tkClass ), и если да, то действительно ли полученный вами объект имеет тип TDataSource (обращение к приведению типов). Если кто-то создаст (злой 🙂 компонент, который будет иметь опубликованное DataSource свойство типа, например Integer , или класс объекта будет отличаться от TDataSource , функция завершится с ошибкой. [ 1ed уже, поскольку RTTI — это правильный путь]