Табличный документ на управляемой форме 1С — это реквизит формы типа ТабличныйДокумент, выведенный полем табличного документа. Он нужен, когда обычной таблицы формы мало: требуется работа «как в Excel», сложное оформление, объединённые ячейки, примечания и расшифровки. Данные в ячейке хранятся либо в свойстве Текст (только строка), либо в Значение (любой тип, включая ссылки) — переключается это свойством СодержитЗначение. Действия пользователя ловятся событиями поля: Выбор, ПриАктивизации, ОбработкаРасшифровки, события перетаскивания.

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

Данные в ячейках: Текст и Значение

У области ячеек два способа хранить данные:

СвойствоТип данныхКогда использовать
ТекстТолько строкаЗаголовки, подписи, вывод отчёта
ЗначениеЧисло, дата, булево, ссылка и т. п.Ввод данных пользователем, хранение ссылок для обработки

Переключатель — СодержитЗначение. При Истина доступно Значение, а Текст формируется по нему автоматически; при Ложь — наоборот. Тип допустимых значений задаётся свойством ТипЗначения.

Для ячеек со значением работает встроенное редактирование: поле ввода для чисел, дат и ссылок, флажок для булева. Если в ячейке поле ввода скрыто, оно появляется только при входе в режим редактирования.

1С
// Готовит ячейку для ввода ссылки на номенклатуру.
Область = ТабличныйДокумент.Область(НомерСтроки, 2);
Область.СодержитЗначение = Истина;
Область.ТипЗначения = Новый ОписаниеТипов("СправочникСсылка.Номенклатура");
Область.Значение = Справочники.Номенклатура.ПустаяСсылка();
Область.Защита = Ложь;

Чтение данных в таблицу значений

Размеры таблицы дают свойства ВысотаТаблицы (строки) и ШиринаТаблицы (колонки). Самый прозрачный способ выгрузки — обход в цикле на сервере:

1С
&НаСервере
Функция ДанныеТабличногоДокумента()

	Результат = Новый ТаблицаЗначений;
	Результат.Колонки.Добавить("Номенклатура");
	Результат.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));

	// Первая строка — шапка, данные со второй
	Для НомерСтроки = 2 По ТабличныйДокумент.ВысотаТаблицы Цикл
		ЯчейкаТовар = ТабличныйДокумент.Область(НомерСтроки, 1);
		ЯчейкаКоличество = ТабличныйДокумент.Область(НомерСтроки, 2);
		Если Не ЗначениеЗаполнено(ЯчейкаТовар.Значение) Тогда
			Продолжить;
		КонецЕсли;
		НоваяСтрока = Результат.Добавить();
		НоваяСтрока.Номенклатура = ЯчейкаТовар.Значение;
		НоваяСтрока.Количество = ЯчейкаКоличество.Значение;
	КонецЦикла;

	Возврат Результат;

КонецФункции

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

1С
Построитель = Новый ПостроительЗапроса;
Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТабличныйДокумент.Область());
Таблица = Построитель.Результат.Выгрузить();

События поля табличного документа

Выбор — двойной щелчок или Enter по ячейке. Координаты берутся из переданной области:

1С
&НаКлиенте
Процедура ТабличныйДокументВыбор(Элемент, Область, СтандартнаяОбработка)

	НомерСтроки = Область.Верх;
	НомерКолонки = Область.Лево;

	Если Область.СодержитЗначение Тогда
		ВыбранноеЗначение = Область.Значение;
	Иначе
		ВыбранныйТекст = Область.Текст;
	КонецЕсли;

	// Например, открыть карточку по ссылке в ячейке
	Если ЗначениеЗаполнено(ВыбранноеЗначение) Тогда
		СтандартнаяОбработка = Ложь;
		ПоказатьЗначение(, ВыбранноеЗначение);
	КонецЕсли;

КонецПроцедуры

ПриАктивизации — смена текущей ячейки. Здесь удобно динамически включать «только просмотр» для строк по их содержимому: текущую область даёт свойство поля ТекущаяОбласть. Обработчик срабатывает часто, поэтому серверные вызовы в нём — плохая идея; если без них никак, используйте ПодключитьОбработчикОжидания с небольшой задержкой.

Перетаскивание

Поведение задают два свойства поля: РазрешитьНачалоПеретаскивания (поле может быть источником) и РазрешитьПеретаскивание (поле может быть приёмником). События распределяются так:

СторонаСобытия
ИсточникНачалоПеретаскивания, ОкончаниеПеретаскивания
ПриёмникПроверкаПеретаскивания, Перетаскивание
Перетаскивание значений между ячейками табличного документа на форме
Перетаскивание значений между ячейками табличного документа на форме

