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