Вопрос циклического обхода компонентов на форме в Delphi является достаточно распространенной проблемой, с которой сталкиваются разработчики при работе с такими объектами, как TabSheet. В данной статье мы рассмотрим типичную проблему, связанную с некорректным подсчетом компонентов и предложим решение, основанное на использовании правильных свойств для обхода дочерних элементов.
Описание Проблемы
Разработчик столкнулся с проблемой, когда попытка обхода компонентов на вкладке TabSheet (Tab) в объекте TabSheet не давала ожидаемого результата. Несмотря на то, что проверка на активную вкладку осуществлялась успешно, количество компонентов на вкладке определялось как ноль, хотя на вкладке находились два панели с общим количеством девяти чекбоксов.
Анализ Кода
В коде, представленном разработчиком, используется свойство Components для обхода компонентов активной вкладки. Однако, в Delphi, свойство Components содержит компоненты, которые являются владельцами активной вкладки, а не ее дочерними элементами. В случае, если компоненты были добавлены в визуальном редакторе, то владельцем этих компонентов является сама форма, а не вкладка TabSheet.
Подтвержденное Решение
Для корректного обхода дочерних элементов вкладки TabSheet необходимо использовать свойство Controls вместо Components. Вместо ComponentCount следует использовать ControlCount. Обход должен осуществляться через массив Controls[].
Кроме того, учитывая, что на вкладках могут быть панели с чекбоксами в качестве дочерних элементов, потребуется рекурсивный обход, чтобы включить все дочерние элементы, независимо от уровня вложенности.
Пример кода, который решает проблему:
procedure TfrmHsUsers.pagUsersClick(Sender: TObject);
var
i, j: Integer;
Fieldname: string;
CheckBox: TcxDbCheckBox;
Panel: TPanels;
begin
if pagUsers.Properties.ActivePage.Name = 'tabProgram' then
begin
// Обход всех дочерних элементов активной вкладки
for i := 0 to pagUsers.Properties.ActivePage.ControlCount - 1 do
begin
if (pagUsers.Properties.ActivePage.Controls[i] is TPanels) then
begin
// Нашли панель, обходим ее дочерние элементы
Panel := TPanels(pagUsers.Properties.ActivePage.Controls[i]);
for j := 0 to Panel.ControlCount - 1 do
begin
if (Panel.Controls[j] is TcxDbCheckBox) then
begin
CheckBox := TcxDbCheckBox(Panel.Controls[j]);
Fieldname := CheckBox.DataBinding.DataField;
CheckBox.Enabled := Settings.License.IsEnabled(Fieldname);
end;
end;
end
else if (pagUsers.Properties.ActivePage.Controls[i] is TcxDbCheckBox) then
begin
CheckBox := TcxDbCheckBox(pagUsers.Properties.ActivePage.Controls[i]);
Fieldname := CheckBox.DataBinding.DataField;
CheckBox.Enabled := Settings.License.IsEnabled(Fieldname);
end;
end;
end;
end;
В данном примере используется проверка типов для каждого дочернего элемента вкладки, и если элемент является панелью или чекбоксом, выполняется соответствующая логика.
Альтернативный Подход
Для упрощения кода и уменьшения количества проверок типов можно использовать перечисление, как показано в альтернативном ответе:
uses
System.SysUtils;
type
TTabSheetEnumerator<T> = TEnumerator<T>;
TTabSheetEnumerator<T>.Create = function(AControl: TControl): TEnumerator<T>;
begin
Result := TEnumerator<T>.Create(AControl, function(const C: TControl): Boolean;
Result := TControl(T).FindControl<T>(AControl, True) <> nil
);
end;
var
CheckBox: TcxDbCheckBox;
begin
if pagUsers.Properties.ActivePage.Name = 'tabProgram' then
begin
for CheckBox in TTabSheetEnumerator<TcxDbCheckBox>.Create(pagUsers.Properties.ActivePage) do
begin
Fieldname := CheckBox.DataBinding.DataField;
CheckBox.Enabled := Settings.License.IsEnabled(Fieldname);
end;
end;
end;
Данный подход позволяет более лаконично обойти все чекбоксы на вкладке, включая те, которые находятся на панелях.
Заключение
При работе с TabSheet в Delphi важно помнить, что для обхода дочерних элементов следует использовать свойства Controls и ControlCount, а не Components и ComponentCount. При необходимости использования вложенных элементов потребуется дополнительный обход дочерних компонентов панелей. Приведенные примеры кода демонстрируют, как можно решить данную проблему, используя стандартные возможности языка Object Pascal.
Проблема заключается в некорректном обходе компонентов на вкладке TabSheet в Delphi из-за неправильного использования свойств для доступа к дочерним элементам.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS