Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
Урок 13 - Жизнь и смерть в режиме RunTime на KOL

Ведущий раздела KOL и MCK: Анатолий aka XVeL
Автор: Борис Моренко
WEB-сайт: http://kol.mastak.ru

Полную версию библиотеки KOL и MCK можно скачать здесь.

13 урок... Если вы суеверный можете не читать :) В этом разделе у нас будет немного мистики и чертовщины (Кнопки и прочие контролы интерфейса будут возникать и пропадать неоткуда). В общем если вы немного Гарри Потерр данный монолог будет вам интересен :)

В форуме уже звучали вопросы про "динамическое" создание кнопок. Если ваш проект на VCL то глоток знаний по данному вопросу можно получить на сайте Королевство DELPHI в статья "Жизнь и смерть в режиме run-time" (надеюсь автор статьи не обвинит меня в плагиате).
Рекомендую вам прочесть данный опус для общего развития и потому что фактически все ниже изложенное вытекает из этого произведения.

Что бы понять отличия от VCL в данном вопросе надо уяснить 2 вещи :

  1. У объектов нет свойства Name (поэтому вы не сможете их искать через FindComponent)
  2. Все изменения вытекают из 1-го пункта :)

При создание объекта на уже работающем окне вам кроме обычного конструктора надо сделать обращение к CreateWindow.
Пример :

// form - родительский объект на котором создается контрол
NewBigButton := NewButton(form, 'КНОПКА');
NewBigButton.CreateWindow;

Если все нормально CreateWindow возвращает true. Так что если вы "правильный" программист неплохо бы эту функцию вызывать c проверкой через IF.

"Родительский" объект "нумерует" все объекты которые вы создаете на нем.
Для того что бы узнать под каким номером идет ваш "дочерний" объект нужно обратившись к свойству ChildIndex. А если вам известен номер "дочернего" объекта то вы сможете обратится к нему через свойство Children.
Пример :

var
  i: Integer;
...
// form - родительский объект
NewBigButton := NewButton(form, 'КНОПКА');
NewBigButton.CreateWindow;
i := form.ChildIndex(NewBigButton); // получаем номер объекта
form.Children(i).caption := ' Это кнопка'; // обращаемся к тому же NewBigButton


Количество дочерних объектов узнается с помощью ChildCount. Таким образом можно устроить "перебор" всех дочерних объектов определенного контрола.

Наверное у некоторых читателей может возникнуть вопрос: к чему мне все эти "номера дочерних объектов"?
Ответ на вопрос лежит на поверхности. Если вы создаете ваши контролы динамически(их количество не определено заранее) вы не сможете обратится к ним другим способом только как через его номер.
При этом надо учесть что номера объектов сдвигается если ранее созданный объект удален.

Для того что бы создаваемые вами визуальные объекты имели дополнительную информацию можно использовать свойство Tag. В него можно заносить любое целое число. В ниже приведенном примере в Tag заносится константа которая указывает на "функциональный тип" объекта (кнопка, EditBox и т.д.)

program Primer13;

uses
  kol,
  messages,
  windows;

{$R *.RES}
var
  form, butNewElement, lebDel, edNoDel, butDelElement, gb,
    rbButton, rbEditBox, rbRadioBox, rbCheckBox: pControl;
  new: pControl;
  Nomer: integer;

const
  cButton = 1;
  cEditBox = 2;
  cRadioBox = 3;
  cCheckBox = 4;

procedure ClickElemet(Dummy: Pointer; Sender: PControl);
begin
  case Sender.Tag of
    cButton: ShowMessage('Нажата кнопка - № ' + Int2Str(form.ChildIndex(Sender)));
    cRadioBox: ShowMessage('Нажата RadioBox - № ' + Int2Str(form.ChildIndex(Sender)));
    cCheckBox: ShowMessage('Нажат CheckBox - № ' + Int2Str(form.ChildIndex(Sender)));
  end; {case}
end;

