Rambler's Top100
"Knowledge itself is power"
F.Bacon
Поиск | Карта сайта | Помощь | О проекте | ТТХ  
 Круглый стол
  
Правила КС
>> Настройки

Фильтр вопросов
>> Новые вопросы
отслеживать по
>> Новые ответы

Избранное

Страница вопросов
Поиск по КС


Специальные проекты:
>> К л ю к в а
>> Г о л о в о л о м к и

Вопрос №

Задать вопрос
Off-topic вопросы

Помощь

 
 К н и г и
 
Книжная полка
 
 
Библиотека
 
  
  
 


Поиск
 
Поиск по КС
Поиск в статьях
Яndex© + Google©
Поиск книг

 
  
Тематический каталог
Все манускрипты

 
  
Карта VCL
ОШИБКИ
Сообщения системы

 
Форумы
 
Круглый стол
Новые вопросы

 
  
Базарная площадь
Городская площадь

 
   
С Л С

 
Летопись
 
Королевские Хроники
Рыцарский Зал
Глас народа!

 
  
ТТХ
Конкурсы
Королевская клюква

 
Разделы
 
Hello, World!
Лицей

Квинтана

 
  
Сокровищница
Подземелье Магов
Подводные камни
Свитки

 
  
Школа ОБЕРОНА

 
  
Арсенальная башня
Фолианты
Полигон

 
  
Книга Песка
Дальние земли

 
  
АРХИВЫ

 
 

Сейчас на сайте присутствуют:
 
  
 
Во Флориде и в Королевстве сейчас  13:09[Войти] | [Зарегистрироваться]
Ответ на вопрос № 71458

28-06-2009 00:17
Здравствуйте, Уважаемые.

Собсно вопрос:
На форме имеется несколько компонентов типа, например TEdit, с именами Edit1, Edit2, Edit3  и т.д. Как можно обратиться к каждому компоненту поочередно в цикле for i:=1 to ... do чтобы изменить какое либо его свойство?

[+] Добавить в избранные вопросы

Отслеживать ответы на этот вопрос по RSS

Ответы:


Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице.
Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.

02-07-2009 12:22
02-07-2009 08:16
Но вот если вы вдруг захотите переименовать компонент... Ведь при компиляции строчки FindComponent('Edit1') ошибки не возникнет, хотя самого Edit1 в помине уже и нет...

Согласен, но на то и есть программист чтобы сначала написать, а потом отлаживать программу)

02-07-2009 08:16
проверку имени компонента
Но вот если вы вдруг захотите переименовать компонент... Ведь при компиляции строчки FindComponent('Edit1') ошибки не возникнет, хотя самого Edit1 в помине уже и нет...

02-07-2009 06:46
В примере приведенном уважаемым  Sphinxs не учитывается что на форме могут быть компоненты типа TEdit, которые не нужно обрабатывать. Т.е. чтобы пользоваться таким примером нужно добавлять проверку имени компонента. Меня лично устраивает и FindComponent.

29-06-2009 04:13
Нда, автор выбрал самый тормозной из возможных вариантов. Антон, не  расстраивайтесь :)

29-06-2009 00:10
Присоединяюсь к Sphinxs. А также хочу заметить, что есть метод FindComponent.

29-06-2009 00:02
for I := 0 to ComponentCount - 1 do
if (Components[I] is TEdit) and
TEdit(Components[i]).свойство:=

собсно и усё

28-06-2009 23:17
>>> При этом вы сами должны следить за уникальностью этого имени, так как VCL не запрещает различным компонентам иметь одно и то же значение свойства Name, даже если эти компоненты имеют одного владельца.

Уточнение:
Компоненты, принадлежащие одному владельцу, не могут иметь одинаковых имён, за исключением случая, когда эти имена пустые. Если при создании компонента не указывать владельца, т.е. писать Create(nil), то за неимением владельца против дублирования имён никто и не возражает.
Привожу работающий пример, чтобы все желающие могли поиграться.

