Delphi → Компоненты в массиве TObjectList

Сен 16, 2010


Недавно, при написании одной из программ, столкнулся с проблемой большого количества элементов на форме. А именно 20 объектов TShape, 20 объектов TEdit и 100 объектов TMaskEdit.

Проблема заключается в том, что при операциях с этими элементами через программный код, его необходимо было бы тиражировать ровно столько раз, сколько этих элементов, а в каждой новой копии изменять только имя элемента (например, Edit1, Edit2 и т.д.) Недостатки такого метода достаточно серьезны: большая вероятность допустить ошибку при изменении имени в каждом блоке; в случае каких-либо изменений кода, его потребуется менять во всех блоках; исходник разрастается до тысяч строк и становится менее понятен и т.д. Обратится к элементам, как к массиву, в виде Edit[i].Text в цикле не получится.

Что же делать? Мы будем использовать класс TObjectList из модуля Contnrs, который позволит нам добавить все элементы в массив, после чего к ним можно обращаться через индекс.

uses Windows, [...], Contnrs;

Как пользоваться? Для начала необходимо добавить в раздел uses модуль Contnrs, затем для каждого типа объекта (TShape, TEdit, TMaskEdit и т.д.) определить класс на основе TObjectList.

Пример для TEdit (размещается между uses и implementation):

type
  TEditList = class(TObjectList)
  {TEditList имя нового класса, на основе TObjectList}
private
  function GetItems(Index: Integer): TEdit; {Заменить TEdit на нужный тип: TShape, TMaskEdit и т.д.}
  procedure SetItems(Index: Integer; const Value: TEdit);  {Заменить TEdit на нужный тип: TShape, TMaskEdit и т.д.}
published
public
  property Items[Index: Integer]: TEdit read GetItems write SetItems; default; {Заменить TEdit на нужный тип: TShape, TMaskEdit и т.д.}
end;

Затем добавляем объявленные функции и процедуры после строки implementation. Эти функции отвечают за установление и получение значений через оператор квадратные скобки [].

{GetItems}
function TEditList.GetItems(Index: Integer): TEdit; {Заменить TEdit на нужный тип: TShape, TMaskEdit и т.д.}
begin
  Result := TEdit(inherited GetItem(Index)); {Заменить TEdit на нужный тип: TShape, TMaskEdit и т.д.}
end;
{SetItems}
procedure TEditList.SetItems(Index: Integer; const Value: TEdit); {Заменить TEdit на нужный тип: TShape, TMaskEdit и т.д.}
begin
  inherited SetItem(Index, Value);
end;

Теперь можно объявить переменную этого класса и использовать её как массив, предварительно заполнив его нужными элементами.

Объявляем переменную EditList:

var
EditList: TEditList;

Добавляем в массив визуальные элементы (код можно разместить в событии OnCreate формы):

EditList := TEditList.Create();
EditList.Add(Edit1.Text);
EditList.Add(Edit2.Text);
EditList.Add(Edit3.Text);
EditList.Add(Edit4.Text);
...

Пример обращения к элементу Edit1.Text:

EditList[0].Text := 'TEST';

Исходный текст полностью:

unit main;

interface

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

type
  TfrmCallbase = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    Edit5: TEdit;
    Edit6: TEdit;
    Edit7: TEdit;
    Edit8: TEdit;
    Edit9: TEdit;
    Edit10: TEdit;
    Edit11: TEdit;
    Edit12: TEdit;
    Edit13: TEdit;
    Edit14: TEdit;
    Edit15: TEdit;
    Edit16: TEdit;
    Edit17: TEdit;
    Edit18: TEdit;
    Edit19: TEdit;
    Edit20: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
  public
  end;

type
TEditList = class(TObjectList)
  private
    function GetItems(Index: Integer): TEdit;
    procedure SetItems(Index: Integer; const Value: TEdit);
  published
  public
    property Items[Index: Integer]: TEdit read GetItems write SetItems; default;
  end;

var
  frmCallbase: TfrmCallbase;
  EditList: TEditList;

implementation