Типичный сценарий — перетащить номенклатуру из списка на форме в ячейку табличного документа: в Перетаскивание приёмника читаем ПараметрыПеретаскивания.Значение и записываем его в нужную ячейку.

Примечания, группировки, расшифровки и фиксация

Примечания. У области есть свойство Примечание типа РисунокТабличногоДокумента, поэтому можно менять не только текст, но и оформление. В ячейке примечание показывается красным треугольником в углу.

1С
ОбластьЯчеек = ТабличныйДокумент.Область(НомерСтроки, НомерКолонки);
ОбластьЯчеек.Примечание.Текст = НСтр("ru = 'Цена изменена вручную'");

Группировки. Группировать можно и строки, и колонки. При выводе отчёта используют НачатьГруппуСтрок / ЗакончитьГруппуСтрок, а для уже выведенной области — её методы Сгруппировать() и Разгруппировать().

Расшифровки работают, когда поле в режиме «только просмотр» или в защищённом режиме. Событие ОбработкаРасшифровки позволяет заменить стандартное действие (параметры — элемент, значение расшифровки и флаг стандартной обработки), а ОбработкаДополнительнойРасшифровки — переопределить меню, которое открывается правой кнопкой.

Фиксация шапки и первых колонок задаётся программно:

1С
ТабличныйДокумент.ФиксацияСверху = 5; // первые пять строк
ТабличныйДокумент.ФиксацияСлева = 1;  // первая колонка

Очистка табличного документа на клиенте: есть ли смысл

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

На клиенте реквизит можно сбросить присваиванием ТабличныйДокумент = Новый ТабличныйДокумент (или Неопределено) — серверного вызова при этом не происходит, и сама операция почти мгновенна. Стандартный путь — ТабличныйДокумент.Очистить() на сервере в той же процедуре, где документ заполняется.

Если замерить полный цикл «очистить — переформировать на сервере — вернуть на клиент» на очень большом документе, клиентская очистка не выигрывает, а иногда проигрывает. Объяснение: при контекстном серверном вызове платформа передаёт на сервер только изменённые реквизиты. Неизменённый заполненный документ не передаётся вовсе, а «новый пустой» — изменённый реквизит, который придётся отправить. Экономия на очистке съедается передачей.

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

Водяной знак на печатной форме программно

Задача с проекта: если документ не согласован, все его печатные формы должны выводиться с подложкой «не для печати». Добавлять картинку в каждый макет — долго, а при доработке через расширение ещё и неудобно; кроме того, пользователь с правом редактировать печатные формы просто удалит рисунок.

Решение проще: картинка хранится один раз в общем макете, а в код печати добавляется присвоение фоновой картинки уже сформированному табличному документу.

  1. Создайте общий макет типа «Табличный документ», например ФоновыйРисунокНеДляПечати, и вставьте в него рисунок с именем ВодянойЗнак.
  2. В общей процедуре, которая вызывается после формирования печатных форм (в БСП для этого есть переопределяемые точки подсистемы печати), добавьте проверку согласования и установку фона:
1С
// Добавляет подложку «не для печати» в печатную форму несогласованного документа.
Процедура ДобавитьВодянойЗнак(ТабличныйДокумент) Экспорт

	МакетПодложки = УправлениеПечатью.МакетПечатнойФормы("ОбщийМакет.ФоновыйРисунокНеДляПечати");
	ТабличныйДокумент.ФоноваяКартинка = МакетПодложки.Рисунки.ВодянойЗнак.Картинка;

КонецПроцедуры
Водяной знак на печатной форме 1С: подложка под содержимым документа
Водяной знак на печатной форме 1С: подложка под содержимым документа

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

Типичные ошибки

  • Ввод в ячейку не работает. У ячейки не снята Защита или поле формы в режиме «только просмотр».
  • Значение ячейки пустое при чтении. Данные записаны в Текст, а читаются из Значение (или наоборот).
  • Тяжёлый код в ПриАктивизации. Каждое перемещение курсора вызывает сервер — форма «тормозит».
  • Перепутаны события перетаскивания. ПроверкаПеретаскивания и Перетаскивание обрабатываются в приёмнике, а не в источнике.
  • Подложка в каждом макете. Хрупко и легко удаляется пользователем; лучше программная установка из общего макета.

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

Коротко

  • Ячейка хранит данные в Текст (строка) или Значение (любой тип) — переключение через СодержитЗначение.
  • Клики и навигацию обрабатывайте событиями Выбор и ПриАктивизации, расшифровки — ОбработкаРасшифровки.
  • Для перетаскивания включите свойства источника и приёмника и обработайте события на нужной стороне.
  • Очищать табличный документ на клиенте перед переформированием обычно бесполезно — делайте это на сервере.
  • Водяной знак добавляйте программно через ФоноваяКартинка из общего макета.