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

Табличная часть
Хотел бы отметить, что здесь идет речь о табличных частях. Про программную модификацию динамических списков есть отдельная статья.
Вот мы и добрались до табличной части. В принципе такая же самые принципы. Главное отличие в том, что нам сначала нужно вывести таблицу формы, а затем привязать к этой таблице колонки. Просто обращаем внимание на поле «ПутьКДанным».
// ТАБЛИЧНАЯ ЧАСТЬ
НовыйЭлемент = Элементы.Добавить("МОД_ГрафикПлатежей", Тип("ТаблицаФормы"), Элементы.МОД_СвернутаяГруппа);
НовыйЭлемент.ПутьКДанным = "Объект.ГрафикПлатежей";
НовыйЭлемент.Отображение = ОтображениеТаблицы.Список;
НовыйЭлемент.УстановитьДействие("Выбор", "МОД_ГрафикПлатежейВыбор");
// ДАТА
НовыйЭлемент = Элементы.Добавить("МОД_ГрафикПлатежейДата", Тип("ПолеФормы"), Элементы.МОД_ГрафикПлатежей);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.Заголовок = "Дата";
НовыйЭлемент.ПутьКДанным = "Объект.ГрафикПлатежей.Дата";
// СУММА
НовыйЭлемент = Элементы.Добавить("МОД_ГрафикПлатежейСумма", Тип("ПолеФормы"), Элементы.МОД_ГрафикПлатежей);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.Заголовок = "Сумма";
НовыйЭлемент.ПутьКДанным = "Объект.ГрафикПлатежей.Сумма";
НовыйЭлемент.УстановитьДействие("ПриИзменении", "МОД_ГрафикПлатежейСуммаПриИзменении");
Но табличная часть получилась уродской. Дата в одном конце таблицы, сумма в другом…

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

