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