P.S. Фреймы в этом отношении имеют свои тонкости: http://www.delphikingdom.com/asp/viewitem.asp?catalogid=673

Unit1.pas

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Button1: TButton;
    Button2: TButton;
    Edit1: TEdit;
    lbComponents: TListBox;
    lbControls: TListBox;
    edtName: TEdit;
    Label1: TLabel;
    Edit2: TEdit;
    Label2: TLabel;
    Label3: TLabel;
    Button3: TButton;
    Button4: TButton;
    Label4: TLabel;
    Label5: TLabel;
    Button5: TButton;
    Button6: TButton;
    Label6: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure ShowLists;
    procedure FormCreate(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
    procedure Button6Click(Sender: TObject);
  private
    FLastTop: Integer;
    function NextTop: Integer;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  ShowLists;
end;

function TForm1.NextTop: Integer;
begin
  Inc(FLastTop, 25);
  Result := FLastTop;
end;

procedure TForm1.ShowLists;
var
  i: Integer;
begin
  {Компоненты формы}
  lbComponents.Items.Clear;
  for i := 0 to ComponentCount-1 do
    lbComponents.Items.Add(Format('[%.2d] - "%s"', [i, Components[i].Name]));
  {Контролы панели}
  lbControls.Items.Clear;
  for i := 0 to Panel1.ControlCount-1 do
    lbControls.Items.Add(Format('[%.2d] - "%s"', [i, Panel1.Controls[i].Name]));
end;

{ Кнопки }

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
  with TEdit.Create(Self) do      // Owner = Self
    begin
      Left := 10;
      Top := NextTop;
      Parent := Panel1;          // Сначала Parent
      Name := edtName.Text;      // Потом Name
    end;
  finally
    ShowLists;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  try
    with TEdit.Create(nil) do    // Owner = nil
    begin
      Left := 10;
      Top := NextTop;
      Parent := Panel1;          // Сначала Parent
      Name := edtName.Text;      // Потом Name
    end;
  finally
    ShowLists;
  end;
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  try
  with TEdit.Create(Self) do      // Owner = Self
    begin
      Left := 10;
      Top := NextTop;
      Name := edtName.Text;      // Сначала Name
      Parent := Panel1;          // Потом Parent
    end;
  finally
    ShowLists;
  end;
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  try
    with TEdit.Create(nil) do    // Owner = nil
    begin
      Left := 10;
      Top := NextTop;
      Name := edtName.Text;      // Сначала Name
      Parent := Panel1;          // Потом Parent
    end;
  finally
    ShowLists;
  end;
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  try
  with TEdit.Create(Self) do      // Owner = Self
    begin
      Left := 10;
      Top := NextTop;
      Parent := Panel1;          //  Parent
      // Name := edtName.Text;    //  Name не задаём
    end;
  finally
    ShowLists;
  end;
end;

procedure TForm1.Button6Click(Sender: TObject);
begin
  try
    with TEdit.Create(nil) do    // Owner = nil
    begin
      Left := 10;
      Top := NextTop;
      Parent := Panel1;          //  Parent
      // Name := edtName.Text;    //  Name не задаём
    end;
  finally
    ShowLists;
  end;
end;

end.


Unit1.dfm

object Form1: TForm1
  Left = 0
  Top = 0
  BorderStyle = bsDialog
  Caption = 'Form1'
  ClientHeight = 588
  ClientWidth = 788
  Color = clBtnFace
  Font.Charset = RUSSIAN_CHARSET
  Font.Color = clWindowText
  Font.Height = -13
  Font.Name = 'Arial'
  Font.Style = []
  OldCreateOrder = False
  Position = poDesktopCenter
  OnCreate = FormCreate
  PixelsPerInch = 96
  TextHeight = 16
  object Label1: TLabel
    Left = 8
    Top = 448
    Width = 34
    Height = 16
    Caption = 'Name'
  end
  object Label2: TLabel
    Left = 435
    Top = 8
    Width = 123
    Height = 16
    Caption = 'Form1.Components'
    Font.Charset = RUSSIAN_CHARSET
    Font.Color = clWindowText
    Font.Height = -13
    Font.Name = 'Arial'
    Font.Style = [fsBold]
    ParentFont = False
  end
  object Label3: TLabel
    Left = 600
    Top = 8
    Width = 100
    Height = 16
    Caption = 'Panel1.Controls'
    Font.Charset = RUSSIAN_CHARSET
    Font.Color = clWindowText
    Font.Height = -13
    Font.Name = 'Arial'
    Font.Style = [fsBold]
    ParentFont = False
  end
  object Label4: TLabel
    Left = 8
    Top = 487
    Width = 103
    Height = 16
    Caption = #1057#1085#1072#1095#1072#1083#1072' Parent'
    Font.Charset = RUSSIAN_CHARSET
    Font.Color = clWindowText
    Font.Height = -13
    Font.Name = 'Arial'
    Font.Style = [fsBold]
    ParentFont = False
  end
  object Label5: TLabel
    Left = 130
    Top = 487
    Width = 98
    Height = 16
    Caption = #1057#1085#1072#1095#1072#1083#1072' Name'
    Font.Charset = RUSSIAN_CHARSET
    Font.Color = clWindowText
    Font.Height = -13
    Font.Name = 'Arial'
    Font.Style = [fsBold]
    ParentFont = False
  end
  object Label6: TLabel
    Left = 252
    Top = 487
    Width = 65
    Height = 16
    Caption = #1041#1077#1079' Name'
    Font.Charset = RUSSIAN_CHARSET
    Font.Color = clWindowText
    Font.Height = -13
    Font.Name = 'Arial'
    Font.Style = [fsBold]
    ParentFont = False
  end
  object Panel1: TPanel
    Left = 8
    Top = 8
    Width = 375
    Height = 418
    Caption = 'Panel1'
    TabOrder = 1
    object Edit1: TEdit
      Left = 328
      Top = 390
      Width = 41
      Height = 19
      TabOrder = 0
      Text = 'Edit1'
    end
  end
  object Button1: TButton
    Left = 8
    Top = 509
    Width = 110
    Height = 27
    Caption = 'TEdit.Create(Self)'
    TabOrder = 2
    OnClick = Button1Click
  end
  object Button2: TButton
    Left = 8
    Top = 547
    Width = 110
    Height = 25
    Caption = 'TEdit.Create(nil)'
    TabOrder = 3
    OnClick = Button2Click
  end
  object lbComponents: TListBox
    Left = 435
    Top = 30
    Width = 146
    Height = 542
    ItemHeight = 16
    TabOrder = 8
  end
  object lbControls: TListBox
    Left = 600
    Top = 30
    Width = 151
    Height = 542
    ItemHeight = 16
    TabOrder = 9
  end
  object edtName: TEdit
    Left = 48
    Top = 445
    Width = 121
    Height = 24
    TabOrder = 0
    Text = 'NewName'
  end
  object Edit2: TEdit
    Left = 336
    Top = 432
    Width = 43
    Height = 19
    TabOrder = 10
    Text = 'Edit2'
  end
  object Button3: TButton
    Left = 130
    Top = 509
    Width = 110
    Height = 27
    Caption = 'TEdit.Create(Self)'
    TabOrder = 4
    OnClick = Button3Click
  end
  object Button4: TButton
    Left = 130
    Top = 547
    Width = 110
    Height = 25
    Caption = 'TEdit.Create(nil)'
    TabOrder = 5
    OnClick = Button4Click
  end
  object Button5: TButton
    Left = 252
    Top = 509
    Width = 110
    Height = 27
    Caption = 'TEdit.Create(Self)'
    TabOrder = 6
    OnClick = Button5Click
  end
  object Button6: TButton
    Left = 252
    Top = 547
    Width = 110
    Height = 25
    Caption = 'TEdit.Create(nil)'
    TabOrder = 7
    OnClick = Button6Click
  end
end


28-06-2009 03:27
Спасибо за ответ. Идея использовать массив мне приходила самому, но не понравилась. Конкретно меня интересовало что-то типа использования FindComponent. Я видел такие примеры раньше, но забывал постоянно из-за нечастого программирования подобных задач. Для себя использовал это следующим образом:
for i:=1 to ... do
    begin
    (Form1.FindComponent('MemoV'+IntToStr(i)) as TMemo).Lines.Clear;
    (Form1.FindComponent('MemoV'+IntToStr(i)) as TMemo).Lines.Append(...);
    (Form1.FindComponent('CheckBox'+IntToStr(i)) as TCheckBox).Checked:=...;
    end;
Спасибо за ответ. Надеюсь запомнить это теперь на долго).

