gifts2017

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

Опубликовал m b (mbm) в раздел Программирование - Практика программирования

Трюки 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) 02.09.13 13:48
Для управления подписками обычных форм, здесь на инфостарте лежит целая подсистема. Пользуюсь уже несколько лет. Лучшего решения пока не видел.

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

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

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

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


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

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

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

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

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

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

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