Как определить адрес ячейки в табличном документе по параметру макета и обратить на нее внимание пользователя?

Программист 1С v8.3 (Управляемые формы)
← На главную

При формировании отчетов или печатных форм в 1С часто возникает задача не просто вывести данные, но и акцентировать внимание пользователя на определенных значениях. Например, если какое-то число выходит за допустимые пределы, нужно подсветить ячейку или вывести предупреждение. Основная проблема заключается в том, чтобы в момент формирования табличного документа из макета точно узнать, в какой ячейке окажется то или иное значение, особенно если макет выводится многократно. При этом хочется избежать сложных и громоздких ручных счетчиков строк и колонок.

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

Основной метод: вычисляем адрес ячейки без счетчиков

Ключ к решению — это правильное использование метода Вывести() объекта ТабличныйДокумент. Многие разработчики воспринимают его как процедуру, которая просто добавляет область макета в итоговый документ. Однако на самом деле это функция, которая возвращает объект ОбластьЯчеекТабличногоДокумента. Этот возвращаемый объект содержит абсолютные координаты (верх, низ, лево, право) вставленного фрагмента в итоговом табличном документе. Именно это позволяет нам точно рассчитать положение любой ячейки внутри этого фрагмента.

Алгоритм действий будет следующим:

  1. Найти относительные координаты ячейки с нужным параметром внутри области макета.
  2. Вывести область макета в итоговый табличный документ и получить в переменную абсолютные координаты выведенной области.
  3. Сложить координаты из п.1 и п.2, чтобы получить финальный адрес ячейки.

Разберем каждый шаг подробнее.

Шаг 1. Находим относительные координаты ячейки в макете

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

Важный момент: нужно проверять, что тип заполнения ячейки — именно Параметр, так как ячейка может быть заполнена текстом или шаблоном.

Посмотрим на пример такой функции. Она будет возвращать массив структур с относительными координатами (номер строки и колонки), так как один и тот же параметр может встречаться в области макета несколько раз.


Функция ПолучитьОтносительныйАдресВОбласти(ОбластьМакета, ИмяПараметра)

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

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

Теперь, имея эту функцию, мы можем легко получить относительное положение ячейки, например: ОтносительныеКоординаты = ПолучитьОтносительныйАдресВОбласти(Макет.ПолучитьОбласть("Строка"), "Номенклатура");

Шаг 2. Выводим область и вычисляем финальный адрес

Теперь самое главное. В цикле формирования отчета, когда мы выводим очередную область, мы сохраняем результат вывода в переменную.


// ... в цикле обхода данных ...

// Заполняем параметры области
ОбластьСтрока.Параметры.Заполнить(ДанныеСтроки);

// Выводим область и получаем ее положение в итоговом документе
ВыведеннаяОбласть = ТабличныйДокументРезультат.Вывести(ОбластьСтрока);

// Теперь в переменной ВыведеннаяОбласть есть свойства Верх, Лево, Низ, Право

Зная относительные координаты из Шага 1 и абсолютные координаты верхнего левого угла выведенной области, мы можем рассчитать итоговый адрес нужной нам ячейки.


// Предположим, мы ищем ячейку с параметром "Сумма"
ОтносительныеКоординаты = ПолучитьОтносительныйАдресВОбласти(ОбластьСтрока, "Сумма");

// Если ячейка найдена (берем первую из найденных для простоты)
Если ОтносительныеКоординаты.Количество() > 0 Тогда
    ОтносительнаяСтрока = ОтносительныеКоординаты[0].Строка;
    ОтносительнаяКолонка = ОтносительныеКоординаты[0].Колонка;
    
    // Рассчитываем абсолютные координаты
    АбсолютнаяСтрока = ВыведеннаяОбласть.Верх + ОтносительнаяСтрока - 1;
    АбсолютнаяКолонка = ВыведеннаяОбласть.Лево + ОтносительнаяКолонка - 1;
    
    // Формируем строковый адрес ячейки
    АдресЯчейки = "R" + АбсолютнаяСтрока + "C" + АбсолютнаяКолонка;
    
    // Теперь у нас есть точный адрес ячейки, и мы можем с ней что-то сделать
    // Например, выделить ее, если есть некое условие
    Если ДанныеСтроки.Сумма > 100000 Тогда
        // ... код для выделения ячейки ...
    КонецЕсли;
КонецЕсли;

