Мастера DELPHI, Delphi programming community Рейтинг@Mail.ru Титульная страница Поиск, карта сайта Написать письмо 
| Новости |
Новости сайта
Поиск |
Поиск по лучшим сайтам о Delphi
FAQ |
Огромная база часто задаваемых вопросов и, конечно же, ответы к ним ;)
Статьи |
Подборка статей на самые разные темы. Все о DELPHI
Книги |
Новинки книжного рынка
Новости VCL
Обзор свежих компонент со всего мира, по-русски!
|
| Форумы
Здесь вы можете задать свой вопрос и наверняка получите ответ
| ЧАТ |
Место для общения :)
Орешник |
Коллекция курьезных вопросов из форумов
KOL и MCK |
KOL и MCK - Компактные программы на Delphi
 
По материалам: http://www.kuban-fans.ru.

Массив из элементов - как с ним бороться или как с ним дружить

  Однажды я опубликовал на Мастерах статью, в которой создавались массивы из различных компонентов, вплоть до форм. Письма, полученные мною после опубликования, были посвящены зачастую не основной теме статьи, а вопросам по созданию массивов из объектов. Здесь я постараюсь ответить на задаваемые вопросы «оптом». Я не претендую на истину в последней инстанции, но, думаю, что этот материал может быть кому-то полезен:). Здесь информация о

Создание массива

  Ну тут всё просто. Объявляем

var Arr: array[1..n] of TEdit; //к примеру
и можно работать!
Так-же можно объявить и многомерный и даже динамический массив.
var Arr1: array [1..7, 1..5] of TEdit;
  var Arr2: array of TEdit;

Работа с массивом

Опасно не падать, а биться о землю, скалы и другие твёрдые предметы.
(альпинистско - парашютистская мудрость).

  Итак, с созданным массивом надо что-то делать. Ну, для начала, чем-то заполнить. А, в отличие от чисел и строк, которые задаются в виде констант и выражений, объекты, помещаемые в наш массив, нужно создавать. Т.е. если мы описали

var ByteArr: array[1..2] of byte;
то можно написать
ByteArr[1]:=3;

  Что же писать после := для массива из объектов? Их же как-то создать надо? (из форума)
Здесь у нас есть два пути - создавать объекты с помощью Create во время работы программы или использовать объекты, созданные во время проектирования формы. Каждый путь имеет своих путников (почти по Мао - дзе -дуну).

Заполнение массива во время работы программы.

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

   For i:=<начальное значение> to<конечное значение> do begin
    <имя массива>[i]:=<имя класса>.Create(Self);
    <имя массива>[i].Parent:=Self; //за объект ответит форма, на которой он создан
    //<присвоение других свойств - по необходимости>
   end; 
После этих действий у нас на форме появятся необходимые компоненты, к которым можно обращаться, используя индекс массива, например так: <имя массива>[i].

  В следующем примере по щелчку по кнопке будет предложено ввести требуемое количество полей, которое и будет создано в центре формы.

procedure TForm1.Button1Click(Sender: TObject);
var c: string;
     i,n:integer;
begin
 c := InputBox('Введите','число:','7');
 try
  n := StrToInt(c);
 except
  on EConvertError do ShowMessage('Что-то не срослось...');
 end;//Try
 SetLength(Arr2, n);
  for i:=0 to n-1 do begin
   Arr2[i] := TEdit.Create(Self);
   Arr2[i].Parent := Self;
   //Эти две строки создают компонент, далее произвольные действия.
   Arr2[i].Top:=i*Arr2[i].Height;
   Arr2[i].Left:=(ClientWidth-Arr2[i].Width)div 2 ;
   Arr2[i].Text:='Поле '+IntToStr(i);
  end;//for
 Button1.Visible:=FormArraylse;
end;

  При заполнении многомерного массива компонентов таким способом никаких подводных камней нет - организуем несколько циклов.

