Как изменить шрифт строки табличной части при активизации строки в другой таблице на обычных формах

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

В разработке на обычных формах 1С часто возникает задача визуально связать данные двух таблиц. Типичный сценарий: при выборе строки в главной (верхней) таблице, соответствующие ей строки в подчиненной (нижней) таблице должны выделяться жирным шрифтом. Связь обычно устанавливается по какому-либо ключевому полю, например, КлючСвязи или Идентификатор.

Реализация этой задачи требует понимания механизма отрисовки табличных полей в обычных формах. В отличие от управляемых форм, здесь нет декларативного условного оформления, и вся логика ложится на программную обработку событий отрисовки. Рассмотрим подробно, как реализовать этот функционал правильно и эффективно.

Разбор типичной ошибки: почему цикл внутри события отрисовки — это плохо

Проанализируем ситуацию, с которой часто сталкиваются начинающие разработчики. Попытка перебрать все строки таблицы внутри процедуры ПриВыводеСтроки является в корне неверной. Рассмотрим ошибочный пример кода:


Процедура КорректировкаРасшифровкаПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    Если ЭлементыФормы.КорректировкаОсновная.ТекущиеДанные <> Неопределено Тогда
        Для каждого Стр Из КорректировкаРасшифровка Цикл // ОШИБКА!
            Если Стр.Ключ = ЭлементыФормы.КорректировкаОсновная.ТекущиеДанные.Ключ Тогда
                ОформлениеСтроки.Шрифт = Новый Шрифт(,,Истина);
            Иначе
                ОформлениеСтроки.Шрифт = Новый Шрифт(,,Ложь);
            КонецЕсли;
        КонецЦикла;
    КонецЕсли;
КонецПроцедуры

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

Правильный алгоритм реализации через ПриВыводеСтроки

Для корректной работы нам понадобится задействовать два события двух разных таблиц. Разберем по шагам процесс реализации.

Шаг 1. Обработка события в верхней таблице. Нам нужно сообщить нижней таблице, что данные в верхней изменились и пора перерисовать строки. Для этого используем событие ПриАктивизацииСтроки верхней таблицы.


Процедура КорректировкаОсновнаяПриАктивизацииСтроки(Элемент)
    // Инициируем перерисовку видимых строк нижней таблицы
    ЭлементыФормы.КорректировкаРасшифровка.ОбновитьСтроки();
КонецПроцедуры

Метод ОбновитьСтроки() крайне важен. В отличие от метода Обновить(), он не перечитывает данные из базы и не сбрасывает позицию курсора, а просто заставляет систему заново вызвать события оформления для тех строк, которые видны пользователю в данный момент.

Шаг 2. Оформление в нижней таблице. Теперь в событии ПриВыводеСтроки нижней таблицы мы просто сравниваем ключ текущей строки с ключом активной строки в верхней таблице.


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

Оптимизация производительности: использование события ПриПолученииДанных

Если нижняя таблица содержит сотни или тысячи строк, использование ПриВыводеСтроки может быть неэффективным. Рассмотрим более продвинутый метод — ПриПолученииДанных. Это событие вызывается один раз для всей порции данных, отображаемых на экране.

Проанализируем преимущества этого метода:

  1. Массовая обработка: Мы получаем массив объектов оформления сразу для всех видимых строк.
  2. Минимизация обращений: Мы можем один раз получить ключ из верхней таблицы и сравнить его со всеми строками массива.

Пример реализации:


Процедура КорректировкаРасшифровкаПриПолученииДанных(Элемент, ОформленияСтрок)
    
    ТекущиеДанныеВерх = ЭлементыФормы.КорректировкаОсновная.ТекущиеДанные;
    КлючДляПоиска = ?(ТекущиеДанныеВерх = Неопределено, Неопределено, ТекущиеДанныеВерх.Ключ);
    
    Для Каждого Оформление Из ОформленияСтрок Цикл
        ДанныеСтроки = Оформление.ДанныеСтроки;
        Если ДанныеСтроки.Ключ = КлючДляПоиска Тогда
            Оформление.Шрифт = Новый Шрифт(Оформление.Шрифт, , , Истина);
        Иначе
            Оформление.Шрифт = Новый Шрифт(Оформление.Шрифт, , , Ложь);
        КонецЕсли;
    КонецЦикла;
    
КонецПроцедуры

Важные технические нюансы работы со шрифтами

При работе с оформлением в 1С 8.3 (Обычные формы) необходимо учитывать несколько критических моментов, влияющих на стабильность системы.

Проблема ресурсов GDI: Каждый вызов Новый Шрифт() создает объект в памяти операционной системы. Если таблица часто перерисовывается (например, при быстром скроллинге), количество таких объектов может превысить лимиты Windows, что приведет к «падению» 1С или графическим артефактам.

Рекомендация по кэшированию: Профессиональным подходом считается создание объектов шрифтов заранее. Мы можем создать два шрифта (обычный и жирный) при открытии формы и просто подставлять ссылки на них:


// В модуле формы
Перем ШрифтЖирный, ШрифтОбычный;

Процедура ПриОткрытии()
    ШрифтЖирный = Новый Шрифт(ЭлементыФормы.КорректировкаРасшифровка.Шрифт, , , Истина);
    ШрифтОбычный = ЭлементыФормы.КорректировкаРасшифровка.Шрифт;
КонецПроцедуры

Процедура КорректировкаРасшифровкаПриВыводеСтроки(Элемент, ОформлениеСтроки, ДанныеСтроки)
    // ... логика проверки ключа ...
    Если Соответствует Тогда
        ОформлениеСтроки.Шрифт = ШрифтЖирный;
    Иначе
        ОформлениеСтроки.Шрифт = ШрифтОбычный;
    КонецЕсли;
КонецПроцедуры

Такой подход не только безопаснее с точки зрения памяти, но и работает значительно быстрее, так как исключает операцию инициализации нового объекта при каждой отрисовке строки.

Альтернативные подходы к визуализации связи

Иногда изменение шрифта на жирный может быть неудобным, так как это увеличивает ширину текста и может приводить к микро-скачкам колонок. Рассмотрим другие способы выделения:

  1. Цвет фона: Изменение ОформлениеСтроки.ЦветФона на мягкий оттенок (например, светло-голубой или бледно-желтый) часто воспринимается пользователями лучше.
  2. Установка отбора: Если соответствие строк — это жесткое правило, возможно, стоит использовать Отбор в нижней таблице. Тогда при активации строки сверху, снизу будут видны только связанные строки. Это исключает необходимость в жирном шрифте и упрощает работу с большими объемами данных.

Для реализации отбора в событии ПриАктивизацииСтроки используется следующий код:


Процедура КорректировкаОсновнаяПриАктивизацииСтроки(Элемент)
    ТекущиеДанные = Элемент.ТекущиеДанные;
    Если ТекущиеДанные <> Неопределено Тогда
        // Устанавливаем фильтр для подчиненной таблицы (если это табличное поле с данными)
        КорректировкаРасшифровка.Отбор.Ключ.Установить(ТекущиеДанные.Ключ);
    КонецЕсли;
КонецПроцедуры

Подытоживая наш разбор, отметим, что связка ПриАктивизацииСтроки + ОбновитьСтроки() + ПриВыводеСтроки является классическим и наиболее гибким решением для обычных форм 1С.

← На главную