Как в событии ПередЗакрытием формы документа определить какая кнопка была нажата или нажат Esc

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке интерфейсов на платформе 1С:Предприятие 8.3 часто возникает задача: выполнить определенное действие только в том случае, если пользователь закрывает форму «просто так» (через крестик или клавишу Escape), и пропустить это действие, если закрытие инициировано осознанно — например, кнопкой «Провести и закрыть». Стандартное событие ПередЗакрытием срабатывает во всех этих случаях, и платформа по умолчанию не передает в него информацию об источнике закрытия. В этой статье мы разберем несколько профессиональных способов решения этой задачи.

Метод 1. Использование переменной-флага на уровне модуля формы

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

Во-первых, в самом верху модуля управляемой формы необходимо объявить переменную. Она будет доступна во всех процедурах модуля, пока форма открыта.


&НаКлиенте
Перем КнопкаДействияНажата;

Во-вторых, в обработчике события ПриОткрытии инициализируем эту переменную значением Ложь. Это гарантирует нам, что при старте системы мы находимся в «состоянии ожидания».


&НаКлиенте
Процедура ПриОткрытии(Отказ)
    КнопкаДействияНажата = Ложь;
КонецПроцедуры

В-третьих, для всех кнопок, которые должны закрывать форму «правильным» образом (например, «Провести и закрыть» или «ОК»), мы создаем собственные команды. В коде этих команд мы сначала устанавливаем наш флаг в значение Истина, а затем вызываем закрытие формы.


&НаКлиенте
Процедура КомандаЗаписатьИЗакрыть(Команда)
    // Устанавливаем флаг, что нажата именно наша кнопка
    КнопкаДействияНажата = Истина;
    
    // Выполняем запись объекта
    Если Записать() Тогда
        ЭтаФорма.Закрыть();
    КонецЕсли;
КонецПроцедуры

Наконец, в событии ПередЗакрытием мы проверяем значение нашей переменной. Если она осталась равна Ложь, значит, пользователь не нажимал на нашу кнопку, а воспользовался клавишей Esc или нажал на крестик в углу окна.


&НаКлиенте
Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)
    Если Не КнопкаДействияНажата Тогда
        // Сюда мы попадем только при нажатии Esc или Крестика
        // Например, сбросим флаг проведения, как требовалось в задаче
        Объект.ФлагПроведения = Ложь;
        Сообщить("Форма закрыта отменой или Esc. Изменения не зафиксированы.");
    КонецЕсли;
КонецПроцедуры

Метод 2. Использование параметра метода Закрыть()

Разберем ситуацию, когда нам нужно передать конкретное значение из вызывающей кнопки в логику закрытия. Метод ЭтаФорма.Закрыть() поддерживает передачу параметра. Этот параметр не попадает напрямую в ПередЗакрытием, но доступен в событии ПриЗакрытии. Посмотрим на пример.


&НаКлиенте
Процедура НажатьКнопкуВыполнить(Команда)
    ЭтаФорма.Закрыть("КнопкаВыполнить");
КонецПроцедуры

&НаКлиенте
Процедура ПриЗакрытии(ПараметрЗакрытия)
    Если ПараметрЗакрытия = "КнопкаВыполнить" Тогда
        // Логика для конкретной кнопки
    ИначеЕсли ПараметрЗакрытия = Неопределено Тогда
        // Логика для Esc или крестика
    КонецЕсли;
КонецПроцедуры

Важно помнить, что событие ПриЗакрытии выполняется, когда отмена закрытия уже невозможна. Если ваша задача — задать уточняющий вопрос пользователю или отменить закрытие при нажатии Esc, используйте первый метод с переменной-флагом.

Метод 3. Перехват клавиши Escape через свойства кнопок

Выясним, как заставить платформу реагировать на клавишу Esc определенным образом. В свойствах любой кнопки на форме (даже невидимой) есть параметр КнопкаОтмены (CancelButton). Если установить это свойство в значение Да (Истина), то при нажатии клавиши Escape на клавиатуре будет автоматически вызываться действие, связанное с этой кнопкой.

Проанализируем, как это можно использовать для решения задачи автора:

  1. Создаем на форме кнопку, называем ее, например, КнопкаОтменаEsc.
  2. В свойствах этой кнопки устанавливаем Сочетание клавиш — Escape.
  3. В обработчике этой кнопки прописываем явный сброс всех нужных флагов и закрытие формы.

Этот способ позволяет четко разделить потоки управления, не загромождая событие ПередЗакрытием сложными условиями Если ... Тогда.

Метод 4. Анализ модифицированности формы

Иногда определение нажатой кнопки нужно лишь для того, чтобы понять, сохранять изменения или нет. Проанализируем системное свойство Модифицированность. Если пользователь внес изменения в документ, 1С сама установит Модифицированность = Истина. При попытке закрыть форму на Esc, платформа спросит: "Сохранить изменения?".

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

Рекомендации по реализации

При работе с формой документа всегда следуйте правилу: явное лучше неявного. Если стандартное поведение платформы не позволяет однозначно определить причину закрытия, лучше всего переопределить стандартные команды закрытия собственными. Это даст вам полный контроль над жизненным циклом формы.

Рассмотрим финальный пример правильной структуры модуля:


&НаКлиенте
Перем СпособЗакрытия; // Принимает значения: "Провести", "Отмена", "Системно"

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    СпособЗакрытия = "Системно";
КонецПроцедуры

&НаКлиенте
Процедура КомандаПровестиИЗакрыть(Команда)
    СпособЗакрытия = "Провести";
    Объект.ФлагПроведения = Истина;
    Если Записать() Тогда
        ЭтаФорма.Закрыть();
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)
    Если СпособЗакрытия = "Системно" Тогда
        // Пользователь нажал Esc или крестик
        Объект.ФлагПроведения = Ложь;
    КонецЕсли;
КонецПроцедуры

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

← На главную