IE2017

Трюки 1С 8 – Управление обычными формами из общего модуля

Программирование - Практика программирования

Трюки 1С 8 – Управление обычными формами из общего модуля

Трюки 1С 8 – Управление обычными формами из общих модулей

Продолжим цикл статей, начатый статьей Трюки 1С 8 Передача реквизитов формы документа в форму выбора.

Если с событиями объектов в 1С все хорошо – на них можно подписаться и встраивать свою логику в штатные алгоритмы, не изменяя модулей конфигурации, то, как известно, с событиями обычных форм дела обстоят хуже.

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

1. Осмотримся

Попробуем понять, что именно может помешать нам в использовании механизма, подобного механизму подписок. В платформе есть возможность менять процедуру обработчика события формы или элемента управления на форме - можно, например, написать в общем модуле:

ФормаИлиЭлементФормы.УстановитьДействие(ИмяСобытия, Новый Действие(«ИмяВашейпроцедуры»));

Попробуйте! И столкнетесь сразу с тремя проблемами:

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

2 – наша процедура, которой мы замещаем штатный обработчик события формы, согласно встроенной справке  1С должна находиться в модуле формы и сигнатура этой процедуры должна совпадать с сигнатурой штатного обработчика, иначе платформа выдаст ошибку:

УстановитьДействие(, )

Примечание:

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

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

Кстати, условие экспортируемости, по-моему, необязательно, поскольку процедура-обработчик вызывается самой формой локально. По крайней мере, у меня все работает без модификатора «Экспорт».

3 – естественно хотелось бы иметь возможность в нужных местах вызывать штатный обработчик, чтобы не дублировать его код в своем общем модуле. Но чтобы штатный обработчик можно было бы запустить извне формы, он должен быть экспортируемой функцией или в форме должна быть универсальная экспортная обертка для вызова штатных обработчиков.

2. Обдумаем увиденное

Исходя из всего вышесказанного, приходим к простым логическим выводам:

1 - инициализация механизма управления формой должна происходить в обработчике одного из первых событий в жизни формы, например, «Перед открытием», чтобы у нас было время для подмены всех нужных нам из числа остальных еще не вызванных обработчиков. Чтобы не менять код формы, можно внедриться в код какой-нибудь процедуры общего модуля, вызываемой при создании нужных нам форм.

2 – модуль формы должен содержать блок оберток универсального обработчика, которые будут вызываться нашим механизмом и в свою очередь будут вызывать универсальный (один для всех форм и их событий) обработчик, находящийся в нашем общем модуле. Отличаться друг от друга эти обертки будут только числом параметров, которое для личного комфорта можно отразить в названии этих процедур.
3 – модуль формы должен содержать универсальную экспортную процедуру-обертку для вызова произвольных локальных штатных процедур обработки событий формы и ее элементов.

3. Набросаем эскиз

Согласно этим умозаключениям модуль формы (пример из реально работающей и легко обслуживаемой конфигурации Комплексной Автоматизации на платформе 8.2) модифицируется следующим способом:

Процедура ПередОткрытием(Отказ, СтандартнаяОбработка)

                …

                НашМодуль.НастроитьФормуДокумента(ДокументОбъект, ЭтаФорма);

КонецПроцедуры // ПередОткрытием()

//Универсальный блок+ ===============================================

Процедура УниверсальныйОбработчик0() {НашМодуль.УниверсальныйОбработчик(ЭтаФорма);}

Процедура УниверсальныйОбработчик1(П1) {НашМодуль.УниверсальныйОбработчик(ЭтаФорма, П1);}

Процедура УниверсальныйОбработчик2(П1, П2) {НашМодуль.УниверсальныйОбработчик(ЭтаФорма, П1, П2);}

Процедура УниверсальныйОбработчик3(П1, П2, П3) {НашМодуль.УниверсальныйОбработчик(ЭтаФорма, П1, П2, П3);}

Процедура УниверсальныйОбработчик4(П1, П2, П3, П4) {   НашМодуль.УниверсальныйОбработчик(ЭтаФорма, П1, П2, П3, П4);}

Процедура ШтатныйОбработчик(Команда, П1, П2, П3, П4) Экспорт {Выполнить(Команда);}

//Универсальный блок- ===============================================

Наши вставки в штатный модуль формы выделены цветом, они во всех формах абсолютно одинаковы, никогда не меняются и легко автоматизируются.

Что я имею в виду под автоматизацией – возможность скриптом убрать эти изменения в модулях форм перед обновлением конфигурации и последующей их обратной вставки после обновления.

Выше я показал, что это необходимый минимум. Если этих изменений в формах хватит для реализации подписок на события форм и их элементов, то этот механизм будет самым компактным из всех возможных. Если бы что-то подобное было встроено в платформу, то настройка форм вообще не требовала бы их изменения.

4. Первоисточники

Идеи почерпнуты из статьи, в которой есть все необходимое для реализации описываемого механизма:

