Работа с обычными формами в 1С:Предприятии 8 сегодня у многих разработчиков вызывает легкую ностальгию, смешанную с растерянностью. Стандарты управляемого интерфейса приучили нас к тому, что платформа берет на себя большинство рутинных задач по отрисовке интерфейса. Возвращаясь к классическому интерфейсу («обычным формам»), мы мгновенно сталкиваемся с неочевидным поведением стандартных элементов управления.
Одна из наиболее частых задач — предоставить пользователю список элементов (например, справочника) с возможностью отметить галочками нужные позиции для последующей обработки. На управляемых формах это решается за пару кликов, но в обычных формах разработчики регулярно наступают на две классические проблемы:
СправочникСписок) система настырно пытается открыть карточку элемента справочника.ТаблицаЗначений), то вместо аккуратного флажка в ячейке выводится текстовое представление булева значения: «Да» или «Нет» («Истина»/«Ложь»).В этой статье мы подробно разберем оба сценария, выясним причины такого поведения платформы и реализуем надежные профессиональные решения для каждого случая.
---
Рассмотрим ситуацию, когда мы решили отказаться от динамического списка в пользу обычной Таблицы Значений (ТЗ), размещенной на форме. Нам нужно заполнить ее данными, дать пользователю возможность интерактивно проставлять флажки и при этом избежать появления раздражающих надписей «Да» и «Нет» при потере фокуса ячейкой.
Основная ошибка большинства разработчиков заключается в попытке связать булеву колонку напрямую через свойство Данные. Платформа 1С в этом случае пытается отобразить текстовое представление значения ячейки. Чтобы решить эту проблему исключительно визуальными средствами конфигуратора, выполним настройку по шагам:
Пометка), платформа при потере фокуса ячейкой будет упорно выводить текст.Флажок.Пометка. Таким образом, колонка будет связана с данными ТЗ только по значению флажка, игнорируя текстовое представление.Непосредственно. Это позволит пользователю менять состояние флажка в один клик мыши без предварительной активации строки и входа в режим редактирования ячейки.Поскольку свойство Данные у колонки теперь пустое, стандартное событие колонки ПриИзменении вызываться не будет. Если вам необходимо выполнять какие-то действия в коде сразу в момент клика по флажку (например, динамически пересчитывать итоги или проверять условия), используем событие самого табличного поля ПриИзмененииФлажка:
Процедура ТабличноеПолеПриИзмененииФлажка(Элемент, Колонка)
Если Колонка.Имя = "Пометка" Тогда
// Значение в Элемент.ТекущиеДанные.Пометка уже автоматически изменилось.
// Здесь мы можем прописать сопутствующую логику:
ТекущаяСтрока = Элемент.ТекущиеДанные;
Если ТекущаяСтрока.Пометка Тогда
Сообщить("Пользователь выбрал элемент: " + СокрЛП(ТекущаяСтрока.Ссылка));
КонецЕсли;
КонецЕсли;
КонецПроцедуры
---
Если по каким-то причинам интерактивная настройка свойств колонки в конфигураторе вам не подходит (например, структура таблицы и колонки формируются полностью динамически из кода), мы можем управлять выводом флажка программно. Для этого задействуем механизм оформления строк.
Проанализируем классический подход с использованием события ПриВыводеСтроки. Нам необходимо принудительно указать платформе, что в ячейке нужно отображать только флажок и полностью скрыть текст.
Процедура ТабличноеПолеПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
// Убедимся, что данные строки доступны для обработки
Если ДанныеСтроки = Неопределено Тогда
Возврат;
КонецЕсли;
ЯчейкаПометки = ОформлениеСтроки.Ячейки.Пометка;
// Настраиваем визуальное представление
ЯчейкаПометки.ОтображатьФлажок = Истина;
ЯчейкаПометки.ОтображатьТекст = Ложь;
// Связываем состояние флажка с булевым значением в нашей ТЗ
ЯчейкаПометки.Флажок = ДанныеСтроки.Пометка;
КонецПроцедуры
Важное примечание по производительности: Событие ПриВыводеСтроки вызывается платформой очень часто — при любом скроллинге, изменении размеров или даже простом движении мыши над таблицей. Если таблица содержит тысячи строк, сложные вычисления внутри этого обработчика могут привести к сильным зависаниям интерфейса.
Для оптимизации работы интерфейса рекомендуется использовать более прогрессивный метод — событие ПриПолученииДанных. Оно отрабатывает пакетно для всех видимых на экране строк одновременно, что существенно снижает нагрузку на процессор.
Разберем пример реализации через пакетную обработку строк:
Процедура ТабличноеПолеПриПолученииДанных(Элемент, ОформленияСтрок)
Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
ДанныеСтроки = ОформлениеСтроки.ДанныеСтроки;
Если ДанныеСтроки <> Неопределено Тогда
ЯчейкаПометки = ОформлениеСтроки.Ячейки.Пометка;
ЯчейкаПометки.ОтображатьФлажок = Истина;
ЯчейкаПометки.ОтображатьТекст = Ложь;
ЯчейкаПометки.Флажок = ДанныеСтроки.Пометка;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
---
Вернемся к первоначальной задаче автора темы. Что делать, если мы принципиально не хотим отказываться от динамического списка СправочникСписок? Ведь динамический список чрезвычайно удобен: он обеспечивает быструю порционную выборку данных из базы, поддерживает стандартные отборы, сортировки и поиск, не требуя полной загрузки всей базы в оперативную память сервера и клиента.
Главное препятствие здесь — при попытке отредактировать ячейку или нажать на область флага система перехватывает управление и пытается открыть форму элемента справочника для просмотра или редактирования.
Чтобы обойти это ограничение, мы применим элегантный архитектурный прием: создадим виртуальный флаг, состояние которого будет храниться исключительно в оперативной памяти нашей формы, а стандартное поведение платформы (открытие карточки) мы заблокируем программно.
Разберем этот алгоритм по шагам.
Шаг 1. Подготовка формы и переменных
Прежде всего, нам нужно место для хранения информации о том, какие элементы пользователь уже отметил галочками. База данных для этого не подходит, перезаписывать элементы справочника (как предлагали некоторые участники обсуждения на форуме) — это грубейшая ошибка проектирования, которая приведет к блокировкам таблиц и мусору в информационной базе.
Мы объявим переменную на уровне модуля формы. В качестве структуры хранения идеально подойдет объект Соответствие, поскольку поиск по ключу в нем происходит практически мгновенно.
Перем СоответствиеВыбранныхЭлементов;
Процедура ПриОткрытии()
// Инициализируем хранилище при открытии формы
СоответствиеВыбранныхЭлементов = Новый Соответствие;
КонецПроцедуры
Шаг 2. Добавление виртуальной колонки
В конфигураторе откроем свойства нашего табличного поля СправочникСписок. Добавим новую колонку, назовем ее Пометка. Свойства Данные и ДанныеФлажка для этой колонки мы оставляем абсолютно пустыми. Нам не нужно связывать ее с реквизитами базы данных напрямую.
Шаг 3. Отрисовка состояния виртуальных флагов
Используем быстрое событие ПриПолученииДанных для того, чтобы на лету подставлять галочки в строки списка на основе нашего соответствия в памяти:
Процедура СправочникСписокПриПолученииДанных(Элемент, ОформленияСтрок)
Для Каждого ОформлениеСтроки Из ОформленияСтрок Цикл
// Получаем ссылку на текущий элемент справочника из данных строки
ТекущаяСсылка = ОформлениеСтроки.ДанныеСтроки.Ссылка;
ЯчейкаПометки = ОформлениеСтроки.Ячейки.Пометка;
ЯчейкаПометки.ОтображатьФлажок = Истина;
ЯчейкаПометки.ОтображатьТекст = Ложь;
// Проверяем, содержится ли ссылка в нашем списке выбранных
Если СоответствиеВыбранныхЭлементов.Получить(ТекущаяСсылка) <> Неопределено Тогда
ЯчейкаПометки.Флажок = Истина;
Иначе
ЯчейкаПометки.Флажок = Ложь;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Шаг 4. Перехват клика и блокировка стандартного открытия карточки
Теперь решим ключевую проблему — заблокируем открытие формы элемента при клике по колонке с пометкой. Для этого идеально подходит событие табличного поля ПередНачаломИзменения. Установив флаг Отказ = Истина, мы предотвращаем стандартную реакцию платформы и вместо этого меняем значение в нашем соответствии:
Процедура СправочникСписокПередНачаломИзменения(Элемент, Отказ)
// Проверяем, что пользователь кликнул именно по нашей колонке "Пометка"
Если Элемент.ТекущаяКолонка.Имя = "Пометка" Тогда
// Блокируем стандартное поведение (открытие карточки элемента)
Отказ = Истина;
// Получаем ссылку на текущую строку
ТекущиеДанныеСтроки = Элемент.ТекущиеДанные;
Если ТекущиеДанныеСтроки = Неопределено Тогда
Возврат;
КонецЕсли;
СсылкаНаЭлемент = ТекущиеДанныеСтроки.Ссылка;
// Инвертируем состояние флага в нашем соответствии
Если СоответствиеВыбранныхЭлементов.Получить(СсылкаНаЭлемент) = Неопределено Тогда
СоответствиеВыбранныхЭлементов.Вставить(СсылкаНаЭлемент, Истина);
Else
СоответствиеВыбранныхЭлементов.Удалить(СсылкаНаЭлемент);
КонецЕсли;
// Принудительно обновляем отображение строк на форме
Элемент.ОбновитьСтроки();
КонецЕсли;
КонецПроцедуры
Благодаря вызову метода Элемент.ОбновитьСтроки() система мгновенно инициирует событие отрисовки, и пользователь сразу увидит изменившийся статус флажка без каких-либо задержек и артефактов.
---
Мы детально изучили внутренние механизмы работы с флажками на обычных формах 1С. Подведем итог, какой подход выбрать в зависимости от архитектурных требований: