При разработке прикладных решений часто возникает задача визуального акцентирования данных: например, выделить цветом строки номенклатуры, присутствующие в определенном списке или удовлетворяющие специальному условию. Рассмотрим, почему попытка покрасить строки напрямую в цикле является ошибкой, и подробно разберем правильные механизмы реализации для обычных и управляемых форм.
Проанализируем типичную ошибку начинающих разработчиков: попытку найти свойство цвета непосредственно у объекта данных (СтрокаТабличнойЧасти или СтрокаТаблицыЗначений). В платформе 1С объекты коллекций данных хранят только прикладные значения (ссылки, числа, строки) и не содержат свойств оформления (таких как ЦветФона или ЦветТекста).
Цвет и шрифт — это свойства визуального слоя отображения. Даже если бы существовал способ точечно изменить цвет конкретного элемента на экране, при первой же прокрутке, сортировке или фильтрации таблица будет перерисована платформой заново, и разовое оформление сбросится. Поэтому раскраска строк всегда должна быть привязана к механизмам отрисовки платформы.
В обычном интерфейсе для элемента управления Табличное поле оптимальным инструментом визуального оформления является обработчик события ПриПолученииДанных. В отличие от события ПриВыводеСтроки, которое вызывается для каждой строки отдельно, ПриПолученииДанных обрабатывает сразу весь видимый на экране пакет строк, что обеспечивает высокую производительность.
Разберем по шагам реализацию эффективной раскраски:
НайтиСтроки() на каждую строку при перерисовке (что создает квадратичную сложность), сохраним список выделяемых значений в объект Соответствие. Поиск по ключу в объекте Соответствие выполняется со сложностью $O(1)$.ПриПолученииДанных обходим коллекцию ОформленияСтрок, проверяем наличие номенклатуры в подготовленном соответствии и задаем цвет оформления.Посмотрим на пример реализации в модуле обычной формы:
// В модуле формы создаем переменную для хранения списка выделяемых позиций
Перем мВыделяемыеПозиции;
Процедура ПриОткрытии()
мВыделяемыеПозиции = Новый Соответствие;
КонецПроцедуры
// Процедура заполнения списка номенклатуры, которую требуется выделить
Процедура ЗаполнитьВыделение(ВременнаяТаблицаВыделения)
мВыделяемыеПозиции = Новый Соответствие;
Для Каждого Стр Из ВременнаяТаблицаВыделения Цикл
Если ЗначениеЗаполнено(Стр.Номенклатура) Тогда
мВыделяемыеПозиции.Вставить(Стр.Номенклатура, Истина);
КонецЕсли;
КонецЦикла;
// Принудительно инициируем перерисовку табличного поля
ЭлементыФормы.ТаблицаДанных.ОбновитьСтроки();
КонецПроцедуры
// Обработчик события табличного поля "ПриПолученииДанных"
Процедура ТаблицаДанныхПриПолученииДанных(Элемент, ОформленияСтрок)
Если мВыделяемыеПозиции = Неопределено Или мВыделяемыеПозиции.Количество() = 0 Тогда
Возврат;
КонецЕсли;
ЦветПодсветки = Новый Цвет(255, 230, 230); // Светло-красный цвет
Для Каждого Оформление Из ОформленияСтрок Цикл
ДанныеСтроки = Оформление.ДанныеСтроки;
Если ДанныеСтроки = Неопределено Тогда
Продолжить;
КонецЕсли;
// Проверяем наличие номенклатуры в нашем соответствии
Если мВыделяемыеПозиции[ДанныеСтроки.Номенклатура] <> Неопределено Тогда
// Устанавливаем цвет фона для всей строки
Оформление.ЦветФона = ЦветПодсветки;
// При необходимости можно покрасить только конкретную ячейку:
// Оформление.Ячейки.Номенклатура.ЦветФона = ЦветПодсветки;
КонецЕсли;
КонецЦикла;
КонецПроцедуры
В управляемом интерфейсе прямого доступа к событиям отрисовки строк нет. Вместо этого используется механизм Условного оформления формы. Выделение строк по списку можно реализовать программным добавлением правила оформления с видом сравнения В Списке.
Разберем по шагам алгоритм для управляемой формы:
СписокЗначений, куда помещаем все значения номенклатуры, требующие выделения.УсловноеОформление.Элементы, чтобы избежать дублирования условий.Рассмотрим пример кода для управляемой формы:
&НаСервере
Процедура ВыделитьСтрокиПоСпискуНаСервере(МассивНоменклатуры)
// 1. Формируем список значений для отбора
СписокДляВыделения = Новый СписокЗначений;
СписокДляВыделения.ЗагрузитьЗначения(МассивНоменклатуры);
// 2. Очищаем существующие правила условного оформления (или находим конкретное)
УсловноеОформление.Элементы.Очистить();
Если СписокДляВыделения.Количество() = 0 Тогда
Возврат;
КонецЕсли;
// 3. Создаем новый элемент условного оформления
ЭлементОформления = УсловноеОформление.Элементы.Добавить();
// Настраиваем оформление: цвет фона
ЭлементОформления.Оформление.УстановитьЗначениеПараметра("ЦветФона", WebЦвета.СветлоЖелтый);
// Указываем поля таблицы, которые будут окрашиваться
ПолеОформления = ЭлементОформления.Поля.Элементы.Добавить();
ПолеОформления.Поле = Новый ПолеКомпоновкиДанных("ТаблицаДанных");
// Задаем условие отбора: Номенклатура В Списке
ЭлементОтбора = ЭлементОформления.Отбор.Элементы.Добавить(Тип("ЭлементОтбораКомпоновкиДанных"));
ЭлементОтбора.ЛевоеЗначение = Новый ПолеКомпоновкиДанных("ТаблицаДанных.Номенклатура");
ЭлементОтбора.ВидСравнения = ВидСравненияКомпоновкиДанных.ВСписке;
ЭлементОтбора.ПравоеЗначение = СписокДляВыделения;
ЭлементОтбора.Использование = Истина;
КонецПроцедуры
Если список строк для выделения формируется сложным алгоритмом или объемы списка номенклатуры слишком велики для передачи в условие отбора, рекомендуется добавить в саму таблицу данных булев реквизит (например, ВыделенаЦветом). В этом случае в таблице формы один раз статически настраивается условное оформление по условию ТаблицаДанных.ВыделенаЦветом Равно Истина, а в коде достаточно лишь проставить значение Истина в нужных строках данных.