Tormozit , Методика переопределения и вызова обработчиков событий формы, http://kb.mista.ru/article.php?id=268.

Мной просто проделан дальнейший путь в направлении большей и, возможно, предельной универсальности этой методики.

5. Примеры использования механизма

Чтобы статья не превратилась в книжку, код реализации в простейшем случае – добавление своей кнопки в командную панель – прикладываю отдельным файлом.

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

Более сложный пример – добавление «Табло цен» в табличную часть документов Товары. В отдельном табличном поле на форме для пользователей с определенными правами по добавленной в командную панель кнопке динамически выводится детальное описание расчета цены для номенклатуры, привязанное к текущей строке табличного поля товаров, – с выводом всех параметров, влияющих на расчет, например, региона покупателя, типа цен, размера наценки. А свободное пространство на форме для этого табло получается сжатием исходного табличного поля по горизонтали. При повторном нажатии на кнопку табло скрывается. И все это делается из общего модуля. Скриншот - в начале статьи.

 

Скачать файлы

Наименование Файл Версия Размер
doc.rar
.rar 20,19Kb
01.09.13
21
.rar 20,19Kb 21 Скачать

См. также

Комментарии
1. script Мальчинко (script) 196 02.09.13 13:48 Сейчас в теме
Для управления подписками обычных форм, здесь на инфостарте лежит целая подсистема. Пользуюсь уже несколько лет. Лучшего решения пока не видел.

"Методика переопределения и вызова обработчиков событий формы в 1С 8"
http://infostart.ru/public/16980/?mid=836587
2. m b (mbm) 45 02.09.13 18:22 Сейчас в теме
На самом деле указанная Вами статья - перепечатка указанного в моей статье первоисточника.
Если Вы пользовались этой методикой, то сразу поймете преимущества указанного в моей статье подхода.
У меня единообразные изменения в модули форм (к которым Вы хотите получить доступ) вносятся один раз.
Затем я уже никогда не трогаю формы - любые фишки реализуются кодом в двух процедурах общего модуля.
Если честно, для меня здесь больше интересна перспектива автоматизации обновлений через временный откат этих изменений в модулях форм, что по удобству применения практически приравняло бы эту методику к механизму подписок.
3. Сергей Лесовой (Synoecium) 195 03.09.13 15:27 Сейчас в теме
Выжат чистый максимум из того, что есть)
4. m b (mbm) 45 03.09.13 17:42 Сейчас в теме
(3) Synoecium, собственно занимался этим наполовину из академического интереса - насколько далеко удастся зайти :)
Однако, и пользу получил ощутимую - программирование форм сейчас происходит в 2 процедурах общего модуля. Что-то вроде центра управления полетами :)
5. Антон Собейко (sobeyko2008) 6 04.09.13 10:20 Сейчас в теме
а можно какое то описание что дает эта обработка?
6. m b (mbm) 45 04.09.13 13:32 Сейчас в теме
(5) sobeyko2008, в приложенном файле не обработка, а выдержки из рабочего кода общего модуля,
с помощью которых добавляется кнопка на форму. Выдержки - потому что у меня все изменения форм
динамические и прописаны именно в этих процедурах, т.е. там слишком много всего.
Причем связанного с целыми пластами доработок, например, в области ценообразования,
более эргономичной версии корректировки заказа покупателя, управленческого баланса и т.д.
Но поняв, как сделать простейшее, потом можно применить эту методику и в более сложных случаях.
Поэтому тем, кому лень разбирать пару страниц кода, качать не советую - кнопки "Сделать все" там нет!
Теория достаточно полно изложена в статье, чтобы понять - нужно это Вам или нет.
7. bulpi bulpi (bulpi) 110 04.09.13 22:47 Сейчас в теме
Все красиво, плюс поставил. Но это годится для конфигурации, которая навсегда твоя. Как будет тебя материть человек, которому вдруг придется с этим разбираться...
8. m b (mbm) 45 05.09.13 00:04 Сейчас в теме
(7) bulpi, согласен, с нуля разобраться в этой цепочке передач управления из формы в модуль и обратно достаточно сложно. Но если каждую фишку снабдить двумя отдельными комментариями - по одному в процедуре настройки форм и в процедуре универсального обработчика в общем модуле (а в формах у нас все единообразно, скупо и лаконично), то и поддерживать систему не составит труда, я думаю. Разобрать механику двух процедур, согласитесь, гораздо проще, нежели сравнивать кучу дописок, разбросанных в разных процедурах модулей (скорее всего многих) форм, в своей конфигурации и конфигурации поставщика.
9. Александр Тарасюк (Aletar) 09.09.13 06:25 Сейчас в теме
Плюсую, сам дошел до такого же решения в итоге.
10. m b (mbm) 45 09.09.13 17:54 Сейчас в теме
(9) Aletar, так опубликуй - идея пока не запатентована :)
При обдумывании и дальнейшем обсуждении статьи могут прийти новые мысли.
У меня так произошло в предыдущей статье - смотри там мои комменты 12 и 13.
А ведь пользуюсь этими идеями не первый год - видимо, не было стимула для их
дальнейшей разработки, пока не решил вынести на публику.
11. Аркадий Кучер (Abadonna) 3681 10.09.13 06:07 Сейчас в теме
(0) А всего-то навсего разработчикам движка надо было бы добавить вот такой обработчик (рис.)
Почему не сделано - лично мне, непонятно...
Мои ВК ловят момент создания форм, но это опять же изменение "родного" кода
Прикрепленные файлы:
12. Сергей Ожерельев (Поручик) 3574 10.09.13 07:40 Сейчас в теме
(11) Разные контексты. Объект и Форма.
13. m b (mbm) 45 10.09.13 08:03 Сейчас в теме
(11) Abadonna, думаю, если бы это было легко осуществимо, то вряд ли бы не внедрили.
По себе знаю, иногда из-за какой-то, казалось бы, мелочи, не предусмотренной в начале разработки, приходится переписывать всю программу, которая не сравнима по сложности и человеко-часам, вложенным в платформу 1С.
С другой стороны, возможно, обычные формы доживают свой век и нет смысла вкладываться в дальнейшую разработку того, с чем и так работают.
14. Аркадий Кучер (Abadonna) 3681 10.09.13 12:37 Сейчас в теме
(13) mbm,
если бы это было легко осуществимо