procedure TForm1.FormCreate(Sender: TObject);
var i, j: byte;
begin
  for i:=1 to 7 do
   for j:=1 to 5 do begin
   Arr1[i,j]:=TEdit.Create(Self);
   Arr1[i,j].Parent := Self;
  //Эти две строки создают компонент, далее произвольные действия.
   Arr1[i,j].Top:=(i-1)*Arr1[i,j].Height;
   Arr1[i,j].Left:=(j-1)*Arr1[i,j].Width;
   Arr1[i,j].Text:='Поле '+ IntToStr(i*j);
                        end;//for j
  end;

  Результат - таблица из Edit`ов, с индексированными ячейками.

  Таким образом можно создать даже массив из форм. Разместим форму для создаваемого массива в Unit2.

uses Unit2;//задействуем его
var FormArray: array [1..5] of TForm2;
 //Теперь нам нужно создать массив FormArray, разместить его на главной форме и заполнить его изображениями.
 //Делать это лучше не во время создания формы, а например во время активации.
 procedure TForm1.FormActivate(Sender: TObject);
 var i: byte;
 begin
  for i:=1 to 5 do begin
   FormArray[i]:=TForm2.Create(Self);
   FormArray[i].Parent:=Self;// Создание формы
   // и что-то с ней делаем
   FormArray[i].Visible:=True; //Вывод формы на экран
   FormArray[i].Top:=i*50//Выбор места расположения (здесь ставятся ваши значения)
                       end;//for
 end;

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

Использование объектов, созданных во время проектирования формы

  Раньше как было - код, компиляция, запуск, а лицо невесты можно увидеть только после свадьбы. Сейчас всё намного гуманнее. Есть проект, в нём форма, а на форму ставишь компоненты. И почему бы их не «объединить» в массиве?

  Итак, на вашу форму во время проектирования помещено несколько Edit`ов, и вы хотите присвоить их элементам массива Arr.
