#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 — это правильный путь]