Версия для печати
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум на Исходниках.RU > Все языки: Статьи, заготовки в FAQ > In-place создание массива из констант/переменных


Автор: Fr0sT 27.11.13, 12:05
In-place создание массива из констант

Этот метод мне подсказал, кажется, leo, за что ему респект.

Задача:
Иногда бывает нужно сделать перебор ряда однотипных переменных. Самый распространенный пример - массовое управление группами контролов
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    Button1.Enabled := False;
    Button3.Enabled := False;
    Button5.Enabled := False;


Лично мой взор неуемного оптимизатора сия конструкция оскорбляет, но на первый взгляд от нее никуда не деться - разве что чере временный массив, но и его придется заполнять по одному. Конструкция [item1, item2, ...] работает только в параметрах подпрограмм - ну а создавать отдельную процедуру для одного действия тоже не хочется.
К счастью, есть и другой, хитрый способ получить переменную дин. массива, а именно:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    <dyn_array_type>.Create(item1, item2, ...)


Для нашего случая:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    var
      btn: TButton;
    ...
      for btn in TArray<TButton>.Create(Button2, Button6, Button7) do
        btn.Enabled := False;

либо получаем для неоднократного последующего применения
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    var
      i: Integer;
      BtnGroup1: TArray<TButton>;
    ...
      BtnGroup1 := TArray<TButton>.Create(Button2, Button6, Button7);
      ...
      for i := Low(BtnGroup1) to High(BtnGroup1) do
       BtnGroup1[i].Enabled := False;

А можно и для разношерстных контролов
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    var
      comp: TControl;
    ...
      for comp in TArray<TControl>.Create(Button2, Button6, CheckBox3) do
        comp.Enabled := False;


Работает и без generics, но тип дин. массива обязательно должен быть предварительно объявлен:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    type
      TArrayButton = array of TButton;
    var
      btn: TButton;
    ...
      for btn in TArrayButton.Create(Button1, Button2) do
        btn.Enabled := False;

Автор: SPM 27.11.13, 18:11
Цитата
Лично мой взор неуемного оптимизатора
стесняюсь спросить, а что тут оптимизировано?

Автор: Fr0sT 28.11.13, 06:10
SPM, куча однотипных действий выполняется не копипастой, а циклом, как и положено однотипным действиям. Оптимизация скорее на уровне исходника, чем машинного кода.

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

Автор: Filka 23.12.13, 05:22
Цитата Fr0sT @
Работает и без generics, но тип дин. массива обязательно должен быть предварительно объявлен

Можно же использовать Open array parameters...

Автор: Fr0sT 23.12.13, 06:28
Цитата Filka @
Можно же использовать Open array parameters...

Как оно применимо к данной ситуации?

Автор: Filka 23.12.13, 06:36
Например, так:
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    procedure SetEnabledBtn(const BtnArr: array of TButton; Value: Boolean);
    var
      I: Integer;
    begin
      for I := Low(BtnArr) to High(BtnArr) do
        BtnArr[I].Enabled := Value;
    end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      SetEnabledBtn([Button2, Button3, Button4], False);
    end;

Автор: Fr0sT 23.12.13, 07:24
Filka, отдельная процедура занимает больше места, чем объявление типа). К тому же что, если понадобится менять не только enabled, а, например, еще и visible?

Автор: Filka 23.12.13, 07:32
Цитата Fr0sT @
отдельная процедура занимает больше места, чем объявление типа
И что?

Цитата Fr0sT @
если понадобится менять не только enabled, а, например, еще и visible?
В процедуре и менять...

Зато Open array parameters есть в любой версии Delphi...

Автор: Fr0sT 24.12.13, 06:30
Filka, я ж и не спорю, что решить задачу можно несколькими способами. Просто делюсь более неочевидным.

Автор: Filka 24.12.13, 06:38
Я тоже не спорю. Я просто хотел сказать, что подобное можно сделать и в старых версиях Delphi.

Автор: Fr0sT 24.12.13, 06:43
Вариант без generics тоже, возможно, сработает - мне не на чем проверить.

Автор: leo 24.12.13, 06:44
Цитата Fr0sT @
К тому же что, если понадобится менять не только enabled, а, например, еще и visible?
Цитата Fr0sT @
В процедуре и менять...
Зато Open array parameters есть в любой версии Delphi...

Ну можно еще использовать универсальную функцию просто для создания и инициализации массива контролов в рамках подхода Fr0sT
<{CODE_COLLAPSE_OFF}><{CODE_WRAP_OFF}>
    type
      TCtlArray = array of TControl;
    function GetCtlArray(Controls:array of TControl):TCtlArray;
    begin
      SetLength(Result,High(Controls)+1);
      Move(Controls[0],Result[0],SizeOf(TControl)*(High(Controls)+1));
    end;

Автор: Filka 24.12.13, 06:47
Цитата Fr0sT @
Вариант без generics тоже, возможно, сработает - мне не на чем проверить.

Например, в D7 не сработает, т.к. там нет конструкторов у дин. массивов.

Powered by Invision Power Board (https://www.invisionboard.com)
© Invision Power Services (https://www.invisionpower.com)