procedure ClickButMakeButton(Dummy: Pointer; Sender: PControl);
begin
 // Фактически самая главная функция.
 // В зависимости от того какой RadioBox выбран создаем
 // определенного вида объект

  if rbButton.Checked then
  begin
    new := NewButton(form, '');
    new.Width := 100;
    new.Caption := 'Button №' + int2Str(form.ChildIndex(new));
    new.Tag := cButton;
  end
  else
    if rbEditBox.Checked then
    begin
      new := NewEditBox(form, []);
      new.Text := 'EditBox №' + int2Str(form.ChildIndex(new));
      new.Tag := cEditBox;
    end
    else
      if rbRadioBox.Checked then
      begin
        new := NewRadioBox(form, '');
        new.Caption := 'RadioBox №' + int2Str(form.ChildIndex(new));
        new.Width := 100;
        new.Tag := cRadioBox;
      end
      else
        if rbCheckBox.Checked then
        begin
          new := NewCheckBox(form, '');
          new.caption := 'CheckBox №' + int2Str(form.ChildIndex(new));
          new.Width := 100;
          new.Tag := cCheckBox;
        end;

  new.CreateWindow;

 // ------- располагаем по красивее новый контрол -------
  new.Left := 10;
  inc(Nomer);
 // так как все 4 элемента имеют одинаковую высоту...
  new.Top := Nomer * new.Height;
 // ------------------------------------------------------

  new.OnClick := TOnEvent(MakeMethod(nil, @ClickElemet));
end;
//////////////////////////////////////////////////////////////////////////

procedure ClickDelElemet(Dummy: Pointer; Sender: PControl);
begin
  form.Children[Str2Int(edNoDel.Text)].free;
end;
//////////////////////////////////////////////////////////////////////////
begin
  Applet := NewApplet('RunTime');
  Applet.Font.FontName := 'Arial';
  Applet.Font.FontWidth := 15;
  form := NewForm(Applet, 'Создание в режиме RunTime элементов интерфейса').SetSize(600, 450);
  form.CenterOnParent;

//--------------------------- рисуем интерфейс ---------------------------
  gb := NewGroupBox(form, 'Выберите').SetAlign(caRight);
  gb.Width := 100;

  rbButton := NewRadioBox(gb, 'Button').SetAlign(caTop);
  rbEditBox := NewRadioBox(gb, 'EditBox').SetAlign(caTop);
  rbRadioBox := NewRadioBox(gb, 'RadioBox').SetAlign(caTop);
  rbCheckBox := NewRadioBox(gb, 'CheckBox').SetAlign(caTop);

 // главная кнопка
  butNewElement := NewButton(gb, 'Создать');
  butNewElement.Width := 110;
  butNewElement.Align := caTop;
  butNewElement.OnClick := TOnEvent(MakeMethod(nil, @ClickButMakeButton));

  butDelElement := NewButton(gb, 'Удалить').SetAlign(caBottom);
  butDelElement.OnClick := TOnEvent(MakeMethod(nil, @ClickDelElemet));
  edNoDel := NewEditBox(gb, []).SetAlign(caBottom);
  edNoDel.Text := '1';
  lebDel := NewWordWrapLabel(gb, 'Номер удаляемого элемента').SetAlign(caBottom);
 //------------------------------------------------------------------------

  run(Applet);
end.
Размер кода 3,3 Кб. Размер программы 31,5 Кб (без сжатия и замены модулей). На экране увидите Вы примерно следующее:

P.S.
Уже когда все было написано Дмитрий Жаров aka Gandalf внес замечание по поводу того что (далее идет цитата)

>1) Есть Tag, ему можно присвоить PChar, вот так:
>obj1.Tag := Integer( 'Obj1' );

(это вырезка из переписки Gandalf с Кладовым)
Мысль очень не плохая так как дает возможность назначать контролам имена и делать поиск по ним.

Проект Delphi World © Выпуск 2002 - 2004
Автор проекта: ___Nikolay