28-06-2009 01:56
Для начала немного теории.

Все компоненты (т.е. наследники TComponent), которые помещаются на форму, могут иметь своего владельца. Владельцем может быть любой другой компонент. Компонен-владелец указывается в качестве параметра конструктора вновь создаваемого компонента и, за исключением очень экзотических случаев, остаётся неизменным на протяжении всего времени жизни этого компонента. Когда компонент-владелец уничтожается, он авоматически уничтожает все компоненты, которыми владеет. Владельцем всех созданных на форме в design-time компонентов становится сама форма.

У каждого компонента есть свойство Name, в котором хранится имя компонента, присвоенное ему при создании. У компонентов, созданных в design-time, это имя совпадает с именем поля формы, которое создаётся средой для данного компонента. Но при этом надо помнить, что совпадение имени переменной и значения свойства Name - это не универсальный закон. Это правило выполняется только для компонентов, созданных в design-time, к которым обращаются через те поля, которые создала сама среда. А если, например, вы создаёте компонент в run-time, то его поле Name по умолчанию имеет пустое значение. Если вы хотите, чтобы такой компонент имел имя, вы должны присвоить значение полю Name вручную. При этом вы сами должны следить за уникальностью этого имени, так как VCL не запрещает различным компонентам иметь одно и то же значение свойства Name, даже если эти компоненты имеют одного владельца.