Мои ВК запросто отслеживают и моменты рождения и моменты разрушения форм. И это "со стороны"!
А уж внутри - не вижу никаких проблем. Скорее всего просто не посчитали нужным.
Тот же Альф сделал же в formex (7.7) глобальное событие ПередОткрытием(), а 1С-ники поленились.
15. Алексей (alexqc) 144 08.12.14 11:15 Сейчас в теме
>Процедура должна быть экспортируемой и располагаться в модуле формы, при этом количество параметров должно совпадать с необходимым количеством параметров события, инициирующего вызов действия.

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

Ограничение на список параметров не столь жестко: главное, чтобы процедура могла быть вызвана с параметрами обработчика. То есть - если параметров процедуры БОЛЬШЕ чем ожидаемых параметров обработчика, но остальным параметрам заданы значения по-умолчанию, то такое назначение тоже допустимо, и вызов произойдет нормально (неиспользуемые параметры получать значение по-умолчанию). Т.е. количество УниверсальныхОбработчиков можно сократить до 1 с макс к-вом параметров.
16. Алексей (alexqc) 144 08.12.14 11:26 Сейчас в теме
(11), (13) в управляемых формах, в модуле менеджера объекта есть события получения формы (там можно например свою подсунуть), но к сожалению там получается не конкретная форма объекта, а лишь ее имя/метаданные. Хотя остается извратный вариант сделать свою прокси-форму, подменяемую в менеджере, которая в свою очередь откроет нужную форму и что-то с ней сделает. Но там возможности все равно ограничены. Зато все штатно. Для неуправляемых к сожалению нет и такого метода.


В 8.3 насколько слышал, добавили подписки на события для форм?
17. m b (mbm) 45 08.12.14 13:17 Сейчас в теме
(15) alexqc, скорее всего в справке нужно поменять И на ИЛИ, то есть процедура должна быть экспортируемой ИЛИ находиться в модуле формы. Со вторым замечанием интересно будет повозиться, поскольку оно действительно, похоже, позволяет сильно упростить структуру универсальной вставки в код модуля формы.
18. m b (mbm) 45 08.12.14 13:25 Сейчас в теме
(16) alexqc, тоже только слышал, к сожалению. Пока нужды наших клиентов удовлетворяются обычными формами с использованием описанного механизма и нет большой необходимости пользоваться чем-то еще. "Если все работает и всех все удовлетворяет, ничего не меняем"
19. m b (mbm) 45 26.12.14 12:13 Сейчас в теме
(15) alexqc, к сожалению, второе замечание неверно. Последовательность команд:

Действие = Новый Действие("АК_УниверсальныйОбработчик");
Элемент.УстановитьДействие(ИмяСобытия, Действие);

где процедура обработчика определена в форме как:

Процедура АК_УниверсальныйОбработчик(П1 = Неопределено, П2 = Неопределено, П3 = Неопределено, П4 = Неопределено)

приводит к ошибке:

Ошибка при вызове метода контекста (УстановитьДействие)
Элемент.УстановитьДействие(ИмяСобытия, Действие);
по причине:
Недопустимое значение параметра (параметр номер '2') (Процедура, указанная в качестве обработчика события, имеет неверное количество параметров)

Так что метод, описанный в статье, это максимально возможное продвижение для данной версии платформы (1С:Предприятие 8.2 (8.2.19.106)).
Оставьте свое сообщение