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