Для доступа к компонентам, которыми владеет компонент, существуют два свойства: ComponentCount типа Integer и индексированное свойство Components, которое возвращает владеемый компонент с заданным номером. Пройдя по списку Components от 0 до ComponentCount-1, мы можем получить ссылки на все компоненты, которыми он владеет.

Поиск компонента по имени автоматизирован: в классе TComponent существует функция FindComponent, которая возвращает ссылку на компонент с заданным именем из числа тех, которыми владеет данный компонент. Если компонентов с таким именем несколько, FindComponent

Вспоминая о том, что владельцем всех созданных в design-time компонентов является форма, получаем такой код для решения вашей задачи (этот код должен быть размещён в одном из методов формы; в противном случае обращение к методу FindComponent должно включать в себя ссылку на форму, для которой он вызывается):

var
  MyEdit: TEdit;
...
for I := 1 to 10 do
begin
  MyEdit := FindComponent('Edit' + IntToStr(I)) as TEdit;
  // Теперь в MyEdit хранится ссылка на требуемый TEdit.
  // Делаем с ним всё, что нужно
end;


Это очень схематичный код. Он не учитывает двух возможных ситуаций. Во-первых, компонента с заданным именем может вообще не существовать на форме (в этом случае FindComponent вернёт nil). Во-вторых, из-за ручных манипуляций с полем Name может оказаться, что имя вида 'Edit<N>' получит и ещё какой-нибудь компонент с типом, отличным от TEdit (в этом случае попытка прведения найденного компонента к типа TEdit при помощи as даст исключение). Чтобы этот код стал надёжным, надо вставить дополнительные проверки, отслеживающие данные ситуации. Я предлагаю вам следать это самостоятельно.