Красивее же?!
Реквизиты формы
При добавлении заглушки мы подобрались к программному созданию реквизитов формы. То есть тех реквизитов, которые мы не хотим сохранять автоматически в объекте (документе или справочнике). Но хотим выводить в них какие то служебные данные и не только.
Давайте сразу сделаем таблицу значений.
Я обычно подготавливаю необходимые типы данных, которые буду использовать в дальнейшем. Во первых они довольно длинные, во вторых они часто повторяющиеся.
// Описание квалификторов
КвалификаторЧислоНеотрицательное15_2 = Новый КвалификаторыЧисла(15, 2, ДопустимыйЗнак.Неотрицательный);
КвалификаторЧислоНеотрицательное10_3 = Новый КвалификаторыЧисла(10, 3, ДопустимыйЗнак.Неотрицательный);
КвалификаторСтрока100 = Новый КвалификаторыСтроки(100, ДопустимаяДлина.Переменная);
// Описание типов
ТипКонтрагентСсылка = Новый ОписаниеТипов("СправочникСсылка.Номенклатура");
ТипНоменклатураСсылка = Новый ОписаниеТипов("СправочникСсылка.Номенклатура");
ТипТаблицаЗначений = Новый ОписаниеТипов("ТаблицаЗначений");
ТипЧислоНеотрицательное15_2 = Новый ОписаниеТипов("Число",,,КвалификаторЧислоНеотрицательное15_2);
ТипЧислоНеотрицательное10_3 = Новый ОписаниеТипов("Число",,,КвалификаторЧислоНеотрицательное10_3);
ТипСтрока100 = Новый ОписаниеТипов("Строка",,,,КвалификаторСтрока100);
Далее добавляем реквизиты на формы
МассивДобавляемыхРеквизитов = Новый Массив;
//Реквизит формы
МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы("МОД_Контрагент", ТипКонтрагентСсылка,,"Контрагент"));
// Табличная часть
МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы("МОД_ТаблицаТоваров", ТипТаблицаЗначений));
// Колонки табличной части
МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы("Номенклатура", ТипНоменклатураСсылка, "МОД_ТаблицаТоваров"));
МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы("Количество", ТипЧислоНеотрицательное10_3, "МОД_ТаблицаТоваров"));
МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы("Цена", ТипЧислоНеотрицательное15_2, "МОД_ТаблицаТоваров"));
МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы("Сумма", ТипЧислоНеотрицательное15_2, "МОД_ТаблицаТоваров"));
МассивДобавляемыхРеквизитов.Добавить(Новый РеквизитФормы("Комментарий", ТипСтрока100, "МОД_ТаблицаТоваров"));
ИзменитьРеквизиты(МассивДобавляемыхРеквизитов);
А теперь генерируем элементы
// 1. Добавим группу в которую будем складывать реквизиты формы
НовыйЭлемент = Элементы.Добавить("МОД_ГруппаТаблицаЗначений",Тип("ГруппаФормы"), Неопределено);
НовыйЭлемент.Вид = ВидГруппыФормы.ОбычнаяГруппа;
НовыйЭлемент.Заголовок = "Группа таблица значений";
НовыйЭлемент.Отображение = ОтображениеОбычнойГруппы.Нет;
НовыйЭлемент.ОтображениеУправления = ОтображениеУправленияОбычнойГруппы.ГиперссылкаЗаголовка;
НовыйЭлемент.Поведение = ПоведениеОбычнойГруппы.Свертываемая;
НовыйЭлемент.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная;
// 2. Сделаем группу свернутой
Элементы.МОД_ГруппаТаблицаЗначений.Скрыть();
Элементы.МОД_ГруппаТаблицаЗначений.Группировка = ГруппировкаПодчиненныхЭлементовФормы.Вертикальная;
// 3. Выведем реквизит контрагент
НовыйЭлемент = Элементы.Добавить("МОД_Контрагент", Тип("ПолеФормы"), Элементы.МОД_ГруппаТаблицаЗначений);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.АвтоОтметкаНезаполненного = Истина;
НовыйЭлемент.Заголовок = "Контрагент";
НовыйЭлемент.ПутьКДанным = "МОД_Контрагент"; // имя реквизита формы
НовыйЭлемент.УстановитьДействие("ПриИзменении", "МОД_КонтрагентПриИзменении");
// 4. Выведем таблицу значений
НовыйЭлемент = Элементы.Добавить("МОД_ТаблицаТоваров", Тип("ТаблицаФормы"), Элементы.МОД_ГруппаТаблицаЗначений);
НовыйЭлемент.ПутьКДанным = "МОД_ТаблицаТоваров";
НовыйЭлемент.Отображение = ОтображениеТаблицы.Список;
НовыйЭлемент.УстановитьДействие("Выбор", "МОД_ТаблицаТоваровВыбор");
// 5. Выведем колонки
// НОМЕНКЛАТУРА
НовыйЭлемент = Элементы.Добавить("МОД_ТаблицаТоваровНоменклатура", Тип("ПолеФормы"), Элементы.МОД_ТаблицаТоваров);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.Заголовок = "Номенклатура";
НовыйЭлемент.ПутьКДанным = "МОД_ТаблицаТоваров.Номенклатура";
// КОЛИЧЕСТВО
НовыйЭлемент = Элементы.Добавить("МОД_ТаблицаТоваровКоличество", Тип("ПолеФормы"), Элементы.МОД_ТаблицаТоваров);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.Заголовок = "Кол-во";
НовыйЭлемент.ПутьКДанным = "МОД_ТаблицаТоваров.Количество";
НовыйЭлемент.УстановитьДействие("ПриИзменении", "МОД_КоличествоПриИзменении");
// ЦЕНА
НовыйЭлемент = Элементы.Добавить("МОД_ТаблицаТоваровЦена", Тип("ПолеФормы"), Элементы.МОД_ТаблицаТоваров);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.Заголовок = "Цена";
НовыйЭлемент.ПутьКДанным = "МОД_ТаблицаТоваров.Цена";
НовыйЭлемент.УстановитьДействие("ПриИзменении", "МОД_ЦенаПриИзменении");
// СУММА
НовыйЭлемент = Элементы.Добавить("МОД_ТаблицаТоваровСумма", Тип("ПолеФормы"), Элементы.МОД_ТаблицаТоваров);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.ТолькоПросмотр = Истина;
НовыйЭлемент.Заголовок = "Сумма";
НовыйЭлемент.ПутьКДанным = "МОД_ТаблицаТоваров.Сумма";
// КОММЕНТАРИЙ
НовыйЭлемент = Элементы.Добавить("МОД_ТаблицаТоваровКомментарий", Тип("ПолеФормы"), Элементы.МОД_ТаблицаТоваров);
НовыйЭлемент.Вид = ВидПоляФормы.ПолеВвода;
НовыйЭлемент.Заголовок = "Комментарий";
НовыйЭлемент.ПутьКДанным = "МОД_ТаблицаТоваров.Комментарий";

