Как передать форму в качестве параметра функции [решено]

Вопросы программирования и использования среды Lazarus.

Модератор: Модераторы

Как передать форму в качестве параметра функции [решено]

Сообщение Nik » 02.03.2011 15:09:09

Столкнулся с интересной ситуёвиной. Есть две формы, выполняющие сходные действия и имеющие частично идентичные наборы контролов. Каждый раз при показе формы нужно заполнить несколько List/Combo-боксов идентичными данным. Сейчас этот процесс реализован в лоб: для каждой формы написан свой набор функций, отвечающих за загрузку данных. По факты эти процедуры для каждой из форм идентичны примерно на 98% (отличия - в таблице БД, из которой ведётся выборка и именах пары контролов).
Выглядит примерно так:

Код: Выделить всё
procedure TAddRasForm.LoadBillsList;
[...]

procedure TAddDohForm.LoadBillsList;
[...]


Пытаюсь это дело упростить, избавившись от дублирующегося кода и сделав примерно так:

Код: Выделить всё
procedure TAddDohForm.LoadBillsList(xForm: TForm);


Но при таком варианте не удаётся обратиться к контролам формы, т.е. если обычное обращение AddDohForm.ComboBox, то в моём варианте должно было быть что-то типа xForm.ComboBox, что компилятор не проглатывает (в принципе, логично).

Конечно, можно обойтись передачей условного параметра и дальше играться с case, подставляя имена форм, но больно уж громоздко, имхо, получится. Вопрос к знатокам: можно ли как-то передавать форму (указатель на форму?) в качестве параметра функции/процедуры так, чтобы внутри функции можно было обращаться к контролам формы по именам?
Последний раз редактировалось Nik 05.03.2011 13:06:23, всего редактировалось 1 раз.
Аватара пользователя
Nik
энтузиаст
 
Сообщения: 573
Зарегистрирован: 04.02.2006 00:08:09
Откуда: Киров

Re: Как передать форму в качестве параметра функции

Сообщение Иван Шихалев » 02.03.2011 15:12:21

Код: Выделить всё
(xForm as TAddDohForm).ComboBox...

Не то?
Аватара пользователя
Иван Шихалев
энтузиаст
 
Сообщения: 1138
Зарегистрирован: 15.05.2006 11:26:13
Откуда: Екатеринбург

Re: Как передать форму в качестве параметра функции

Сообщение Nik » 02.03.2011 15:14:36

2Иван Шихалев
Вся фишка в том, что при таком варианте снова нужен case:

Код: Выделить всё
case xForm from
AddDohForm: (xForm as TAddDohForm).ComboBox...


В итоге - снова огород.
Аватара пользователя
Nik
энтузиаст
 
Сообщения: 573
Зарегистрирован: 04.02.2006 00:08:09
Откуда: Киров

Re: Как передать форму в качестве параметра функции

Сообщение Иван Шихалев » 02.03.2011 15:17:29

Другой вариант:
Код: Выделить всё
(xForm.FindComponent('ComboBox') as TComboBox)...
Аватара пользователя
Иван Шихалев
энтузиаст
 
Сообщения: 1138
Зарегистрирован: 15.05.2006 11:26:13
Откуда: Екатеринбург

Re: Как передать форму в качестве параметра функции

Сообщение Nik » 02.03.2011 15:33:14

Иван Шихалев писал(а):Другой вариант:
Код: Выделить всё
(xForm.FindComponent('ComboBox') as TComboBox)...

О! Именно то, что нужно! Спасибо! :)
Аватара пользователя
Nik
энтузиаст
 
Сообщения: 573
Зарегистрирован: 04.02.2006 00:08:09
Откуда: Киров

Re: Как передать форму в качестве параметра функции

Сообщение Kitayets » 02.03.2011 15:39:16

Выделить общего предка двух форм в виде отдельного класса и реализовать в нём функции загрузки данных в контролы (наследование).

Или создать класс загрузчик с необходимыми функциями и включить их в классы форм (агрегация/делегирование).
Kitayets
постоялец
 
Сообщения: 171
Зарегистрирован: 05.05.2010 21:15:24

Re: Как передать форму в качестве параметра функции

