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