Ну вроде выглядит неплохо.
Кнопки
Добавление кнопки делается в 3 этапа
- Создание команды
- Размещение команды на форме
- Определение обработчика команды
// 1. Создание команды
НоваяКоманда = ЭтаФорма.Команды.Добавить("МОД_КомандаСказатьПривет");
НоваяКоманда.Заголовок = "Сказать привет!";
НоваяКоманда.Действие = "МОД_КомандаСказатьПривет"; //Имя клиентской процедуры
// 2. Размещение в командной панели
НовыйЭлемент = ЭтаФорма.Элементы.Добавить("КнопкаСказатьПривет", Тип("КнопкаФормы"), Элементы.ФормаКоманднаяПанель);
НовыйЭлемент.Заголовок = "Привет!";
НовыйЭлемент.ИмяКоманды = "МОД_КомандаСказатьПривет";
Обработчик команды — это просто клиентская процедура в модуле формы.
&НаКлиенте
Процедура МОД_КомандаСказатьПривет(Команда)
Сообщение = Новый СообщениеПользователю;
Сообщение.Текст = "Привет, программист!";
Сообщение.Сообщить();
КонецПроцедуры

Меню и подменю
Кнопку мы добавляли в стандартную командную панель формы. Подобным образом можно размещать в командные панели динамического списка, табличной части итп. Но только вместо Элементы.ФормаКоманднаяПанель, было бы Элементы.ИмяТабличнойЧасти.КоманднаяПанель
Но давайте накодим свою командную панель с кнопками и подменю.
// Добавим в корень формы командную панель
НоваяКоманднаяПанель = Элементы.Добавить("МОД_КоманднаяПанельСПодменю", Тип("ГруппаФормы"), Неопределено);
НоваяКоманднаяПанель.Вид = ВидГруппыФормы.КоманднаяПанель;
// Разместим кнопку в командной панели
НоваяКоманда = Команды.Добавить("МОД_КомандаСказатьХеллоу");
НоваяКоманда.Заголовок = "Хеллоу";
НоваяКоманда.Действие = "МОД_КомандаСказатьХеллоу"; //Имя клиентской процедуры
НовыйЭлемент = Элементы.Добавить("МОД_КнопкаСказатьХеллоу", Тип("КнопкаФормы"), Элементы.МОД_КоманднаяПанельСПодменю);
//НовыйЭлемент.Заголовок = "Хеллоу"; У кнопки не обязательно переопределять заголовок, если он уже установлен в заголовке команды
НовыйЭлемент.ИмяКоманды = "МОД_КомандаСказатьХеллоу";
// Добавим подменю в командную панель
НовоеПодменю = Элементы.Добавить("МОД_ПодменюКоманднаяПанель", Тип("ГруппаФормы"), Элементы.МОД_КоманднаяПанельСПодменю);
НовоеПодменю.Заголовок = "Это заголовок подменю";
НовоеПодменю.Вид = ВидГруппыФормы.Подменю;
// Разместим кнопку №1 в подменю
НоваяКоманда = Команды.Добавить("МОД_КомандаСказатьКоманднаяПанель");
НоваяКоманда.Заголовок = "Сказать командная панель";
НоваяКоманда.Действие = "МОД_КомандаСказатьКоманднаяПанель"; //Имя клиентской процедуры
НовыйЭлемент = Элементы.Добавить("МОД_КнопкаСказатьКоманднаяПанель", Тип("КнопкаФормы"), Элементы.МОД_ПодменюКоманднаяПанель);
НовыйЭлемент.Заголовок = "Сказать командная панель";
НовыйЭлемент.ИмяКоманды = "МОД_КомандаСказатьКоманднаяПанель";
// Разместим кнопку №2 в подменю
НоваяКоманда = Команды.Добавить("МОД_КомандаСказатьПока");
НоваяКоманда.Заголовок = "Сказать пока";
НоваяКоманда.Действие = "МОД_КомандаСказатьПока"; //Имя клиентской процедуры
НовыйЭлемент = Элементы.Добавить("МОД_КнопкаСказатьПока", Тип("КнопкаФормы"), Элементы.МОД_ПодменюКоманднаяПанель);
НовыйЭлемент.Заголовок = "Сказать пока";
НовыйЭлемент.ИмяКоманды = "МОД_КомандаСказатьПока";
Получаем такой результат:

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

