Как-то заказчик попросил добавить возможность сохранять табличное поле в файл Excel кнопкой, а не через контекстное меню поля. К сожалению на просторах интернета не нашел готового решения, возможно плохо искал. Правда, в инструментах разработчика от TormozIT есть подобная штука, но увидел её уже намного позже чем сделал своё. Для того, чтобы визуально было более-менее приемлемо - пришлось прикрутить расчёт ширины колонок по содержимому (источник процедуры уже, к сожалению не припомню). Америк не открыл, на оригинальность не претендую, просто делюсь примером, возможно кому-то пригодится. Не исключаю, что данное решение не самое красивое, поэтому советы и пожелания постараюсь учесть/дополнить в статье. Полученный в функции табличный документ сохранить в файл уже можно, соответственно, одной строкой текста (ТД.Записать("ИмяФайла",ТипФайлаТабличногоДокумента.XLSX)).
Подходит для любой конфигурации на обычных формах.
Функция ТабличноеПолеВТабличныйДокумент(ТабличноеПоле)
ТабДокумент = Новый ТабличныйДокумент;
ГраницаСлева = ?(ТабличноеПоле.ВертикальныеЛинии , Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная, 1), Неопределено);
ГраницаСправа = ?(ТабличноеПоле.ВертикальныеЛинии , Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная, 1), Неопределено);
ГраницаСверху = ?(ТабличноеПоле.ГоризонтальныеЛинии, Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная, 1), Неопределено);
ГраницаСнизу = ?(ТабличноеПоле.ГоризонтальныеЛинии, Новый Линия(ТипЛинииЯчейкиТабличногоДокумента.Сплошная, 1), Неопределено);
НомерСтроки = 0;
Для Каждого Колонка Из ТабличноеПоле.Колонки Цикл
Если Колонка.Данные = "" Тогда
Продолжить;
КонецЕсли;
ИндексКолонки = ТабличноеПоле.Колонки.Индекс(Колонка);
КолонкаТабличногоПоля = ТабДокумент.Область(, ИндексКолонки+1, , ИндексКолонки+1);
КолонкаТабличногоПоля.ШиринаКолонки = Колонка.Ширина;
КонецЦикла;
Если ТабличноеПоле.Шапка Тогда
НомерСтроки = НомерСтроки + 1;
Для Каждого Колонка Из ТабличноеПоле.Колонки Цикл
ИндексКолонки = ТабличноеПоле.Колонки.Индекс(Колонка);
ОбластьЯчейки = ТабДокумент.Область(НомерСтроки, ИндексКолонки+1, НомерСтроки, ИндексКолонки+1);
ОбластьЯчейки.Текст = Колонка.ТекстШапки;
ОбластьЯчейки.ЦветТекста = ?(Колонка.ЦветТекстаШапки = ВидЦвета.АвтоЦвет, ЦветаСтиля.ЦветТекстаШапкиТаблицы, Колонка.ЦветТекстаШапки);
ОбластьЯчейки.ЦветФона = ?(Колонка.ЦветФонаШапки.Вид = ВидЦвета.АвтоЦвет, ЦветаСтиля.ЦветФонаКнопки, Колонка.ЦветФонаШапки);
ОбластьЯчейки.ЦветРамки = ?(ТабличноеПоле.ЦветРамки.Вид = ВидЦвета.АвтоЦвет, ЦветаСтиля.ЦветРамки, ТабличноеПоле.ЦветРамки);
ОбластьЯчейки.Шрифт = Колонка.ШрифтШапки;
ОбластьЯчейки.ГоризонтальноеПоложение = Колонка.ГоризонтальноеПоложениеВШапке;
ОбластьЯчейки.Обвести(ГраницаСлева, ГраницаСверху, ГраницаСправа, ГраницаСнизу);
КонецЦикла;
КонецЕсли;
Построитель = Новый ПостроительЗапроса;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТабличноеПоле.Значение);
Для Каждого ЭлементОтбораИсточник Из ТабличноеПоле.ОтборСтрок Цикл
Если ЭлементОтбораИсточник.Использование = Ложь Тогда
Продолжить;
КонецЕсли;
ЭлементОтбораПриемник = Построитель.Отбор.Добавить(ЭлементОтбораИсточник.ПутьКДанным);
ЭлементОтбораПриемник.Использование = ЭлементОтбораИсточник.Использование;
ЭлементОтбораПриемник.ВидСравнения = ЭлементОтбораИсточник.ВидСравнения;
ЭлементОтбораПриемник.Значение = ЭлементОтбораИсточник.Значение;
ЭлементОтбораПриемник.ЗначениеС = ЭлементОтбораИсточник.ЗначениеС;
ЭлементОтбораПриемник.ЗначениеПо = ЭлементОтбораИсточник.ЗначениеПо;
КонецЦикла;
Построитель.Выполнить();
Результат = Построитель.Результат;
Выборка = Результат.Выбрать();
Пока Выборка.Следующий() Цикл
НомерСтроки = НомерСтроки + 1;
Для Каждого Колонка Из ТабличноеПоле.Колонки Цикл
ИндексКолонки = ТабличноеПоле.Колонки.Индекс(Колонка);
ОбластьЯчейки = ТабДокумент.Область(НомерСтроки, ИндексКолонки+1, НомерСтроки, ИндексКолонки+1);
ОбластьЯчейки.ЦветФона = ?(Колонка.ЦветФонаПоля.Вид = ВидЦвета.АвтоЦвет, ЦветаСтиля.ЦветФонаПоля, Колонка.ЦветФонаПоля);
ОбластьЯчейки.ЦветРамки = ?(ТабличноеПоле.ЦветРамки.Вид = ВидЦвета.АвтоЦвет, ЦветаСтиля.ЦветРамки, ТабличноеПоле.ЦветРамки);
ОбластьЯчейки.ЦветТекста = ?(Колонка.ЦветТекстаПоля = ВидЦвета.АвтоЦвет, ЦветаСтиля.ЦветТекстаПоля, Колонка.ЦветТекстаПоля);
ОбластьЯчейки.Шрифт = Колонка.ШрифтТекста;
ОбластьЯчейки.ГоризонтальноеПоложение = Колонка.ГоризонтальноеПоложениеВКолонке;
ОбластьЯчейки.Обвести(ГраницаСлева, ГраницаСверху, ГраницаСправа, ГраницаСнизу);
ФорматнаяСтрока = "";
Если Колонка.Данные = "" Тогда
ЗначениеЯчейки = Выборка[Колонка.Имя];
ТипКолонки = Результат.Колонки[Колонка.Имя].ТипЗначения;
Иначе
ЗначениеЯчейки = Выборка[Колонка.Данные];
ТипКолонки = Результат.Колонки[Колонка.Данные].ТипЗначения;
КонецЕсли;
Если ТипЗнч(ЗначениеЯчейки) = Тип("Число") Тогда
КвалификаторыЧисла = ТипКолонки.КвалификаторыЧисла;
ФорматнаяСтрока = "ЧЦ=" + КвалификаторыЧисла.Разрядность + "; ЧДЦ=" + КвалификаторыЧисла.РазрядностьДробнойЧасти;
ИначеЕсли ТипЗнч(ЗначениеЯчейки) = Тип("Дата") Тогда
КвалификаторыДаты = ТипКолонки.КвалификаторыДаты;
Если КвалификаторыДаты.ЧастиДаты = ЧастиДаты.Дата Тогда
ФорматнаяСтрока = "ДФ=dd.MM.yyyy";
ИначеЕсли КвалификаторыДаты.ЧастиДаты = ЧастиДаты.Время Тогда
ФорматнаяСтрока = "ДФ=HH:mm:ss";
КонецЕсли;
КонецЕсли;
Если ЗначениеЗаполнено(ФорматнаяСтрока) Тогда
ОбластьЯчейки.Текст = Формат(ЗначениеЯчейки, ФорматнаяСтрока);
ИНаче
ОбластьЯчейки.Текст = ЗначениеЯчейки;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Если ТабличноеПоле.Подвал Тогда
НомерСтроки = НомерСтроки + 1;
Для Каждого Колонка Из ТабличноеПоле.Колонки Цикл
ИндексКолонки = ТабличноеПоле.Колонки.Индекс(Колонка);
ОбластьЯчейки = ТабДокумент.Область(НомерСтроки, ИндексКолонки+1, НомерСтроки, ИндексКолонки+1);
ОбластьЯчейки.Текст = Колонка.ТекстПодвала;
ОбластьЯчейки.ЦветТекста = ?(Колонка.ЦветТекстаПодвала = ВидЦвета.АвтоЦвет, ЦветаСтиля.ЦветТекстаПодвалаТаблицы, Колонка.ЦветТекстаПодвала);
ОбластьЯчейки.ЦветФона = ?(Колонка.ЦветФонаШапки.Вид = ВидЦвета.АвтоЦвет, ЦветаСтиля.ЦветФонаКнопки, Колонка.ЦветФонаПодвала);
ОбластьЯчейки.ЦветРамки = ?(ТабличноеПоле.ЦветРамки.Вид = ВидЦвета.АвтоЦвет, ЦветаСтиля.ЦветРамки, ТабличноеПоле.ЦветРамки);
ОбластьЯчейки.Шрифт = Колонка.ШрифтПодвала;
ОбластьЯчейки.ГоризонтальноеПоложение = Колонка.ГоризонтальноеПоложениеВПодвале;
ОбластьЯчейки.Обвести(ГраницаСлева, ГраницаСверху, ГраницаСправа, ГраницаСнизу);
КонецЦикла;
КонецЕсли;
РасчетШириныКолонок(ТабДокумент,200,150);
Возврат ТабДокумент;
КонецФункции
// Процедура - Расчет ширины колонок
//
// Параметры:
// ТабличныйДокумент - ТабличныйДокумент - Табличный документ, в котором будет перерасчитана ширина колонок
// МаксимальноеКоличествоСтрок - Число - Максимальное количество строк, которые будут использованы для расчета ширин колонок
// МаксимальнаяШиринаКолонки - Число - Ограничение максимальной ширины колонки
//
Процедура РасчетШириныКолонок(ТабличныйДокумент,МаксимальноеКоличествоСтрок,МаксимальнаяШиринаКолонки)
Перем КонечнаяСтрока, НачальнаяСтрока, ТекущаяКолонка, ТекущаяСтрока, НачалоДанных;
Перем ОбластьШапки, ОбластьПодвала;
Перем ШиринаКолонки, ТекстЯчейки, НомерСтрокиТекста;
Перем ШириныКолонок;
// Массив, в который будут помещаться ширины колонок
ШириныКолонок = Новый Массив;
// Инициализируем начальные строки
НачальнаяСтрока = 0;
НачалоДанных = 0;
КонечнаяСтрока = НачальнаяСтрока + МаксимальноеКоличествоСтрок;
// Ограничим конечную строку
КонечнаяСтрока = Мин(КонечнаяСтрока, ТабличныйДокумент.ВысотаТаблицы);
// Переберем все колонки
Для ТекущаяКолонка = 1 По ТабличныйДокумент.ШиринаТаблицы Цикл
МаксимальнаяШиринаТекстаЯчейки = 0;
// Переберем строки, которые будут использованы для расчета ширин колонок
Для ТекущаяСтрока = НачальнаяСтрока По КонечнаяСтрока Цикл
ШиринаКолонки = 0;
// Получим область текущей ячейки
ОбластьЯчейки = ТабличныйДокумент.Область(ТекущаяСтрока, ТекущаяКолонка);
ТекстЯчейки = ОбластьЯчейки.Текст;
// Для каждой строки из текста ячейки рассчитаем количество символов в строке
Для НомерСтрокиТекста = 1 По СтрЧислоСтрок(ТекстЯчейки) Цикл
ШиринаТекстаЯчейки = СтрДлина(СтрПолучитьСтроку(ТекстЯчейки, НомерСтрокиТекста));
Если ШиринаТекстаЯчейки > МаксимальнаяШиринаТекстаЯчейки Тогда
МаксимальнаяШиринаТекстаЯчейки = ШиринаТекстаЯчейки;
КонецЕсли;
ШиринаКолонки = Макс(ШиринаКолонки, МаксимальнаяШиринаТекстаЯчейки);
КонецЦикла;
Если ШиринаКолонки > МаксимальнаяШиринаКолонки Тогда
// Ограничим ширину колонки
ШиринаКолонки = МаксимальнаяШиринаКолонки;
КонецЕсли;
Если ШиринаКолонки <> 0 Тогда
// Ширина колонки рассчитана
// Определим, сколько ячеек по ширине используется в области для текущей ячейки
КоличествоКолонок = ОбластьЯчейки.Право - ОбластьЯчейки.Лево;
// Переберем все ячейки, расположенные в области
Для НомерКолонки = 0 По КоличествоКолонок Цикл
Если ШириныКолонок.ВГраница() > ТекущаяКолонка - 1 + НомерКолонки Тогда
// В массиве ширин колонок уже был элемент для текущей колонки
Если ШириныКолонок[ТекущаяКолонка - 1 + НомерКолонки] = Неопределено Тогда
// Значение ширины колонки еще не было установлено
ШириныКолонок[ТекущаяКолонка - 1 + НомерКолонки] = ШиринаКолонки / (КоличествоКолонок + 1);
Иначе
// Значение ширины колонки уже было установлено
// Вычислим максимум ширины колонки
ШириныКолонок[ТекущаяКолонка - 1 + НомерКолонки] =
Макс(ШириныКолонок[ТекущаяКолонка - 1 + НомерКолонки], ШиринаКолонки / (КоличествоКолонок + 1));
КонецЕсли;
Иначе
// В массиве ширин колонок еще не было элемента для данной колонки
// Добавим элемент в массив ширин колонок
ШириныКолонок.Вставить(ТекущаяКолонка - 1 + НомерКолонки, ШиринаКолонки / (КоличествоКолонок + 1));
КонецЕсли;
КонецЦикла;
КонецЕсли; // Конец Условия ШиринаКолонки <> 0
КонецЦикла; // Конец цикла перебора строк
КонецЦикла; // Конец цикла перебора колонок
// Переберем все элементы в массиве вычисленных ширин колонок
Для ТекущаяКолонка = 0 По ШириныКолонок.ВГраница() Цикл
Если ШириныКолонок[ТекущаяКолонка] <> Неопределено Тогда
// Ширина колонок установлена
// Установим ширину области ячеек
ТабличныйДокумент.Область(, ТекущаяКолонка +1, НачалоДанных, ТекущаяКолонка + 2).ШиринаКолонки = ШириныКолонок[ТекущаяКолонка] + 1;
КонецЕсли;
КонецЦикла;
КонецПроцедуры