Как сделать сворачиваемые и разворачиваемые строки («плюсики») в печатной форме 1С 7.7?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При формировании сложных отчетов в среде 1С:Предприятие 7.7 разработчики часто сталкиваются с необходимостью вывода иерархических данных. Идеальный вариант представления такой информации — древовидная структура, аналогичная группировкам в Microsoft Excel, когда пользователь может кликом по кнопке-плюсику [+] развернуть сводные данные по контрагенту или номенклатурной группе и детально изучить входящие в нее строки.

По умолчанию стандартный движок табличных документов 1С 7.7 (так называемый Moxel) не поддерживает интерактивное группирование строк «из коробки». Тем не менее, решить эту задачу можно несколькими способами. В этой статье мы подробно разберем четыре наиболее эффективных метода: от эмуляции стандартными средствами до использования мощной внешней компоненты Йоксель (Yoksel), а также прямого управления COM-объектом Excel.

---

Способ 1. Эмуляция группировок без внешних компонент через «ОбработкаЯчейкиТаблицы»

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

Принцип реализации по шагам:

  1. Создание структуры данных: Всю выводимую информацию мы предварительно помещаем в служебную таблицу значений (ТЗ) на форме отчета. В этой ТЗ, помимо числовых данных и аналитики, мы заводим служебные колонки: Уровень (число), Развернут (булево/число: 1 — да, 0 — нет), Родитель (ссылка на строку-группировку) и ЭтоГруппа (1 — да, 0 — нет).
  2. Макет печатной формы: В макете отчета создаем крайнюю левую узкую колонку. В ячейках этой колонки для строк-группировок мы будем выводить текстовые символы-маркеры: [+] или [-].
  3. Настройка расшифровки: Для ячейки с маркером в поле «Расшифровка» прописываем специальный идентификатор. В качестве расшифровки удобнее всего использовать список значений, в который мы передаем текущий номер строки в нашей служебной ТЗ или уникальный код группы.
  4. Перехват события клика: В модуле формы отчета определяем предопределенную процедуру ОбработкаЯчейкиТаблицы(). При двойном клике пользователя по «плюсику» управление передается в эту процедуру. Мы считываем параметры из расшифровки, меняем флаг Развернут в служебной ТЗ на противоположный, полностью очищаем текущую печатную форму и формируем её заново на основе обновленных данных ТЗ.

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


Процедура ВывестиТаблицу()
    Таб.Очистить();
    Таб.ИсходнаяТаблица("МакетОтчета");
    
    // Выводим шапку
    Таб.ВывестиСекцию("Шапка");
    
    // Обходим подготовленную ТЗ с данными
    ТЗДанные.ВыбратьСтроки();
    Пока ТЗДанные.ПолучитьСтроку() = 1 Цикл
        // Если это детальная строка, и ее родитель свернут — пропускаем вывод
        Если ТЗДанные.ЭтоГруппа = 0 Тогда
            СтрокаРодителя = 0;
            // Ищем строку родителя в ТЗ
            Если ТЗДанные.НайтиЗначение(ТЗДанные.Родитель, СтрокаРодителя, "ИдентификаторГруппы") = 1 Тогда
                Если ТЗДанные.ПолучитьЗначение(СтрокаРодителя, "Развернут") = 0 Тогда
                    Продолжить; // Родитель свернут, деталь не выводим
                КонецЕсли;
            КонецЕсли;
        КонецЕсли;
        
        // Определяем, какой маркер выводить для групп
        Если ТЗДанные.ЭтоГруппа = 1 Тогда
            Если ТЗДанные.Развернут = 1 Тогда
                Маркер = "[-]";
            Иначе
                Маркер = "[+]";
            КонецЕсли;
            // Готовим расшифровку для клика
            Расшифровка = СоздатьОбъект("СписокЗначений");
            Расшифровка.Установить("Действие", "ПереключитьГруппу");
            Расшифровка.Установить("НомерСтрокиТЗ", ТЗДанные.НомерСтроки);
            
            Таб.ВывестиСекцию("СтрокаГруппы");
        Иначе
            Маркер = "  "; // Для детальных строк отступ без маркера
            Расшифровка = "";
            Таб.ВывестиСекцию("СтрокаДетали");
        КонецЕсли;
    КонецЦикла;
    
    Таб.Показать("Интерактивный отчет", "");
КонецПроцедуры

