Новый лист в книге Excel из кода 1С: COM, Add, Move и Copy
Содержание
Чтобы добавить лист в Excel из 1С, подключитесь к Excel через Новый COMОбъект("Excel.Application"), откройте или создайте книгу и вызовите у коллекции листов метод Add. Получите объект нового листа, задайте ему имя через свойство Name, а в конце закройте книгу и выйдите из Excel. Всё остальное в теме (позиция листа, копирование шаблона, скорость) — детали вокруг этого вызова.
Частая ошибка новичка: он выгружает данные в первый лист книги и потом удивляется, что «лист по умолчанию» называется Лист1, а при втором запуске данные затирают старые. Один лист на отчёт — не всегда удобно. Ниже разберём, как создавать листы осознанно: с нужным именем, на нужном месте и без зависших процессов Excel.
Что нужно, чтобы 1С вообще могла управлять Excel
COM-подключение работает только там, где установлен Excel. Проверьте четыре вещи до написания кода:
- 🖥️ Где выполняется код. На клиенте — нужен Excel на компьютере пользователя. На сервере 1С — на сервере, а это отдельная головная боль (см. раздел про ошибки).
- 🧩 Разрядность. Если платформа 64-разрядная, Excel тоже должен быть 64-разрядным, и наоборот. Несовпадение даёт ошибку создания COM-объекта.
- 🔑 Права. Пользователь, под которым запущена 1С, должен иметь право запускать Excel.
- 📄 Что вам на самом деле нужно. Если достаточно просто выгрузить таблицу в файл, обойдитесь без COM: табличный документ 1С умеет сохраняться в формат
xlsxметодомЗаписать(). Excel при этом не нужен, и работает это на сервере. Но с готовым файлом такой способ не дружит: добавить лист в существующую книгу им не получится.
COM выбирайте, когда нужно дописать лист в уже существующую книгу, скопировать лист-шаблон с форматированием, формулами и диаграммами или управлять видом книги.
Подключение: запуск Excel и создание книги
Минимальный каркас, от которого отталкиваются все остальные примеры:
Попытка
Excel = Новый COMОбъект("Excel.Application");
Исключение
ВызватьИсключение "Не удалось запустить Excel: " + ОписаниеОшибки();
КонецПопытки;
Excel.Visible = Ложь; // не показывать окно
Excel.DisplayAlerts = Ложь; // не задавать вопросов пользователю
Книга = Excel.Workbooks.Add(); // новая пустая книга
// или открыть существующую:
// Книга = Excel.Workbooks.Open("C:\Отчёты\Реестр.xlsx");
Что здесь важно:
Visible = Ложьпрячет окно. Пока вы отлаживаете, поставьтеИстина— так видно, что происходит.DisplayAlerts = Ложьотключает диалоги («Файл уже существует, заменить?»). Без этого код может повиснуть на скрытом окне вопроса, и вы этого не увидите.- Новая книга создаётся с несколькими пустыми листами. Сколько их — зависит от настройки самого Excel (параметр «число листов в новой книге»), в коде на это рассчитывать нельзя. Если нужны только свои листы, лишние удалите, а не гадайте, сколько их.
Как добавить новый лист: метод Add
Коллекция листов — Книга.Worksheets. Метод Add принимает четыре необязательных параметра: Before (перед каким листом), After (после какого), Count (сколько листов) и Type (тип листа). Позицию задают одним из первых двух параметров, не обоими сразу.
Добавление в начало
Листы = Книга.Worksheets;
НовыйЛист = Листы.Add(Листы.Item(1)); // перед первым листом
НовыйЛист.Name = "Сводка";
Добавление в конец
В 1С пропущенный параметр COM-метода оставляют пустым — просто запятая:
Листы = Книга.Worksheets;
НовыйЛист = Листы.Add(, Листы.Item(Листы.Count)); // после последнего
НовыйЛист.Name = "Продажи";
Без параметров Листы.Add() вставит лист перед активным, а не в конец. Это самая частая причина «листы идут в обратном порядке»: активным остаётся тот, что добавили последним, и каждый следующий встаёт перед ним.
Таблица: какой вызов за что отвечает
| Что нужно | Вызов | Результат |
|---|---|---|
| Лист в начало | Add(Листы.Item(1)) | Новый лист первый |
| Лист в конец | Add(, Листы.Item(Листы.Count)) | Новый лист последний |
| Лист после нужного | Add(, Листы.Item("Итоги")) | Сразу за листом «Итоги» |
| Лист без указаний | Add() | Перед активным листом |
Обращаться к листу можно по номеру (Item(1)) или по имени (Item("Итоги")). Номер отсчитывается с единицы, а не с нуля, как привыкли в массивах 1С. Если листа с таким именем нет, получите ошибку COM.
Имя, позиция и порядок листов
Сразу после добавления лист называется Лист2, Лист3 и так далее. Дайте ему осмысленное имя:
НовыйЛист.Name = "Март";
У имени листа в Excel есть жёсткие ограничения:
- 📏 не длиннее 31 символа;
- 🚫 нельзя символы
\ / ? * [ ] :; - 🔁 имя уникально в пределах книги, регистр не различается («Март» и «МАРТ» — одно и то же);
- ⛔ имя не может быть пустым и не может начинаться или заканчиваться апострофом.
Поэтому имя, собранное из данных 1С (наименование организации, номер документа), нужно подчистить:
Функция ИмяЛиста(Знач Имя)
Для Каждого Символ Из СтрРазделить("\ / ? * [ ] :", " ") Цикл
Имя = СтрЗаменить(Имя, Символ, "_");
КонецЦикла;
Возврат Лев(СокрЛП(Имя), 31);
КонецФункции
Если листов с одинаковыми именами может быть несколько (например, по одному на контрагента), перед присвоением проверьте, свободно ли имя:
Функция ЛистСуществует(Книга, Имя)
Для Н = 1 По Книга.Worksheets.Count Цикл
Если ВРег(Книга.Worksheets.Item(Н).Name) = ВРег(Имя) Тогда
Возврат Истина;
КонецЕсли;
КонецЦикла;
Возврат Ложь;
КонецФункции
Если такой лист есть — добавьте к имени суффикс (Март (2)) в цикле, пока не найдёте свободное.
Переставить лист: метод Move
Уже созданный лист переносят методом Move, у которого тоже есть Before и After:
// В самое начало
НовыйЛист.Move(Книга.Worksheets.Item(1));
// В конец
НовыйЛист.Move(, Книга.Worksheets.Item(Книга.Worksheets.Count));
Если вызвать Move без параметров, Excel создаст новую книгу и перенесёт лист туда. Если вы этого не хотели — вы потеряете лист из исходной книги. Всегда передавайте хотя бы один параметр.
Удалить лишние листы
После Workbooks.Add() в книге остаются заготовки. Удалите ненужные, предварительно выключив вопрос о подтверждении:
Excel.DisplayAlerts = Ложь;
Книга.Worksheets.Item("Лист1").Delete();
Удалять можно только пока в книге остаётся хотя бы один видимый лист. Поэтому сначала добавляйте свои листы, потом удаляйте лишние.
Копирование листа-шаблона вместо создания с нуля
Если у вас есть оформленная форма — шапка, ширина колонок, формулы, печатные настройки, — проще один раз подготовить шаблон и копировать его, чем перерисовывать в коде. Метод Copy ведёт себя как Move: тоже принимает Before или After.
Шаблон = Книга.Worksheets.Item("Шаблон");
Шаблон.Copy(, Книга.Worksheets.Item(Книга.Worksheets.Count));
НовыйЛист = Книга.Worksheets.Item(Книга.Worksheets.Count);
НовыйЛист.Name = "Контрагент 1";
Что нужно знать:
- После
Copyкопия становится активным листом, но возвращаемого значения у метода нет. Поэтому либо берёте последний лист по номеру (как выше, если копировали в конец), либо обращаетесь кExcel.ActiveSheet. - Копия получает автоматическое имя вида
Шаблон (2). Переименуйте её сразу. - Копируются формулы, форматы, объединённые ячейки, диаграммы и именованные диапазоны, привязанные к листу. Именно ради этого шаблоны и делают.
- Шаблон может лежать в той же книге или в отдельном файле. Во втором случае откройте файл шаблона как книгу и копируйте лист с параметром
Afterиз другой книги — это работает так же.
Хранить шаблон удобно в макете 1С (двоичные данные), а перед использованием записывать во временный файл. Тогда шаблон всегда версионируется вместе с конфигурацией, и пользователи не ломают его вручную.
Заполнение листа: быстро и без зависаний
Основная потеря времени — не создание листов, а запись данных. Обращение к ячейке через COM занимает заметное время, а на тысячах строк эти миллисекунды складываются в минуты.
Медленно:
Для Н = 1 По Таблица.Количество() Цикл
НовыйЛист.Cells(Н, 1).Value = Таблица[Н - 1].Наименование;
НовыйЛист.Cells(Н, 2).Value = Таблица[Н - 1].Сумма;
КонецЦикла;
Быстро — собрать данные в массив и записать одним обращением:
Строк = Таблица.Количество();
Колонок = 2;
Массив = Новый COMSafeArray("VT_VARIANT", Колонок, Строк);
Для Н = 0 По Строк - 1 Цикл
Массив.SetValue(0, Н, Таблица[Н].Наименование);
Массив.SetValue(1, Н, Таблица[Н].Сумма);
КонецЦикла;
Диапазон = НовыйЛист.Range(НовыйЛист.Cells(1, 1), НовыйЛист.Cells(Строк, Колонок));
Диапазон.Value = Массив;
Размерности COMSafeArray задаются как «колонки, строки», а индексы в SetValue идут с нуля. Это легко перепутать, поэтому сначала проверьте на пяти строках.
Дополнительно ускоряют работу три настройки на время выгрузки:
| Настройка | Значение на время записи | Зачем |
|---|---|---|
Excel.ScreenUpdating | Ложь | Excel не перерисовывает экран |
Excel.Calculation | -4135 (ручной пересчёт) | Формулы не пересчитываются после каждой ячейки |
Excel.EnableEvents | Ложь | Не срабатывают макросы книги |
После записи верните прежние значения: ScreenUpdating = Истина, Calculation = -4105 (автоматический), EnableEvents = Истина. Если не вернуть, пользователь потом получит Excel, который не пересчитывает формулы.
Не оставляйте Excel в изменённом состоянии при ошибке. Возврат настроек положите в блок Исключение, иначе после сбоя они останутся выключенными до перезапуска.
Сохранение, закрытие и освобождение ресурсов
Самая неприятная проблема COM-выгрузок: код отработал, а в диспетчере задач остался невидимый EXCEL.EXE. Через сутки их накапливается десяток, и потом файлы «заняты неизвестным процессом».
Правильное завершение:
Попытка
Книга.SaveAs("C:\Отчёты\Реестр.xlsx");
Книга.Close(Ложь); // не спрашивать о сохранении
Excel.Quit();
Исключение
// сообщить об ошибке
КонецПопытки;
Книга = Неопределено;
Excel = Неопределено;
Порядок: сохранить, закрыть книгу, выйти из Excel, обнулить переменные. Если пропустить Quit() или не обнулить ссылки, процесс останется жить.
Чтобы он не оставался и при сбое в середине, оберните основной код в Попытка … Исключение, а закрытие вынесите так, чтобы оно выполнялось в обоих случаях. Если в базе есть пользователи, которые могут прервать выгрузку, предупредите их: принудительное завершение сеанса 1С оставит Excel висеть.
Если вам приходится вручную завершать зависшие процессы EXCEL.EXE на сервере или в терминале, убедитесь, что это не Excel другого пользователя с открытым несохранённым файлом. Завершайте только процессы своего сеанса.
Типичные ошибки при работе с листами
Ошибки здесь однотипны. Вот те, что встречаются чаще всего:
- ❌ «Класс не зарегистрирован» или не создаётся COM-объект. Excel не установлен на машине, где выполняется код, либо разрядность не совпадает. Если код идёт на сервере, а Excel стоит только у пользователя, перенесите выгрузку на клиента.
- ❌ Лист не добавляется, возникает исключение. Чаще всего книга защищена (структура заблокирована) или открыта только для чтения. Проверьте свойство защиты структуры книги и режим открытия.
- ❌ Ошибка при присвоении имени. Длина больше 31 символа, запрещённый символ или дубль имени. Применяйте функции очистки из раздела выше.
- ❌ Данные попали не в тот лист. Вы сохранили ссылку на лист до вызова
CopyилиMove, а работаете сActiveSheet. Всегда держите ссылку на конкретный лист в переменной и пишите через неё. - ❌ Появляется диалог, и код встаёт. Не выключен
DisplayAlerts, либо файл с таким именем уже открыт в другом сеансе Excel. - ❌ Русские буквы в формулах не работают. В
Formulaформулы пишутся на английском (SUM), вFormulaLocal— на языке интерфейса Excel (СУММ). Для переносимости используйтеFormula.
Для диагностики на сервере полезно писать в журнал регистрации ОписаниеОшибки() целиком: в тексте обычно видно, на каком именно обращении упал COM.
Частые вопросы
Можно ли добавить лист в Excel из 1С без установленного Excel?
xlsx силами 1С (табличный документ, Записать()), но добавить лист в готовую книгу так не получится.Как добавить сразу несколько листов?
Add количество не передаётся надёжно во всех версиях, поэтому добавляйте в цикле: один вызов Add на каждый лист, с именем из списка.Как узнать, сколько листов в книге?
Книга.Worksheets.Count. Скрытые листы тоже входят в это число.Как скрыть лист?
Visible значение 0 (скрыт) или -1 (виден). Значение 2 делает лист «очень скрытым», он не виден даже в окне показа скрытых листов.Работает ли это на сервере 1С?
xlsx средствами платформы.Как защитить лист паролем?
Лист.Protect("пароль"). Снимается методом Unprotect с тем же паролем.