Сообщение Maxizar » 02.03.2011 15:43:00

Код: Выделить всё
procedure TAddDohForm.LoadBillsList(xForm: TForm);

Говорит, что при входе в процедуру LoadBillsList ей передали xForm типа TForm (а TForm - это чистая форма без всяких. ComboBox)... Ну Вы это и так знаете, из-за чего
Иван Шихалев предложил делать так:
Код: Выделить всё
(xForm as TAddDohForm).ComboBox...

Т.е мы принудительно говорим что перадали форму (но типа уверены что это нужная форма) и говорим что она имеет тип TAddDohForm... Внимание вопрос: А идентичны ли ComboBox-ы (включая названия типа ComboBoх1) у этих двух форм?... Если да то все ок. но тоже грабли...
Если же нет то второай вариант от Иван Шихалев.

Мое имхо: А не легче если они на 98% похожи.. выделить форму предка.. скажем MyOldestFormForMyApplications и именно для не написать процедуру:
Код: Выделить всё
procedure LoadBillsList(xForm: TMyOldestFormForMyApplications);

Благодоря этому мы сможем передать в эту процедуру обе формы т.к у них это общий предок..., что касается отличий ну тут наверное т.к их всего 2% легче уже сделать как метод самих форм.
Ну я понятно объяснил точку зрения?
Ой пока писал опередили :oops:
Maxizar
постоялец
 
Сообщения: 385
Зарегистрирован: 20.03.2010 19:48:14

Re: Как передать форму в качестве параметра функции

Сообщение Nik » 02.03.2011 15:49:36

2Maxizar
Первый вариант, как я выше написал, - это огород, поскольку придётся как-то проверять, что за форма вызвала функцию.

Контролы идентичны (вплоть до названий).

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

Второй вариант от Ивана Шихалеева идеально подошёл. Я уже, собственно, всё переделал и протестировал - работает без проблем, изменений в коде - минимум, код остаётся читабельным (разгребать все эти case после перерыва в пару месяцев - то ещё удовольствие :) ).
Аватара пользователя
Nik
энтузиаст
 
Сообщения: 573
Зарегистрирован: 04.02.2006 00:08:09
Откуда: Киров

Re: Как передать форму в качестве параметра функции

Сообщение Vadim » 02.03.2011 15:55:51

Nik
А может быть общие функции выделить в один inc-файл и просто включать его у каждой формы?
Vadim
долгожитель
 
Сообщения: 4112
Зарегистрирован: 05.10.2006 08:52:59
Откуда: Красноярск

Re: Как передать форму в качестве параметра функции

Сообщение Nik » 02.03.2011 17:01:08

Vadim писал(а):Nik
А может быть общие функции выделить в один inc-файл и просто включать его у каждой формы?

Вряд ли получится. Если бы проблема была только в использовании одинаковых кусков кода для работы с контролами - тогда да, inc был бы лучшим вариантом. Но у меня функции ещё и с БД работают. Есть способ определить в коде, из какого модуля был вызван inc, чтобы исходя из этого менять название, скажем, таблицы в БД?
Аватара пользователя
Nik
энтузиаст
 
Сообщения: 573
Зарегистрирован: 04.02.2006 00:08:09
Откуда: Киров

Re: Как передать форму в качестве параметра функции

Сообщение dunin » 02.03.2011 17:45:00

Что наспех в голову приходит...

Вариант первый:
Код: Выделить всё
procedure TAddDohForm.LoadBillsList(Sender: Tobject);
begin
   case Tobject(Sender).Tag of
      0: ...

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

Вариант второй:
Код: Выделить всё
procedure TAddDohForm.LoadBillsList(TabelName: string);
begin
   SQLQuery.SQL.Clear;
   SQLQuery.SQL.Add('select * from '+TabelName);
   ...

Во втором варианте не знаю что вы там делаете, но, думаю по смыслу понятно.
Аватара пользователя
dunin
энтузиаст
 
Сообщения: 634
Зарегистрирован: 02.05.2007 13:18:11
Откуда: Тољя††и

Re: Как передать форму в качестве параметра функции

Сообщение Nik » 02.03.2011 20:33:03

2dunin
Теги не используются, но имхо, так больше мороки - опять вернулись к case.