{$R *.dfm}

procedure TfrmCallbase.FormCreate(Sender: TObject);
begin
  EditList := TEditList.Create();
  EditList.Add(Edit1);
  EditList.Add(Edit2);
  EditList.Add(Edit3);
  EditList.Add(Edit4);
  EditList.Add(Edit5);
  EditList.Add(Edit6);
  EditList.Add(Edit7);
  EditList.Add(Edit8);
  EditList.Add(Edit9);
  EditList.Add(Edit10);
  EditList.Add(Edit11);
  EditList.Add(Edit12);
  EditList.Add(Edit13);
  EditList.Add(Edit14);
  EditList.Add(Edit15);
  EditList.Add(Edit16);
  EditList.Add(Edit17);
  EditList.Add(Edit18);
  EditList.Add(Edit19);
  EditList.Add(Edit20);

  for i:=0 to EditList.Count - 1 do
  EditList[i].Text = 'default';
end;

procedure TfrmCallbase.FormDestroy(Sender: TObject);
begin
  EditList.Free;
end;

function TEditList.GetItems(Index: Integer): TEdit;
begin
  Result := TEdit(inherited GetItem(Index));
end;

procedure TEditList.SetItems(Index: Integer; const Value: TEdit);
begin
  inherited SetItem(Index, Value);
end;

end.

Таким образом, мне удалось уменьшить функцию в 1000 строк до 46 (20 блоков по 46 строк).

Post to Twitter

Похожие статьи:

  1. Создаем компонент TCP на Winsock (Часть 2)
  2. Утечка памяти в IEnumVARIANT
  3. Многопоточность в Delphi
  4. Количество элементов в IEnumVARIANT
  5. Создаем компонент TCP на Winsock (Часть 1)

Комментарии (2)

  1. avatar

    Удав Анаконда
    Январь 30th, 2011 at 15:08 #

    Я множил Image в цикле. В примере ниже их V штук в массиве. Если количество неизвестно, то можно взять динамический массив.

    const V=10;
    type
    Imaglist = array[0..V] of Timage;

    var Imglist:Imaglist;

    // Можно сделать общее для всех событие при щелках открыть картинку

    procedure TForm1.ClickImages(Sender: TObject);
    var name:pchar;
    begin
    name:=Pchar(TImage(Sender).Hint);
    ShellExecute(Self.Handle, ‘open’, Name, nil, nil, SW_RESTORE);
    END;

    for k:=0 to V do
    BEGIN

    imglist[k]:=TImage.Create(Form1); // вот создаю

    Imglist[k].Left:=100+(k)*zx; if k=0 then Imglist[k].Left:=20;
    if k>5 then Imglist[k].Left:=100+(k — 5)*zx;
    Imglist[k].Visible:=true;
    Imglist[k].Top:=5; if k=0 then Imglist[k].Top:=20; if k>5 then Imglist[k].Top:=110;
    Imglist[k].Height:=90; if k=0 then Imglist[k].Height:=160;
    Imglist[k].Width:=90; if k=0 then Imglist[k].Width:=160;
    Imglist[k].Transparent:=false;
    Imglist[k].Parent:=Form1;
    Imglist[k].Proportional:=true;
    Imglist[k].Center:=true;

    Imglist[k].PopupMenu:=Form1.PopupMenu1;
    Imglist[k].OnContextPopup:= Form1.Image1ContextPopup;
    filename:=se; papka:=ExtractFileDir(se);
    Imglist[k].Autosize:=false;

    // вот оно общее событие
    Imglist[k].OnDblClick:=fORM1.ClickImages;

    imglist[k].Picture.LoadFromFile(se);
    end;

  2. avatar

    Малин
    Сентябрь 21st, 2011 at 16:02 #

    Может я чего не понимаю, но раз такое большое количество однородных по большому счету контролов, не проще ли их дружно поместить в грид, пусть даже и немного модифицированный чтобы отображать нетипичное содержание данных? Тогда не нужно городить форму с прокруткой элементов…

Ваш комментарий

Rambler's Top100 Яндекс.Метрика