Шаг 3. Привлекаем внимание пользователя: почему `СообщениеПользователю` не подходит и что делать

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

Свойство Поле предназначено для привязки к реквизитам формы или колонкам табличной части (например, "Объект.Товары[10].Цена"). Табличный документ на форме — это единый элемент управления, и платформа не предоставляет штатного способа адресовать сообщение к внутренней ячейке через путь вида "РезультатОтчета[R5C10]".

Но есть отличные и даже более наглядные альтернативы.

Альтернатива 1: Изменение оформления ячейки

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


// ... после вычисления АдресЯчейки ...
Если УсловиеВыделения Тогда
    // Получаем область конкретной ячейки по ее адресу
    ПроблемнаяЯчейка = ТабличныйДокументРезультат.Область(АдресЯчейки);
    
    // И меняем ее оформление
    ПроблемнаяЯчейка.ЦветФона = WebЦвета.СветлоРозовый;
    ПроблемнаяЯчейка.Шрифт = Новый Шрифт(ПроблемнаяЯчейка.Шрифт, , Истина); // Делаем жирным
    ПроблемнаяЯчейка.ГоризонтальноеПоложение = ГоризонтальноеПоложениеЭлементаУправления.Центр;
КонецЕсли;

Альтернатива 2: Добавление примечания

Если нужно не просто выделить ячейку, а дать пояснение, идеально подойдет примечание. Оно отображается при наведении курсора мыши на ячейку.


// ... после вычисления АдресЯчейки ...
Если УсловиеВыделения Тогда
    ПроблемнаяЯчейка = ТабличныйДокументРезультат.Область(АдресЯчейки);
    
    // Добавляем текст примечания
    ПроблемнаяЯчейка.Примечание.Текст = "Внимание! Сумма превышает установленный лимит.";
    // Можно сделать так, чтобы примечание отображалось всегда
    ПроблемнаяЯчейка.ОтображатьПримечание = РежимОтображенияПримечанийТабличногоДокумента.Всегда;
КонецЕсли;

Дополнительные возможности

Программное назначение имени ячейке

Если в дальнейшем вам понадобится обращаться к этой ячейке, можно присвоить ей уникальное имя. Это удобнее, чем каждый раз вычислять ее адрес заново.


// Генерируем уникальное имя, например, на основе идентификатора данных
УникальноеИмяЯчейки = "Сумма_" + ДанныеСтроки.Ссылка.УникальныйИдентификатор();

// Присваиваем имя
ТабличныйДокументРезультат.Область(АдресЯчейки).Имя = УникальноеИмяЯчейки;

// Позже можно легко получить эту область по имени
НужнаяОбласть = ТабличныйДокументРезультат.Область(УникальноеИмяЯчейки);

Поиск ячейки по уже выведенному тексту

Если вам нужно найти ячейку не по параметру макета, а по ее текстовому содержимому уже после формирования документа, можно использовать метод НайтиТекст(). Важно помнить, что для поиска всех вхождений его нужно вызывать в цикле, каждый раз передавая ранее найденную область в качестве стартовой точки для следующего поиска.


Функция НайтиВсеОбластиПоТексту(ТабДок, ИскомыйТекст) Экспорт
    
    НайденныеОбласти = Новый Массив;
    
    // Ищем первое вхождение
    НайденнаяОбласть = ТабДок.НайтиТекст(ИскомыйТекст);
    
    Пока НайденнаяОбласть <> Неопределено Цикл
        НайденныеОбласти.Добавить(НайденнаяОбласть);
        
        // Ищем следующее вхождение, начиная с области, следующей за найденной
        НайденнаяОбласть = ТабДок.НайтиТекст(ИскомыйТекст, НайденнаяОбласть);
    КонецЦикла;
    
    Возврат НайденныеОбласти;
    
КонецФункции

// Пример использования
ВсеЯчейкиСНужнымТекстом = НайтиВсеОбластиПоТексту(ТабличныйДокументРезультат, "Итог");
Для Каждого ОбластьИтога Из ВсеЯчейкиСНужнымТекстом Цикл
    ОбластьИтога.ЦветФона = WebЦвета.СветлоЖелтый;
КонецЦикла;

Таким образом, комбинируя эти подходы, вы можете полностью контролировать процесс формирования табличного документа, точно определять положение нужных данных и гибко управлять их визуальным представлением для пользователя.

← На главную