Метод FindComponent устроен внутри очень просто: он в цикле перебиает все элементы списка Components, пока не дойдёт до элемента с заданным именем. Понятно, что в приведённом ваше коде получается два цикла: внешний, написанный нами, и вложенный, который выполняется внутри FindComponent. Если на форме много компонентов, а искомые компоненты лежат в конце списка, это здорово снижает производительность. Поэтому FindComponent обычно применяют для поиска одиночного компонента, а не нескольких компонентов в цикле. Хочется обойтись одним циклом по массиву компонентов. Сделать это можно примерно так (чтобы этот пример откомпилировался, необходимо подключить модуль StrUtils):

var
  MyEdit: TEdit;
  EditNumber: Integer;
...
for I := 0 to ComponentCount - 1 do
if (Components[I] is TEdit) and
  AnsiStartsStr('Edit', Components[I].Name) and
  TryStrToInt(Copy(Components[I].Name, 5, MaxInt), EditNumber) and
  (EditNumber >= 1) and (EditNumber <= 10) then
begin
  MyEdit := Components[I] as TEdit; // Здесь дополнительные проверки не нужны, всё уже проверено
  // Делаем с MyEdit всё, что нужно
end;


Слабое в смыле производительности место этого варианта - затратные операции со строками. Правда, если отключена опция компилятора Complete boolean eval (а по умолчанию она как раз отключена), эти операции будут выполняется не на каждом шаге цикла, а только в том случае, когда очередной компонент из списка - TEdit. Тем не менее, если на форме много TEdit'ов и практически нет других компонентов, данный способ может оказаться даже более затратным, чем первый, особенно если интересующие вас компоненты находятся близко к началу списка, и FindComponent отрабатывает быстро.

Как же обойтись без операций над строками? В этом нам может помочь ствойство Tag, которое есть у каждого компонента. Это целочисленное свойство, которое никак не используется стандартными классами. Сделано оно специально для того, чтобы вы могли записывать туда любое значение и использовать его по своему усмотрению. По умолчанию Tag=0. Записываем в design-time в свойства Tag интересующих вас TEdit'ов значения от 1 до 10 и следим, чтобы Tag никакого другого TEdit'а не получил значение из этого диапазона. Тогда можно использовать такой код:

for I := 0 to ComponentCount - 1 do
if (Components[I] is TEdit) and (Components[I].Tag >= 1) and (Components[I].Tag <= 10) then
begin
  MyEdit := Componets[I] as TEdit;
  ...
end;


Приведённый код - тоже не предел по быстродействию. Первое улучшение напрашивается сразу: надо выкинуть проверку Components[I] is TEdit. Правда, тогда нам придётся следить, чтобы вообще никакой компонент, а не только TEdit, не имел занчения свойства Tag в диапазоне 1..10. Второе улучшение связано с ситуацией, когда интересующие вас компоненты группируются в начале списка. Рассмотрим крайний случай: интересующие вас TEdit'ы занимают элементы с индексами от 0 до 9, а всего на форме 100 компонентов. Всё, что нужно, цикл выполнит на первых 10-ти итерациях, и оставшиеся 90 итераций будет заниматься заведомо бессмысленными проверками. Чтобы этого не происходило, нужно завести отдельную переменную, служащую счётчиком для найденных TEdit'ов. Перед началом цикла мы этот счётчик обнуляем, на каждом найденном TEdit'е увеличиваем на единицу, и как только он достигнет значения 10, прерываем цикл с помощью Break (кстати, аналогичную оптимизацию можно сделать и для второго варианта). Правда, такая модификация может дать обратный эффект, если искомые компоненты находятся в конце списка. Так, если один из искомых компонентов стоит последним в списке, количество итераций цикла вообще не уменьшится, а время работы увеличится из-за дополнительных проверок.

Недостаток этого метода - то, что надо внимательно следить за занчением свойства Tag. Если вам придётся модифицировать этот код спустя несколько лет, или же этим будет заниматься вообще другой человек, будет не очень просто сразу восстановить логику работы.

