При разработке и доработке конфигураций на платформе 1С 7.7 разработчики часто сталкиваются с нехваткой привычных штатных событий. Например, для табличной части документа предусмотрена предопределенная процедура ПриОкончанииРедактированияСтроки(), однако аналогичного универсального события для реквизитов шапки ПриИзменении в платформе нет.
Прописывать формулу вручную в свойствах каждого реквизита на форме неудобно и рискованно: при добавлении новых полей легко пропустить назначение формулы. Предопределенная процедура ОбработкаВыбораЗначения() также не решает задачу полностью, так как срабатывает только при выборе с помощью кнопки («педальки») и выполняется до момента обновления значения реквизита в контексте формы.
Разберем основные практические способы, которые позволяют отследить факт изменения любого реквизита формы и запустить нужный алгоритм пересчета.
Платформа 1С 7.7 пересчитывает формулы текстовых элементов диалога при любом обновлении или перерисовывании формы. Если поместить на форму невидимый текстовый элемент и прописать в его поле «Формула» специальную функцию, она будет вызываться регулярно. Чтобы предотвратить лишние срабатывания при открытии и избежать зацикливания при пересчете, реализуем механизм сравнения с кэшем прошлых значений.
Рассмотрим пошаговый алгоритм реализации:
ПриОткрытии() заполняем список значений текущими реквизитами формы и устанавливаем флаг завершения инициализации.ФлОтследитьИзменения().ФлОтследитьИзменения() сравниваем текущие значения реквизитов со значениями из кэша. При обнаружении изменений обновляем кэш и вызываем процедуру обработки.Проанализируем пример кода для модуля формы:
Перем мКэшРеквизитов;
Перем ФлИнициализацияПрошла;
Перем ФлПересчетВыполняется;
Функция ФлОтследитьИзменения()
// Предотвращаем выполнение функции до окончания процедуры ПриОткрытии()
Если ФлИнициализацияПрошла <> 1 Тогда
Возврат "";
КонецЕсли;
// Защита от рекурсивного зацикливания при программном изменении реквизитов
Если ФлПересчетВыполняется = 1 Тогда
Возврат "";
КонецЕсли;
// Перебираем сохраненные реквизиты
Для Сч = 1 По мКэшРеквизитов.РазмерСписка() Цикл
ИмяРеквизита = "";
СтароеЗначение = мКэшРеквизитов.ПолучитьЗначение(Сч, ИмяРеквизита);
ТекущееЗначение = Вычислить(ИмяРеквизита);
Если ТекущееЗначение <> СтароеЗначение Тогда
// Обновляем значение в кэше
мКэшРеквизитов.УстановитьЗначение(Сч, ТекущееЗначение, ИмяРеквизита);
// Включаем флаг блокировки и вызываем обработчик
ФлПересчетВыполняется = 1;
ОбработатьИзменениеРеквизита(ИмяРеквизита, ТекущееЗначение);
ФлПересчетВыполняется = 0;
КонецЕсли;
КонецЦикла;
Возврат "";
КонецФункция
Процедура ПриОткрытии()
ФлИнициализацияПрошла = 0;
ФлПересчетВыполняется = 0;
// Инициализируем кэш реквизитов шапки
мКэшРеквизитов = СоздатьОбъект("СписокЗначений");
мКэшРеквизитов.ДобавитьЗначение(Контрагент, "Контрагент");
мКэшРеквизитов.ДобавитьЗначение(Договор, "Договор");
мКэшРеквизитов.ДобавитьЗначение(Склад, "Склад");
ФлИнициализацияПрошла = 1;
КонецПроцедуры
Важный момент: Флаг ФлПересчетВыполняется критически важен. Если внутри процедуры ОбработатьИзменениеРеквизита() происходит изменение других полей формы, платформа вызовет перерисовку диалога. Без установки флага произойдет зацикливание вызова функции.
Если в базе разрешено использование внешних компонент, эффективным решением является применение FormEx.dll. Данная библиотека расширяет возможности работы с интерфесом 1С 7.7 и позволяет программно управлять элементами диалога.
С помощью объекта РасширениеФормы можно программно обойти все элементы диалога при открытии формы и назначить им единую формулу обработки без необходимости редактировать свойства каждого элемента вручную в Конфигураторе.
Выясним, как это реализовать на практике:
Перем Сервис, РасшФормы;
Процедура ПриИзмененииЛюбогоРеквизита(ИдентификаторЭлемента)
Сообщить("Изменен реквизит: " + ИдентификаторЭлемента);
// Выполняем требуемый пересчет
КонецПроцедуры
Процедура ПриОткрытии()
Если ЗагрузитьВнешнююКомпоненту("formex.dll") = 1 Тогда
Сервис = СоздатьОбъект("Сервис");
РасшФормы = СоздатьОбъект("РасширениеФормы");
РасшФормы.УстановитьФорму(Форма);
// Обходим элементы формы и программно назначаем формулу
Для Сч = 1 По Форма.КоличествоЭлементов() Цикл
Элемент = Форма.ПолучитьЭлемент(Сч);
ИмяЭлемента = Элемент.Идентификатор;
Если ПустаяСтрока(ИмяЭлемента) = 0 Тогда
// Назначаем вызов процедуры с передачей идентификатора
Элемент.Формула = "ПриИзмененииЛюбогоРеквизита(""" + ИмяЭлемента + """)";
КонецЕсли;
КонецЦикла;
КонецЕсли;
КонецПроцедуры
При использовании внешней компоненты 1С++ или классов перехватчиков доступен механизм перехвата низкоуровневых событий формы. Это позволяет отлавливать события потери фокуса элементом ввода (OnKillFocus) или непосредственного редактирования текста.
Преимущество этого метода заключается в том, что событие срабатывает ровно в момент, когда пользователь завершил ввод данных в поле и переместил фокус на другой элемент (клавишами Enter, Tab или мышью).
ПриОкончанииРедактированияСтроки().