Почему разъезжается табличный документ 1С при раскраске ячеек и как это исправить?

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

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

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

Выясняем причину: природа относительной адресации

Давайте проанализируем типичную ситуацию. Разработчик получает область макета с помощью метода ПолучитьОбласть("Таблица"). В исходном макете эта секция расположена, к примеру, на 11-й и 12-й строках. Логично предположить, что для раскраски двух ячеек во второй колонке нужно обратиться к ним по адресу: ОбластьТаблица.Область("R11C2:R12C2"). Но именно здесь кроется главная ошибка.

Когда мы вызываем метод ПолучитьОбласть(), платформа 1С копирует указанную секцию и создает на ее основе изолированный, самостоятельный табличный документ. Координаты внутри этой новой локальной области всегда сбрасываются и начинаются с R1C1 (строка 1, колонка 1), независимо от того, на каких строках эта область находилась в исходном шаблоне конфигуратора.

Если реальная высота полученной области составляет всего 2 строки, а в коде выполняется обращение к 11-й строке через Область("R11C2:R12C2"), платформа 1С автоматически «растягивает» эту локальную область до 12 строк, заполняя пустые строки значениями по умолчанию. При последующем вызове метода Вывести() в итоговый документ попадает не компактная строка, а огромный пустой блок из 12 строк с раскрашенным низом. Это и приводит к визуальному разрыву таблицы.

Решение №1: Исправление относительных координат

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

ОбластьТаблица.Область("R1C2:R2C2").ЦветФона = WebЦвета.Зеленый;

Однако при использовании этого метода в цикле нас подстерегает еще одна проблема — проблема «грязного» шаблона. Если мы получаем область макета один раз вне цикла (что абсолютно верно с точки зрения производительности), любые изменения свойств ее ячеек будут сохраняться в памяти.

Если в цикле обхода данных мы покрасим ячейку в зеленый цвет при выполнении какого-то условия, то все последующие строки, выводимые следом, также останутся зелеными, даже если они не соответствуют условию. Чтобы избежать этого эффекта, нам придется принудительно возвращать стандартный цвет в ветке Иначе:


Пока ВыборкаДетЗаписи.Следующий() Цикл
    ОбластьТаблица.Параметры.Заполнить(ВыборкаДетЗаписи);
    
    Если ВыборкаДетЗаписи.ВажноеУсловие Тогда
        ОбластьТаблица.Область("R1C2:R2C2").ЦветФона = WebЦвета.Зеленый;
    Иначе
        // Возвращаем авто-цвет (сбрасываем оформление)
        ОбластьТаблица.Область("R1C2:R2C2").ЦветФона = Новый Цвет;
    КонецЕсли;
    
    ТабличныйДокумент.Вывести(ОбластьТаблица);
КонецЦикла;

Решение №2: Оформление ячеек после вывода (Рекомендуемый способ)

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

Метод ТабличныйДокумент.Вывести() возвращает специальный объект типа ОбластьЯчеекТабличногоДокумента. Эта возвращаемая область содержит абсолютные координаты только что выведенного блока строк уже непосредственно в результирующем документе. У этого объекта есть свойства Верх, Низ, Лево и Право.

Давайте посмотрим на пример реализации этого подхода:


// Получаем область один раз вне цикла, макет остается чистым
ОбластьТаблица = Макет.ПолучитьОбласть("Таблица"); 

Пока ВыборкаДетЗаписи.Следующий() Цикл
    // Заполняем параметры области данными из выборки
    ОбластьТаблица.Параметры.Заполнить(ВыборкаДетЗаписи);
    
    // Выводим область и сразу получаем её абсолютные координаты в результирующем документе
    ОбластьОформления = ТабличныйДокумент.Вывести(ОбластьТаблица);
    
    // Раскрашиваем ячейки непосредственно в итоговом документе
    Если ВыборкаДетЗаписи.ВажноеУсловие Тогда
        // Красим только что выведенные строки (с Верх по Низ) во 2-й колонке
        ТабличныйДокумент.Область(ОбластьОформления.Верх, 2, ОбластьОформления.Низ, 2).ЦветФона = WebЦвета.Зеленый;
    КонецЕсли;
КонецЦикла;

Преимущества этого метода очевидны:

  1. Исходный макет ОбластьТаблица всегда остается чистым. Нам не нужно писать ветку Иначе для сброса цвета фона.
  2. Мы работаем с реальными абсолютными координатами выведенной строки, что полностью исключает риск «растягивания» макета.
  3. Высокая производительность кода, так как нам не нужно заново переполучать область из макета на каждой итерации цикла.

Решение №3: Отказ от жесткого кодирования адресов ячеек

Использование строковых литералов формата "R1C2:R2C2" считается плохим стилем разработки по ряду причин. Если в будущем аналитик или дизайнер изменит структуру макета (например, добавит новую колонку слева), целевая колонка сместится с индекса 2 на индекс 3. Код продолжит красить вторую колонку, выводя неверное оформление и заставляя разработчика вручную переписывать программный код.

Чтобы сделать код гибким и устойчивым к изменениям, воспользуемся альтернативными подходами:

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

ОбластьТаблица.Область("ЯчейкаСтатуса").ЦветФона = WebЦвета.Зеленый;

Платформа 1С самостоятельно определит, где именно внутри выведенной строки находится именованная ячейка, даже если вы добавите новые колонки в макет.

Б. Использование числовых параметров области
Вместо текстового формата адресации "R1C2" лучше использовать обращение через числовые индексы метода Область(НачСтрока, НачКолонка, КонСтрока, КонКолонка), где номера колонок вынесены в понятные константы или переменные в начале процедуры:


КолонкаСуммы = 2; // Номер колонки легко поменять в одном месте кода

// В цикле при выводе:
ТабличныйДокумент.Область(ОбластьОформления.Верх, КолонкаСуммы, ОбластьОформления.Низ, КолонкаСуммы).ЦветФона = WebЦвета.Зеленый;

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

← На главную