Можно конечно написать Arr[1]:=Edit1; Arr[2]:=Edit2; и т.д., но это как-то не хорошо:(.
Значительно лучше просмотреть существующие компоненты и, если компонент - TEdit, поместить его в массив. Вот так:

   procedure TForm1.FormCreate(Sender: TObject);
   var i, j: byte;
   begin
    j:=1;
    for i:=0 to ComponentCount-1 do //просматриваем
     if (Components[i] is TEdit) then begin //если подходит
      Arr[j]:=(Components[i] as TEdit);//помещаем
      j:=j+1;
                                                   end;//if
   // а теперь посмотрим, в каком порядке они попали в массив
    for i:=1 to 5 do
     Arr[i].Text:='Arr['+IntToStr(i)+']';
   end;

  На самом деле, такой способ не намного менее коряв, чем присваивание «напрямую». В массив попадут все Edit`ы, присутствующие на форме, причём в порядке их создания. А как быть, если хочется поместить их не все и в своём порядке?
Очевидно, надо указать где-то, кого и в каком порядке мы хотим видеть принятым в члены массива. Под это где-то хорошо заточено свойство Tag - есть у любого компонента, целое число, используется «без вопросов». На этапе проектирования укажите в Tag`е, на каком месте в массиве вы хотите видеть данный компонент. Затем используйте следующий код:

   procedure TForm1.FormCreate(Sender: TObject);
   var i: byte;
   begin
    for i:=0 to ComponentCount-1 do
     if Components[i].Tag>0 then //Tag больше нуля
      Arr[Components[i].Tag]:=(Components[i] as TEdit);//Значит клиент наш!
   end.

  Смотрится значительно лучше. Для организации двух массивов пронумеруйте (протагируйте) компоненты, предназначенные для помещения в первый из массивов как обычно, а во второй, например, с десяти (или с любого другого числа, желательно с круглого - проще считать). Затем напишите что нибудь вроде

var Arr1: array [1..3] of TEdit;
    Arr2: array [1..3] of TEdit;
   procedure TForm1.FormCreate(Sender: TObject);
   var i: byte;
   begin
    for i:=0 to ComponentCount-1 do
     if Components[i].Tag>0 then 
      if Components[i].Tag<10 then
       Arr1[Components[i].Tag]:=(Components[i] as TEdit)
                                          else
       Arr2[Components[i].Tag-10]:=(Components[i] as TEdit);
    end;

  При создании многомерного массива используем тот-же приём - немного поработаем с тагом. Edit`ы протагированы 11.12.13.21.22.23:

var Arr1: array [1..3,1..2] of TEdit;

procedure TForm1.FormCreate(Sender: TObject);
var i, j: byte;
begin
 for i:=0 to ComponentCount-1 do
  if Components[i].Tag>0  then
   Arr1[Components[i].Tag mod 10,Components[i].Tag div 10 ]:=(Components[i] as TEdit);
//убедимся,  что всё получилось
for i:=1 to 3 do
 for j:=1 to 2 do
  arr1[i,j].text := IntToStr(i)+' '+IntToStr(j);
end;

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

var ArrE: array [1..3] of TEdit;
     ArrC: array [1..8] of TComboBox;
procedure TForm1.FormCreate(Sender: TObject);
var i: byte;
begin
for i:=0 to ComponentCount-1 do
if Components[i].Tag>0 then begin
 if (Components[i] is TEdit)
  then ArrE[Components[i].Tag]:=(Components[i] as TEdit);
 if (Components[i] is TComboBox)
  then  ArrC[Components[i].Tag]:=(Components[i] as TComboBox);
                                          end;//if
end;

  При необходимости создания более сложных массивов - комбинируйте эти способы.

  Лирическое отступление. Присвоение объектов происходит не совсем так, как у «обычных» переменных. Если у переменных присваивние не отоджествляет переменные т.е. после a:=3;b:=a;a:=5; в переменной b находится 3, а не 5, то с объектами всё наоборот. После ArrL[1]:=Label1; ArrL[1] и Label1 cтановятся одним объектом, и например ArrL[1].Caption:='Вася'; изменит надпись Label1. В некоторых языках для разруливания этой ситуации для блондинок введён специальный оператор присваивания объектов (Vb, set). Ну мы то, Дельфийцы, народ умный...

Получение номера элемента массива в процедуре обработки события

  Чтобы узнать индекс элемента массива, с которым произошло событие придётся придётся сравнить переменную Sender, использующуюся обработчиком события, со всеми элементами массива и при совпадении извлечь индекс. Похоже только так... Впрочем, может кто знает и лучший способ.

var ArrB: array [1..3] of TButton;
    n: byte;// Здесь будет храниться индекс
procedure TForm1.Clicker(Sender:TObject);
var i: byte;
begin
 for i:=1 to 3 do
  if Sender = ArrB[i] then n:=i;
  //находим индекс компонента, к которому относится событие
 ShowMessage('Нажата кнопка '+IntToStr(n)); //что-то делаем
end;

procedure TForm1.FormCreate(Sender: TObject);
var i: byte;
begin
 for i:=0 to ComponentCount-1 do
  if Components[i].Tag > 0
   then ArrB[Components[i].Tag]:=(Components[i] as TButton);//наполняем массив
 for i:=1 to 3 do
  ArrB[i].OnClick:=Clicker; //устанавливаем обработчик
end;

  Ну, как говорится, спасибо за внимание. Ижогин Ян Валерьевич.

   Внимание! Запрещается перепечатка данной статьи или ее части без согласования с автором. Если вы хотите разместить эту статью на своем сайте или издать в печатном виде, свяжитесь с автором.
Автор статьи:  Ижогин Ян Валерьевич
  

Другие статьи Наверх


  Рейтинг@Mail.ru     Титульная страница Поиск, карта сайта Написать письмо