// Вставим кнопку №3 между кнопкой №1 и №2
НоваяКоманда = Команды.Добавить("МОД_КомандаНомерТри");
НоваяКоманда.Заголовок = "Сказать пока";
НоваяКоманда.Действие = "МОД_КомандаНомерТри"; //Имя клиентской процедуры
НовыйЭлемент = Элементы.Вставить("МОД_КнопкаМеждуПервойИВторой", Тип("КнопкаФормы"), Элементы.МОД_ПодменюКоманднаяПанель, Элементы.МОД_КнопкаСказатьПока);
НовыйЭлемент.Заголовок = "Кнопка между";
НовыйЭлемент.ИмяКоманды = "МОД_КомандаНомерТри";
Результат:

Всё тоже самое можно использовать для других элементов на форме.
Страницы
Это вообще easy peasy lemon squeezy
// 1. Создадим группу страницы, чтобы размещать на ней непосредственно страницы
СтраницыФормы = Элементы.Добавить("МОД_СтраницыФормы", Тип("ГруппаФормы"), Неопределено);
СтраницыФормы.Вид = ВидГруппыФормы.Страницы;
// 2. Страница 1
НоваяСтраница = Элементы.Добавить("МОД_Страница1", Тип("ГруппаФормы"), Элементы.МОД_СтраницыФормы);
НоваяСтраница.Вид = ВидГруппыФормы.Страница;
НоваяСтраница.Заголовок = "Страница 1";
// 3. Страница 1
НоваяСтраница = Элементы.Добавить("МОД_Страница2", Тип("ГруппаФормы"), Элементы.МОД_СтраницыФормы);
НоваяСтраница.Вид = ВидГруппыФормы.Страница;
НоваяСтраница.Заголовок = "Страница 2";
// 4. Разместим на страницах что нибудь, чтобы они в принципе отображались.
// пустые страницы на форме отображаться не будут
НоваяДекорация = Элементы.Добавить("МОД_ДекарацияСтраница1", Тип("ДекорацияФормы"), Элементы.МОД_Страница1);
НоваяДекорация.Заголовок = "Декарация страница 1";
НоваяДекорация = Элементы.Добавить("МОД_ДекарацияСтраница2", Тип("ДекорацияФормы"), Элементы.МОД_Страница2);
НоваяДекорация.Заголовок = "Декарация страница 2";

Перемещение элементов формы
А давайте теперь контрагента из группы с табличной значений переместим на страницу 2. И поставим его перед декорацией.
Элементы.Переместить(Элементы.МОД_Контрагент, Элементы.МОД_Страница2, Элементы.МОД_ДекарацияСтраница2);

Динамические списки
Про динамические списки у меня есть отдельная статья, посвященная только им.
Лайфхаки
Для некоторого упрощения можно использовать использовать библиотеки для упрощенной генерации элементов форм. Первая попавшаяся: https://infostart.ru/1c/articles/1270443/
Интересный инструмент — «Декомпилятор управляемых форм» https://infostart.ru/public/304736/ Поддерживает не все свойства элементов форм. Да и сгенерированный код получается немного «грязноватым», но бывает очень удобно накидать в конфигураторе элементов и в режиме предприятия просто сгенерировать значительную часть кода.
Файлы и заключение
Когда соберетесь модифицировать формы, то не пишите весь код в событии ПриСозданииНаСервере, а выносите блоками. Блок с табличной частью, блок с какой то одной группой итп. Я к такому привык очень быстро, когда при разработке приложений под ОС Android пересел с View на JetPack Compose. В котором вообще весь интерфейс генерируется кодом.
Подготовленный пример в виде внешней обработки, который работает на БП, РТ, УНФ, УТ, КА2, ERP