Выборка из базы примерно так и делается, но мне мало указать таблицу, надо ещё указать, в контролы какой формы вписывать результаты выборки.
Аватара пользователя
Nik
энтузиаст
 
Сообщения: 573
Зарегистрирован: 04.02.2006 00:08:09
Откуда: Киров

Re: Как передать форму в качестве параметра функции

Сообщение VirtUX » 03.03.2011 01:00:06

А что мешает передавать параметром не форму, а сам контрол TComboBox?
Аватара пользователя
VirtUX
энтузиаст
 
Сообщения: 880
Зарегистрирован: 05.02.2008 10:52:19
Откуда: Крым, Алушта

Re: Как передать форму в качестве параметра функции

Сообщение Шурик Сетевой » 03.03.2011 01:42:16

Наверное, в таких случаях следует оперировать интерфейсами, тогда экземпляр формы, реализующей интерфейс, можно передавать, как параметр без всякого приведения типов.
http://www.freepascal.org/docs-html/ref ... #QQ2-84-99

Опишите интерфейс interface IMyForm, в нем объявите процедуру LoadBillsList.
Передавайте вашей функции вызова форм в качестве параметра не экземпляр формы (param: xForm), а экземпляр, реализующий интерфейс (param: IMyForm).
Каждый класс формы, для которой требуется загрузка списков, должен будет наследовать IMyForm и реализовать собственный вариант LoadBillsList.

Внутри функции вызова вы сможете сказать param.LoadBillsList и выполнится строго реализация LoadBillsList для конкретного класса формы.

Плюсы - полностью скрывается от вызывающего кода реализация LoadBillsList, классов форм можно наплодить, сколько влезет, контроль за приведением типов выполняется при компиляции и сломать глобально ничего не получится. Очень надежный механизм.
Минусы - реализацию LoadBillsList в каждом конкретном случае придется писать собственную, ну или копи-паст. Но опять-таки - глобально ничего не сломаете, это не прямое наследование.
Шурик Сетевой
новенький
 
Сообщения: 11
Зарегистрирован: 05.03.2009 21:42:42

Re: Как передать форму в качестве параметра функции

Сообщение Maxizar » 03.03.2011 10:31:11

Nik писал(а):Форму предка создать, увы, не получится - у контролов разное расположение. Конечно, можно при создании потомка их программно раскидывать по разным углам, но это уж совсем изврат.

Хочу поспорить…. В низу исходник, главная форма + две других Form2 and Form3 при чем Form3 яв-ся предком Form2, но с другим расположение контролов (контролов родителя) Так что я буду немного спорить… Как это делать->Строим форму (родителя) с 98% нужных контролами... тестим проверяем.. Добавляем в приложение(проект) новую форму, сохроняем юнит и все такое.. компилируем. После компиляции, изменяем предка с TForm на наш.. почему сразу нельзя изменить на наш (перед компиляции) незнаю, у меня в таком случае при разных версиях лазаруса то происходит зависание отладчика то нет.. так что я всегда делаю компиляцию, а потом меняю предка и работает на 100%.. после того как поменяли предка. еще раз компилим. Ну а потом F12 у новой формы (уже с контролами родителя) и просто меняем их расположение.
Из-за чего можно делать как я написал чуть выше, через общую функцию (перекрываемую) предка.. в которой реализуем 98% общего алгоритма, и перекрываем ее в детях для реализации уже остальных 2%.. И это будет наиболее правильным подходм.
Не я сказал, что приведение типов через as и т.п трюки в RTL явл-ся мелким хаком… в некоторых случаях эти трюки просто необходимы, скажем в инспекторе обьектов, откуда вам знать, что за контрол (класс) выберет пользователь. Или ваше приложение до такой степени универсально, что его строит и подстраивает пользователь, тогда да без таких штучек не обойтись…
В вашем же случае, у вас все железно.. ну а расположение компонент см исходник. :wink:
У вас нет необходимых прав для просмотра вложений в этом сообщении.
Maxizar
постоялец
 
Сообщения: 385
Зарегистрирован: 20.03.2010 19:48:14

След.

Вернуться в Lazarus

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 36

Рейтинг@Mail.ru