Теперь опишем процедуру перехвата клика в модуле формы отчета:


Процедура ОбработкаЯчейкиТаблицы(ЗначениеЯчейки, ФлагСтандартнойОбработки, Таблица)
    Если ТипЗначенияСтр(ЗначениеЯчейки) = "СписокЗначений" Тогда
        Действие = ЗначениеЯчейки.Получить("Действие");
        Если Действие = "ПереключитьГруппу" Тогда
            // Отменяем стандартное открытие карточки субконто или документа
            ФлагСтандартнойОбработки = 0;
            
            НомерСтрокиТЗ = ЗначениеЯчейки.Получить("НомерСтрокиТЗ");
            
            // Меняем состояние сворачивания группы
            ТекущееСостояние = ТЗДанные.ПолучитьЗначение(НомерСтрокиТЗ, "Развернут");
            ТЗДанные.УстановитьЗначение(НомерСтрокиТЗ, "Развернут", 1 - ТекущееСостояние);
            
            // Перерисовываем печатную форму
            ВывестиТаблицу();
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Преимущества метода: Работает абсолютно на любом компьютере с установленной 1С 7.7, не требует админских прав для регистрации DLL, не вызывает проблем при обновлении платформы.

Недостатки: При больших объемах данных (более 5-10 тысяч строк) полная перерисовка таблицы при каждом клике может вызывать заметные задержки («моргание» экрана). Также этот метод не позволяет перенести структуру группировок при сохранении файла в Excel — там останутся просто текстовые символы [+].

---

Способ 2. Использование внешней компоненты Yoksel (Йоксель)

Это наиболее элегантный, профессиональный и современный подход к реализации структуры в 1С 7.7. Внешняя компонента Yoksel (также известная как библиотека SpreadSheet.dll) представляет собой альтернативный движок для работы с табличными документами 1С, который полностью заменяет стандартный Moxel.

Ключевые преимущества использования Yoksel:

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


// Загружаем внешнюю компоненту динамически из папки базы данных
ПутьКВК = КаталогИБ() + "SpreadSheet.dll";
Если ФС.СуществуетФайл(ПутьКВК) = 1 Тогда
    ЗагрузитьВнешнююКомпоненту(ПутьКВК);
Иначе
    Предупреждение("Компонента Йоксель (SpreadSheet.dll) не найдена в каталоге базы!");
    Возврат;
КонецЕсли;

// Создаем объекты Йокселя
ТабДок = СоздатьОбъект("ТабличныйДокумент");
Конвертер = СоздатьОбъект("КонвертерТаблиц");

// Сначала формируем стандартную таблицу 1С
Таб1С = СоздатьОбъект("Таблица");
Таб1С.ИсходнаяТаблица("Макет");

// Предположим, мы выводим данные по контрагентам и их договорам
Таб1С.ВывестиСекцию("Шапка");

ТЗКонтрагенты.ВыбратьСтроки();
Пока ТЗКонтрагенты.ПолучитьСтроку() = 1 Цикл
    
    // Запоминаем строку начала группы в будущем документе Йокселя
    // Учитываем, что высота таблицы 1С увеличивается с каждой секцией
    СтрокаНачала = Таб1С.ВысотаТаблицы() + 1;
    
    Таб1С.ВывестиСекцию("СтрокаКонтрагента");
    
    // Выводим детальные строки договоров
    ТЗДоговоры.ВыбратьСтроки();
    Пока ТЗДоговоры.ПолучитьСтроку() = 1 Цикл
        Таб1С.ВывестиСекцию("СтрокаДоговора");
    КонецЦикла;
    
    СтрокаКонца = Таб1С.ВысотаТаблицы();
    
    // Важно: Группировать нужно детальные строки (подчиненные)
    // Если под контрагентом есть детальные строки, фиксируем их координаты
    Если СтрокаКонца > СтрокаНачала Тогда
        // Запоминаем координаты для последующей группировки в Йокселе
        // Добавляем границы группы в список значений для отложенной обработки
        СписокГруппировок.ДобавитьЗначение(СтрокаНачала + 1, СтрокаКонца);
    КонецЕсли;
    
КонецЦикла;

// Конвертируем стандартную таблицу 1С в объект ТабличныйДокумент Йокселя
Конвертер.Конвертировать(Таб1С, ТабДок);