Не следует забывать и о том, что каждый визуальный компонент имеет ещё и родителя, который определяется значением свойства Parent. Родитель - это компонент, который визуально содержит данный компонент. Например, родителем компонентов, положенных непосредственно на форму, становится сама форма. А родителем компонентов, положенных на панель (TPanel), становится эта панель. Родитель (им может быть любой наследник TWinControl) имеет свойства ControlCount и Controls, аналогичные ComponentCount и Components, но служащие для перечисления дочерних визуальных компонентов. Существует так же и аналогичная функция FindControl, так что все перечисленные выше методы могут быть модифицированы для поиска в списке Controls. Преимуществ у поиска в Controls перед поиском в Components два. Во-первых, список Controls любого компонента-контейнера на форме будет короче, чем список Components формы, что даст выигрыш в скорости. Во-вторых, компоненты, над которыми требуется выполнить одинаковые действия, часто и визуально размещаются в одном контейнере, что позволяет сократить число проверок. Например, если все интересующие вас TEdit'ы расположены на одной панели, и больше на этой панели никаих TEdit'ов нет, вы можете просто пройти по Controls этой панели, тупо выбрать все TEdit'ы, и не проверяя ни имя, ни Tag, выполнить нужное действие. Однако у этого способа есть два серьёзных ограничения. Он не применим, во-первых, для поиска невизуальных компонентов, а во-вторых, для поиска компонентов, у которых разные родители.

И, наконец, самый быстрый способ. Заводите в классе формы поле MyEdits: array[1..10] of TEdit, а в обработчике OnCreate пишете такой код:

MyEdits[1] := Edit1;
MyEdits[2] := Edit2;
MyEdits[3] := Edit3;
MyEdits[4] := Edit4;
MyEdits[5] := Edit5;
MyEdits[6] := Edit6;
MyEdits[7] := Edit7;
MyEdits[8] := Edit8;
MyEdits[9] := Edit9;
MyEdits[10] := Edit10;


Теперь в любой момент практически без дополнительных издержек вы можете обратиться к нужному вам TEdit'у через массив MyEdits. Перебрать все его элементы в цикле тоже не составит труда. Правда, если таких TEdit'ов будет не 10, а, например, 100, писать все присваивания будет несколько утомительно, но если производительность для вас очень критична, а групповые операции выполняются часто, эти затраты того стоят.

Думаю, теперь, когда вы знакомы с достоинствами и недостатками различных способов, вы легко выберете тот из них, который лучше всего подходит для вашей задачи.

Добавьте свое cообщение

Вашe имя:  [Войти]
Ваш адрес (e-mail):На Королевстве все адреса защищаются от спам-роботов
контрольный вопрос:
Жил-был у бабушки серенький КТО?
в качестве ответа на вопрос или загадку следует давать только одно слово в именительном падеже и именно в такой форме, как оно используется в оригинале.
Надоело отвечать на странные вопросы? Зарегистрируйтесь на сайте.
Тип сообщения:
Текст:
Жирный шрифт  Наклонный шрифт  Подчеркнутый шрифт  Выравнивание по центру  Список  Заголовок  Разделительная линия  Код  Маленький шрифт  Крупный шрифт  Цитирование блока текста  Строчное цитирование
  • вопрос Круглого стола № XXX

  • вопрос № YYY в тесте № XXX Рыцарской Квинтаны

  • сообщение № YYY в теме № XXX Базарной площади
  • обсуждение темы № YYY Базарной площади
  •  
     Правила оформления сообщений на Королевстве

    Страница избранных вопросов Круглого стола.
      
    Время на сайте: GMT минус 5 часов

    Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter.
    Функция может не работать в некоторых версиях броузеров.

    Web hosting for this web site provided by DotNetPark (ASP.NET, SharePoint, MS SQL hosting)  
    Software for IIS, Hyper-V, MS SQL. Tools for Windows server administrators. Server migration utilities  

     
    © При использовании любых материалов «Королевства Delphi» необходимо указывать источник информации. Перепечатка авторских статей возможна только при согласии всех авторов и администрации сайта.
    Все используемые на сайте торговые марки являются собственностью их производителей.

    Яндекс цитирования