// Теперь расставляем группировки в документе Йокселя
СписокГруппировок.ВыбратьЗначения();
Пока СписокГруппировок.ПолучитьЗначение(Индекс, СтрокаДеталиНачало) = 1 Цикл
    СтрокаДеталиКонец = Число(СписокГруппировок.ПолучитьОбъект(Индекс));
    
    // Добавляем группу строк (параметры: НачалоСтроки, КонецСтроки)
    ТабДок.ДобавитьГруппуСтрок(СтрокаДеталиНачало, СтрокаДеталиКонец);
КонецЦикла;

// Настраиваем показ структуры в окне просмотра
Фрейм = ТабДок.Показать("Отчет с группировками Йоксель");
Фрейм.ОтображатьСтруктуру(1);      // Показывает линии группировки слева
Фрейм.ОтображатьКнопкиУровней(1);  // Выводит кнопки уровней "1", "2" вверху панели

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

---

Способ 3. Прямой вывод данных в Microsoft Excel через COM-соединение

Если конечной целью вашего отчета является отправка готового файла клиенту или руководству, нет необходимости программировать сложный интерфейс в самой 1С 7.7. Мы можем выгрузить данные напрямую в приложение MS Excel, используя механизм ActiveX / COM, и применить встроенные функции группировки табличного процессора Excel.

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


// Создаем COM-объект Excel
Попытка
    Эксель = СоздатьОбъект("Excel.Application");
Исключение
    Предупреждение("Microsoft Excel не установлен на данном компьютере!");
    Возврат;
КонецПопытки;

// Добавляем новую книгу и выбираем активный лист
Книга = Эксель.Workbooks.Add();
Лист = Книга.ActiveSheet;

// Заполняем шапку
Лист.Cells(1, 1).Value = "Контрагент / Договор";
Лист.Cells(1, 2).Value = "Сумма взаиморасчетов";

СтрокаЭкселя = 2;

ТЗКонтрагенты.ВыбратьСтроки();
Пока ТЗКонтрагенты.ПолучитьСтроку() = 1 Цикл
    
    СтрокаГруппыНачало = СтрокаЭкселя;
    
    // Записываем данные контрагента (итоговая строка)
    Лист.Cells(СтрокаЭкселя, 1).Value = ТЗКонтрагенты.Наименование;
    Лист.Cells(СтрокаЭкселя, 2).Value = ТЗКонтрагенты.ИтогСумма;
    Лист.Cells(СтрокаЭкселя, 1).Font.Bold = 1; // Делаем шрифт жирным
    
    СтрокаЭкселя = СтрокаЭкселя + 1;
    СтрокаДеталейНачало = СтрокаЭкселя;
    
    // Выводим подчиненные договоры
    ТЗДоговоры.ВыбратьСтроки();
    Пока ТЗДоговоры.ПолучитьСтроку() = 1 Цикл
        Лист.Cells(СтрокаЭкселя, 1).Value = "   " + ТЗДоговоры.НомерДоговора;
        Лист.Cells(СтрокаЭкселя, 2).Value = ТЗДоговоры.Сумма;
        
        СтрокаЭкселя = СтрокаЭкселя + 1;
    КонецЦикла;
    
    СтрокаДеталейКонец = СтрокаЭкселя - 1;
    
    // Если у контрагента были детальные строки, группируем их
    Если СтрокаДеталейКонец >= СтрокаДеталейНачало Тогда
        ДиапазонГруппировки = Лист.Rows(СтрокаДеталейНачало & ":" & СтрокаДеталейКонец);
        ДиапазонГруппировки.Group(); // Группируем строки средствами Excel
    КонецЕсли;
    
КонецЦикла;

// Настраиваем отображение кнопок группировки сверху над подчиненными строками (по желанию)
Лист.Outline.SummaryRow = 0; // Показывает "плюсик" напротив строки контрагента (сверху)

// Сворачиваем все группы до 1-го уровня по умолчанию
Лист.Outline.ShowLevels(1);

// Делаем Excel видимым пользователю
Эксель.Visible = 1;

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

Недостатки: Требует обязательного наличия установленного пакета Microsoft Office на компьютере пользователя. Работает медленнее, чем вывод в стандартный табличный документ 1С или использование Йокселя.

---

Резюме: какой метод выбрать?

Проанализируем все рассмотренные варианты и выберем оптимальный под конкретные задачи:

← На главную