-
1С Hard Skills
-
1.09.2019
Эту и другие технические статьи написали наши программисты 1С и получили за них премии. Если вы тоже работаете с 1С и любите делиться опытом, приходите разработчиком в Neti
Рассмотрим пример обработки COM-объекта на Клиенте на примере загрузки из файла xls.
В случаях, когда на сервере не установлен Excel или когда сервер 1С:Предприятие 64-х битный, а объем загружаемых данных небольшой, данные файла xls можно обработать на Клиенте и передать для дальнейшей обработки на Сервер. Рассмотрим на примере.
Внешняя обработка с табличной частью ТабЧасть, СотрудникСтр — строка для заполнения из xls файла на Клиенте, Сотрудник — СправочникСсылка.СотрудникиОрганизаций для заполнения из значения СотрудникСтр на Сервере. В файле xls в колонке 1 — наименования сотрудников, в колонке 2 — суммы, данные по сотрудникам начинаются с 7-й строки файла.
Форма обработки
Процедуры модуля формы обработки:
&НаКлиенте Процедура ОткрытьФайл(Команда) ДиалогВыбораФайла = Новый ДиалогВыбораФайла(РежимДиалогаВыбораФайла.Открытие); ДиалогВыбораФайла.Заголовок = "Прочитать табличный документ из файла"; ДиалогВыбораФайла.Фильтр = "Лист Excel (*.xlsx)|*.xlsx|Лист Excel (*.xls)|*.xls"; Если ДиалогВыбораФайла.Выбрать() Тогда ИмяФайла = ДиалогВыбораФайла.ПолноеИмяФайла; КонецЕсли; КонецПроцедуры &НаКлиенте Процедура ПрочитатьФайл(Команда) ПрочитатьДокумент(ИмяФайла); Обработать(); КонецПроцедуры &НаКлиенте Процедура ПрочитатьДокумент(ИмяФайла) Попытка Excel = ПолучитьCOMОбъект(ИмяФайла); ExcelЛист = Excel.Sheets(1); Исключение Сообщить(ОписаниеОшибки()); Возврат; КонецПопытки; Объект.ТабЧасть.Очистить(); сч = 7; Пока НЕ ПустаяСтрока(ExcelЛист.Cells(сч, 1).Value) Цикл //Заполнение табличной части обработки НоваяСтр = Объект.ТабЧасть.Добавить(); НоваяСтр.СотрудникСтр = СокрЛП(ExcelЛист.Cells(сч, 1).Value); НоваяСтр.Сумма = ExcelЛист.Cells(сч, 2).Value; сч = сч + 1; КонецЦикла; Excel.Application.Quit(); КонецПроцедуры &НаСервере Процедура Обработать() //заполнение значений как элементов справочников //получение значения Сотрудник из СотрудникСтр КонецПроцедуры
Эту статью хорошо дополняют
Для работы с Excel файлами в системе 1C существуют определенные технологии. Организовать взаимодействие системы 1C с внешней программой MS Excel можно через COM-объект «Excel.Application». Также есть возможность наладить взаимодействие с Excel из 1C используя технологию ADO.
Данный пример демонстрирует работу с использованием «Excel.Application». Для работоспособности данного примера на компьютере обязательно должно быть установлено программное обеспечение MS Excel.
Прочитать из существующего Excel Файла
Процедура ПрочитатьСуществующийExcelФайл(ПутьКФайлу)Попытка
Excel = Новый COMОбъект("Excel.Application");
Excel.DisplayAlerts = 0;
Excel.Visible = 0;
Исключение
Сообщить(ОписаниеОшибки() + " Программа Exсel не установлена");
Возврат;
КонецПопытки; Книга
= Excel.Workbooks.Open(ПутьКФайлу);
КоличествоЛистов = Книга.Sheets.Count;//Перебор листов
Для НомерЛиста = 1 По КоличествоЛистов Цикл Лист
= Книга.Sheets(НомерЛиста);
КоличествоСтрок = Лист.Cells(1, 1).SpecialCells(11).Row;
КоличествоКолонок = Лист.Cells(1, 1).SpecialCells(11).Column;//Перебор строк
Для НомерСтроки = 1 По КоличествоСтрок Цикл//Перебор колонок
Для НомерКолонки = 1 По КоличествоКолонок Цикл
ЗначениеЯчейки = Лист.Cells(НомерСтроки, НомерКолонки).Value;
//Выполнение действий с полученным значением
//...
//...
КонецЦикла;КонецЦикла;КонецЦикла; Excel
.Workbooks.Close();
Excel.Application.Quit();КонецПроцедуры
Записать в существующий Excel Файл
Процедура ЗаписатьСуществующийExcellФайл(ПутьКФайлу)Попытка
Excel = Новый COMОбъект("Excel.Application");
Excel.DisplayAlerts = 0;
Excel.Visible = 0;
Исключение
Сообщить(ОписаниеОшибки() + " Программа Exсel не установлена");
Возврат;
КонецПопытки; Книга
= Excel.Workbooks.Open(ПутьКФайлу); Лист
= Книга.Sheets(1);
//Установить значение в ячейку
Лист.Cells(1, 1).Value = "Тестовое значение";
Книга.Save(); Excel
.Workbooks.Close();
Excel.Application.Quit();КонецПроцедуры
Создать новый Excel Файл
Процедура СоздатьНовыйExcellФайл(ПутьКФайлу)Попытка
Excel = Новый COMОбъект("Excel.Application");
Excel.DisplayAlerts = 0;
Excel.Visible = 0;
Исключение
Сообщить(ОписаниеОшибки() + " Программа Exсel не установлена");
Возврат;
КонецПопытки; //Автоматически будут созданы три листа
Книга = Excel.WorkBooks.Add();
//Получить первый лист
Лист = Книга.Sheets(1);
//Установить значение в ячейку
Лист.Cells(1, 1).Value = "Тестовое значение";Попытка
Книга.SaveAs(ПутьКФайлу);
Исключение
Сообщить(ОписаниеОшибки() + " не удалось сохранить файл");
КонецПопытки; Excel
.Workbooks.Close();
Excel.Application.Quit();КонецПроцедуры
Вообще COM-объекты используют для соединения информационной базы 1С с файлом Word, Excel, Outlook или любой другой программой, поддерживающей данный интерфейс обмена данными. В этой статье рассмотрим задачу выгрузки/загрузки данных из/в MS Excel. Чтобы это осуществить воспользуемся COM-соединением и объектом Excel.Application. Для примера возьмём задачу выгрузки/загрузки данных о номенклатуре. Пример рассмотрим ниже.
COM-соединение
Что же такое COM-соединение? Component Object Model (или COM) – это технология (фирмы Microsoft) взаимодействующих компонентов, которые одновременно могут быть использованы в разных приложениях. При этом весь функционал соответствующего компонента наследуется внутрь разрабатываемого приложения. В нашем случае COM-объект Excel.Application используется внутри кода 1С для операций с файлом книги MS Excel.
Объект Excel.Application
У объекта Excel.Application существует ряд методов, которые нам могут пригодиться для реализации нижепоставленной задачи:
- ОбъектExcel.WorkBooks.Open(ИмяФайла) – Открытие книги MS Excel
- ОбъектExcel.ActiveWorkbook.Close() – Закрытие текущей книги
- ОбъектExcel.Quit() – Закрытие COM-объекта
- ОбъектExcel.Sheets(ИмяЛиста) – Получает лист книги
- ЛистExcel.Cells(НачалоСтрока, НачалоСтолбец) – Ячейка таблицы на данном листе
- ЛистExcel.Range(Ячейка1, Ячейка2) – Выделенная область
- ЯчейкаExcel.Value – Значение ячейки таблицы
- ЯчейкаExcel.Text – Текст ячейки таблицы
Постановка задачи
Итак, предположим, что в обработке 1С у нас имеется табличная часть, состоящая из следующих колонок:
- Номенклатура
- Количество
- Цена
- Сумма.
Необходимо реализовать 2 функционала (сделать на форме 2 основные кнопки):
- Выгрузка табличной части в подготовленный файл MS Excel
- Загрузка табличной части из файла.
Алгоритм выгрузки/загрузки в MS Excel
Алгоритм выгрузки следующий:
- Выгружаем табличную часть в таблицу значений
- Создаём новый COM-объект Excel.Application
- Выбираем файл, открываем файл книги MS Excel
- Переходим на заданный лист книги
- Выгружаем данные в файл
- Закрываем книгу, выходим из COM-объекта.
Алгоритм загрузки следующий:
- Создаём новый COM-объект Excel.Application
- Выбираем файл, открываем файл книги MS Excel
- Переходим на заданный лист книги
- Загружаем данные из файла в таблицу значений
- Закрываем книгу, выходим из COM-объекта
- Таблицу значений выгружаем в табличную часть.
Операция выгрузки и загрузки данных о номенклатуре происходит в заранее подготовленный шаблон MS Excel.
Пример кода 1С
Код 1С я постарался разделить на отдельные функции, чтобы, скопировав, с ними можно было работать где угодно. На форме обработки 1С были созданы 3 кнопки:
- Выгрузить
- Загрузить
- Очистить.
В итоге в реализации алгоритма получились следующие основные процедуры и функции 1С:
- ПолучитьExcel – Получает COM-объект MS Excel;
- ЗакрытьExcel – Закрывает использование COM-объекта MS Excel;
- ПолучитьЛистExcel – Получает лист книги Excel;
- ДобавитьТабличныйДокументВExcel – Добавляет табличный документ на лист Excel (нужно для выгрузки данных);
- ПрочитатьОбластьИзExcel – Читает область ячеек с листа Excel (нужно для загрузки данных);
- ШиринаЛистаExcel – Ширина листа Excel;
- ВысотаЛистаExcel – Высота листа Excel;
- ПреобразоватьТДвТЗ – Преобразует табличный документ в таблицу значений;
- ПреобразоватьТЗвТД – Преобразует таблицу значений в табличный документ;
Для начала приведу вспомогательную функцию для открытия/сохранения файла на диске:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
#Если Клиент Тогда // Функция выбора файла. // // Параметры: // РежимВыбора - <РежимДиалогаВыбораФайла> - Выбор каталога, открытие или сохранение файла; // Расширение - <Строка>, <Массив> - Список расширений файла. // // Возвращаемое значение: // <Строка> - Путь к выбранному файлу. // Функция ВыбратьФайлДокумента(РежимВыбора, Расширение = "*") Экспорт ИмяФайла = ""; //ФорматМассив = РазобратьСтрокуВМассивПоРазделителю(Расширение); ФорматМассив = ПреобразоватьВМассив(Расширение); ДиалогФайла = Новый ДиалогВыбораФайла(РежимВыбора); Если РежимВыбора = РежимДиалогаВыбораФайла.Открытие Тогда ДиалогФайла.Заголовок = "Открыть документ"; ИначеЕсли РежимВыбора = РежимДиалогаВыбораФайла.Сохранение Тогда ДиалогФайла.Заголовок = "Сохранить документ"; ИначеЕсли РежимВыбора = РежимДиалогаВыбораФайла.ВыборКаталога Тогда ДиалогФайла.Заголовок = "Выбрать каталог"; КонецЕсли; Фильтр = ""; Для Каждого ЭлементМассив Из ФорматМассив Цикл Если ЭлементМассив = "*" Тогда Фильтр = Фильтр + "|" + НСтр("ru = ""Все файлы""; en = ""All files"""); ИначеЕсли ВРег(ЭлементМассив) = ВРег("TXT") Тогда Фильтр = Фильтр + "|" + НСтр("ru = ""Текстовый документ""; en = ""Text document"""); ИначеЕсли ВРег(ЭлементМассив) = ВРег("MXL") Тогда Фильтр = Фильтр + "|" + НСтр("ru = ""Табличный документ""; en = ""Table document"""); ИначеЕсли ВРег(ЭлементМассив) = ВРег("XLS") ИЛИ ВРег(ЭлементМассив) = ВРег("XLSX") ИЛИ ВРег(ЭлементМассив) = ВРег("XLSM") Тогда Фильтр = Фильтр + "|" + НСтр("ru = ""Табличный документ MS Excel""; en = ""Table document MS Excel"""); ИначеЕсли ВРег(ЭлементМассив) = ВРег("XML") Тогда Фильтр = Фильтр + "|" + НСтр("ru = ""Документ XML""; en = ""Document XML"""); ИначеЕсли ВРег(ЭлементМассив) = ВРег("HTML") ИЛИ ВРег(ЭлементМассив) = ВРег("HTM") Тогда Фильтр = Фильтр + "|" + НСтр("ru = ""HTML документ""; en = ""HTML document"""); Иначе Фильтр = Фильтр + "|" + НСтр("ru = ""Файл " + ВРег(ЭлементМассив) + """; en = ""File " + ВРег(ЭлементМассив) + """"); КонецЕсли; Фильтр = Фильтр + " (*." + НРег(ЭлементМассив) + ")|*." + НРег(ЭлементМассив); КонецЦикла; Фильтр = Сред(Фильтр, 2); ДиалогФайла.Фильтр = Фильтр; ДиалогФайла.МножественныйВыбор = Ложь; Если ДиалогФайла.Выбрать() Тогда ИмяФайла = ?(РежимВыбора = РежимДиалогаВыбораФайла.ВыборКаталога, ДиалогФайла.Каталог, ДиалогФайла.ПолноеИмяФайла); Иначе Текст = "ru = ""Файл не выбран!""; en = ""File(s) not selected!"""; Предупреждение(НСтр(Текст)); КонецЕсли; Возврат ИмяФайла; КонецФункции #КонецЕсли |
Также в реализации алгоритма были задействованы следующие вспомогательные функции:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// Преобразует в массив переменную любого типа данных. // // Параметры: // Объект - Произвольный - произвольный объект данных; // Проверка - <Булево> - Осуществление проверки на заполненное значение. // // Возвращаемое значение: // <Массив> - Массив с теми же данными. // Функция ПреобразоватьВМассив(Объект, Проверка = Ложь) Экспорт ОбъектМассив = Новый Массив; Если НЕ Проверка ИЛИ ЗначениеЗаполнено(Объект) Тогда Если ТипЗнч(Объект) = Тип("Массив") Тогда ОбъектМассив = Объект; ИначеЕсли ТипЗнч(Объект) = Тип("СписокЗначений") Тогда ОбъектМассив = Объект.ВыгрузитьЗначения(); ИначеЕсли ТипЗнч(Объект) = Тип("Строка") Тогда ОбъектМассив = РазобратьСтрокуВМассивПоРазделителю(Объект); ИначеЕсли ТипЗнч(Объект) = Тип("Структура") Тогда Для Каждого Элемент Из Объект Цикл ОбъектМассив.Добавить(Элемент.Значение); КонецЦикла; Иначе ОбъектМассив.Добавить(Объект); КонецЕсли; КонецЕсли; Возврат ОбъектМассив; КонецФункции; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// Разбирает строку в массив подстрок по разделителю. // При этом пробелы между подстроками не учитываются. // // Параметры: // Стр - исходная строка; // СтрРазделитель - разделитель, по умолчанию ","; // ИгнорироватьПустые - игнорировать ли пустые места между разделителями. // // Возвращаемое значение: // Массив строк // Функция РазобратьСтрокуВМассивПоРазделителю(Знач Стр, СтрРазделитель = ",", ИгнорироватьПустые = Ложь) Экспорт Результат = Новый Массив; ВхождениеРазделителя = Найти(Стр, СтрРазделитель); Пока ВхождениеРазделителя <> 0 Цикл ЧастьДоРазделителя = СокрЛП(Лев(Стр, ВхождениеРазделителя - 1)); Если НЕ (ИгнорироватьПустые И ПустаяСтрока(ЧастьДоРазделителя)) Тогда Результат.Добавить(ЧастьДоРазделителя); КонецЕсли; Стр = СокрЛП(Сред(Стр, ВхождениеРазделителя + 1)); ВхождениеРазделителя = Найти(Стр, СтрРазделитель); КонецЦикла; Если НЕ (ИгнорироватьПустые И ПустаяСтрока(Стр)) Тогда Результат.Добавить(СокрЛП(Стр)); КонецЕсли; Возврат Результат; КонецФункции; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
// Создаёт новую таблицу значений с заданными колонками. // // Параметры: // пКолонки - <Строка>, <Структура>, <Массив>, <СписокЗначений>, <ТаблицаЗначений> - // Набор колонок для таблицы значений. // // Возвращаемое значение: // <ТаблицаЗначений> - Созданная таблица. // Функция ПолучитьТаблицуВывода(пКолонки) Экспорт ТЗ = Новый ТаблицаЗначений; Если пКолонки <> Неопределено Тогда Если ТипЗнч(пКолонки) = Тип("Строка") Тогда пКолонки = РазобратьСтрокуВМассивПоРазделителю(пКолонки); КонецЕсли; Если ТипЗнч(пКолонки) = Тип("Структура") Тогда Для Каждого Поле Из пКолонки Цикл СтрокаТабл = ТЗ.Колонки.Добавить(Поле.Ключ, Поле.Значение); КонецЦикла; ИначеЕсли ТипЗнч(пКолонки) = Тип("СписокЗначений") Тогда Для Каждого Поле Из пКолонки Цикл Если Поле.Пометка Тогда СтрокаТабл = ТЗ.Колонки.Добавить(Поле.Значение, пКолонки.ТипЗначения, Поле.Представление); КонецЕсли; КонецЦикла; ИначеЕсли ТипЗнч(пКолонки) = Тип("ТаблицаЗначений") Тогда ЕстьНаименование = (пКолонки.Колонки.Найти("Наименование") <> Неопределено); ЕстьТипЗначения = (пКолонки.Колонки.Найти("ТипЗначения") <> Неопределено); ЕстьЗаголовок = (пКолонки.Колонки.Найти("Заголовок") <> Неопределено); ЕстьШирина = (пКолонки.Колонки.Найти("Ширина") <> Неопределено); Для Каждого Поле Из пКолонки Цикл СтрокаТабл = ТЗ.Колонки.Добавить(?(ЕстьНаименование, Поле.Наименование, ""), ?(ЕстьТипЗначения, Поле.ТипЗначения, Новый ОписаниеТипов), ?(ЕстьЗаголовок, Поле.Заголовок, ""), ?(ЕстьШирина, Поле.Ширина, 0)); КонецЦикла; Иначе Для Каждого Поле Из пКолонки Цикл СтрокаТабл = ТЗ.Колонки.Добавить(Поле); КонецЦикла; КонецЕсли; КонецЕсли; Возврат ТЗ; КонецФункции; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// Создаёт структуру колонок из таблицы значений. // // Параметры: // ТабЗначений - <ТаблицаЗначений> - Любая таблица. // // Возвращаемое значение: // <Структура> - Созданная таблица. // Функция ПолучитьСтруктуруКолонокИзТаблицы(ТабЗначений) Экспорт СтруктураКолонок = Новый Структура; Для Каждого ЭлементКолонка Из ТабЗначений.Колонки Цикл СтруктураКолонок.Вставить(ЭлементКолонка.Имя, ЭлементКолонка.ТипЗначения); КонецЦикла; Возврат СтруктураКолонок; КонецФункции; |
Основные функции обработки алгоритма следующие:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
// Получает объект файла MS Excel. // // Параметры: // ИмяФайла - <Строка> - Путь к файлу XLS. // // Возвращаемое значение: // <COMОбъект> - Полученный объект. Если объект не найден, то возвращается "Неопределено". // Функция ПолучитьExcel(ИмяФайла) Экспорт ФайлНаДиске = Новый Файл(ИмяФайла); Excel = Неопределено; Если нРег(ФайлНаДиске.Расширение) = ".xls" ИЛИ нРег(ФайлНаДиске.Расширение) = ".xlsx" ИЛИ нРег(ФайлНаДиске.Расширение) = ".xlsm" Тогда Если НЕ ФайлНаДиске.Существует() Тогда Сообщить("Файл не существует!", СтатусСообщения.Внимание); Возврат Неопределено; КонецЕсли; Попытка Excel = Новый COMОбъект("Excel.Application"); Excel.WorkBooks.Open(ИмяФайла); Исключение Сообщить("Не удалось инициализировать Excel!", СтатусСообщения.Внимание); Возврат Неопределено; КонецПопытки; КонецЕсли; Возврат Excel; КонецФункции; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
// Закрывает файл MS Excel. // // Параметры: // Excel - <COMОбъект> - Объект файла MS Excel; // Сохранить - <Булево> - Указывает сохранять файл при закрытии или нет. По умолчанию // пользователю предлагается выбрать это самому. // Процедура ЗакрытьExcel(Excel, Сохранить = Неопределено) Экспорт Попытка #Если Клиент Тогда Состояние("Закрытие файла Microsoft Excel..."); #КонецЕсли Если Сохранить = Неопределено Тогда Excel.ActiveWorkbook.Close(); Иначе Excel.ActiveWorkbook.Close(Сохранить); КонецЕсли; Excel.Quit(); Исключение Сообщить("Ошибка закрытия Excel!", СтатусСообщения.Внимание); КонецПопытки; Excel = Неопределено; КонецПроцедуры; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// Получает лист из файла книги MS Excel. // // Параметры: // Excel - <COMОбъект> - Объект файла MS Excel; // ИмяЛиста - <Строка> - Имя листа книги MS Excel. // // Возвращаемое значение: // <COMОбъект> - Полученный лист. Если объект не найден, то возвращается "Неопределено". // Функция ПолучитьЛистExcel(Excel, ИмяЛиста) Экспорт Попытка ExcelЛист = Excel.Sheets(ИмяЛиста); Исключение Сообщить("Не удалось прочитать лист Excel!", СтатусСообщения.Внимание); Возврат Неопределено; КонецПопытки; Возврат ExcelЛист; КонецФункции; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
// Записывает данные из табличного документа в файл MS Excel. // // Параметры: // ЛистExcel - <COMОбъект> - Лист из файла MS Excel; // Таблица - <ТабличныйДокумент> - Документ, по порядку следования колонок и строк // соответствующий листу файла MS Excel; // Шапка - <Число> - Количество первых строк для шапки в файле MS Excel; // СписокСтолбцов - <Строка>, <Массив> - Список номеров столбцов, которые будут выгружены // в файл MS Excel; // СписокСтрокЗапрета - <Строка>, <Массив> - Список номеров строк, которые не должны // выгружаться в файл MS Excel. Если этот параметр не задан, то выгружаются все строки; // ПроверятьЗначения - <Булево> - Определяет будут ли проверяться ячейки табличного // документа на содержание в них значения, а не текстовое представление этого значения. // По умолчанию этот параметр "Ложь". // Процедура ДобавитьТабличныйДокументВExcel(ЛистExcel, Таблица, Шапка, СписокСтолбцов, СписокСтрокЗапрета = Неопределено, ПроверятьЗначения = Ложь) Экспорт Если ТипЗнч(СписокСтолбцов) = Тип("Строка") Тогда СписокСтолбцов = РазобратьСтрокуВМассивПоРазделителю(СписокСтолбцов); КонецЕсли; Если ТипЗнч(СписокСтрокЗапрета) = Тип("Строка") Тогда СписокСтрокЗапрета = РазобратьСтрокуВМассивПоРазделителю(СписокСтрокЗапрета); КонецЕсли; ЕстьМассив = (СписокСтрокЗапрета = Неопределено); Если ЕстьМассив Тогда Попытка МассивCOM = Новый COMSafeArray("VT_VARIANT", 1, Таблица.ВысотаТаблицы - Шапка); Исключение ЕстьМассив = Ложь; КонецПопытки; КонецЕсли; Для Каждого НомерСтолбца Из СписокСтолбцов Цикл Для НомерСтроки = Шапка+1 По Таблица.ВысотаТаблицы Цикл Если СписокСтрокЗапрета = Неопределено ИЛИ (СписокСтрокЗапрета.Найти(Строка(НомерСтроки)) = Неопределено И СписокСтрокЗапрета.Найти(Число(НомерСтроки)) = Неопределено) Тогда Область = Таблица.Область(НомерСтроки, Число(НомерСтолбца)); Значение = ?(ПроверятьЗначения И Область.СодержитЗначение, Область.Значение, Область.Текст); Если ЕстьМассив Тогда МассивCOM.SetValue(0, НомерСтроки-Шапка-1, Значение); Иначе ЛистExcel.Cells(НомерСтроки, Число(НомерСтолбца)).Value = Значение; КонецЕсли; КонецЕсли; КонецЦикла; Если ЕстьМассив Тогда ЛистExcel.Range(ЛистExcel.Cells(Шапка+1, Число(НомерСтолбца)), ЛистExcel.Cells(Таблица.ВысотаТаблицы, Число(НомерСтолбца))).Value = МассивCOM; КонецЕсли; КонецЦикла; КонецПроцедуры; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
// Читает область ячеек из MS Excel в табличный документ. // // Параметры: // ЛистExcel - <COMОбъект> - Лист из файла MS Excel; // ТабДок - <ТабличныйДокумент> - Исходный табличный документ, поле табличного // документа или таблица значений. Если этот параметр не задан, то создаётся // новый табличный документ; // НачалоСтрока - <Число> - Начальная строка в файле MS Excel; // НачалоСтолбец - <Число> - Начальный столбец в файле MS Excel; // КонецСтрока - <Число> - Конечная строка в файле MS Excel; // КонецСтолбец - <Число> - Конечный столбец в файле MS Excel. // // Возвращаемое значение: // <ТабличныйДокумент> - Возвращает прочитанный из области в MS Excel табличный // документ, который передавался в эту функцию параметром "ТабДок". // Функция ПрочитатьОбластьИзExcel(ЛистExcel, ТабДок = Неопределено, НачалоСтрока, НачалоСтолбец, КонецСтрока, КонецСтолбец) Экспорт Если ТабДок = Неопределено Тогда ТабДок = Новый ТабличныйДокумент; КонецЕсли; Попытка МассивCOM = Новый COMSafeArray("VT_VARIANT", КонецСтолбец - НачалоСтолбец + 1, КонецСтрока - НачалоСтрока + 1); ЕстьМассив = Истина; Исключение ЕстьМассив = Ложь; КонецПопытки; Если ЕстьМассив Тогда МассивCOM = ЛистExcel.Range(ЛистExcel.Cells(НачалоСтрока, НачалоСтолбец), ЛистExcel.Cells(КонецСтрока, КонецСтолбец)).Value; Для ИндексКолонка = НачалоСтолбец По КонецСтолбец Цикл Для ИндексСтрока = НачалоСтрока По КонецСтрока Цикл Значение = МассивCOM.GetValue(ИндексКолонка - НачалоСтолбец + 1, ИндексСтрока - НачалоСтрока + 1); ТабДок.Область(ИндексСтрока, ИндексКолонка).СодержитЗначение = Истина; ТабДок.Область(ИндексСтрока, ИндексКолонка).Значение = Значение; КонецЦикла; КонецЦикла; Иначе Для ИндексКолонка = НачалоСтолбец По КонецСтолбец Цикл Для ИндексСтрока = НачалоСтрока По КонецСтрока Цикл Значение = ЛистExcel.Cells(ИндексСтрока, ИндексКолонка).Value; ТабДок.Область(ИндексСтрока, ИндексКолонка).СодержитЗначение = Истина; ТабДок.Область(ИндексСтрока, ИндексКолонка).Значение = Значение; КонецЦикла; КонецЦикла; КонецЕсли; Возврат ТабДок; КонецФункции; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Определяет ширину листа MS Excel. // // Параметры: // ЛистExcel - <COMОбъект> - Лист из файла MS Excel. // // Возвращаемое значение: // <Число> - Количество столбцов в таблице. // Функция ШиринаЛистаExcel(ЛистExcel) Экспорт ЕстьЗащита = ЛистExcel.ProtectContents; Возврат ?(ЕстьЗащита, ЛистExcel.UsedRange.Columns.Count, ЛистExcel.Cells.SpecialCells(11).Column); КонецФункции; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// Определяет высоту листа MS Excel. // // Параметры: // ЛистExcel - <COMОбъект> - Лист из файла MS Excel. // // Возвращаемое значение: // <Число> - Количество строк в таблице. // Функция ВысотаЛистаExcel(ЛистExcel) Экспорт ЕстьЗащита = ЛистExcel.ProtectContents; Возврат ?(ЕстьЗащита, ЛистExcel.UsedRange.Rows.Count, ЛистExcel.Cells.SpecialCells(11).Row); КонецФункции; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
// Преобразовать табличный документ в таблицу значений. // // Параметры: // ТабДок - <ТабличныйДокумент> - Исходный табличный документ; // СтруктураКолонок - <Структура>, <ТаблицаЗначений> - Структура колонок; // НачалоСтрока - <Число> - Строка начала области; // НачалоСтолбец - <Число> - Столбец начала области; // КонецСтрока - <Число> - Строка конца области; // КонецСтолбец - <Число> - Столбец конца области. // // Возвращаемое значение: // <ТаблицаЗначений> - Полученная таблица значений. // Функция ПреобразоватьТДвТЗ(ТабДок, СтруктураКолонок, Знач НачалоСтрока = Неопределено, Знач НачалоСтолбец = Неопределено, Знач КонецСтрока = Неопределено, Знач КонецСтолбец = Неопределено) Экспорт // Определение габаритов таблицы Если НачалоСтрока = Неопределено И НачалоСтолбец = Неопределено Тогда НачалоСтрока = 1; НачалоСтолбец = 1; КонецЕсли; Если НачалоСтрока = Неопределено Тогда НачалоСтрока = 1; Пока НЕ ТабДок.Область(НачалоСтрока, НачалоСтолбец).СодержитЗначение И НачалоСтрока < ТабДок.ВысотаТаблицы Цикл НачалоСтрока = НачалоСтрока + 1; КонецЦикла; ИначеЕсли НачалоСтолбец = Неопределено Тогда НачалоСтолбец = 1; Пока НЕ ТабДок.Область(НачалоСтрока, НачалоСтолбец).СодержитЗначение И НачалоСтолбец < ТабДок.ШиринаТаблицы Цикл НачалоСтолбец = НачалоСтолбец + 1; КонецЦикла; КонецЕсли; КонецСтрока = ?(КонецСтрока = Неопределено, ТабДок.ВысотаТаблицы, КонецСтрока); КонецСтолбец = ?(КонецСтолбец = Неопределено, ТабДок.ШиринаТаблицы, КонецСтолбец); // Преобразование ЭтоТаблица = (ТипЗнч(СтруктураКолонок) = Тип("ТаблицаЗначений")); ТабЗначений = ПолучитьТаблицуВывода(СтруктураКолонок); Для ИндексСтроки = НачалоСтрока По КонецСтрока Цикл СтрокаТЗ = ТабЗначений.Добавить(); ИндексКолонки = НачалоСтолбец; Для Каждого Колонка Из СтруктураКолонок Цикл НаименованиеКолонки = ?(ЭтоТаблица, Колонка.Наименование, Колонка.Ключ); пИндексКолонки = ?(ЭтоТаблица, Колонка.СтолбецОтчёт, ИндексКолонки); Если ТабДок.Область(ИндексСтроки, пИндексКолонки).СодержитЗначение Тогда СтрокаТЗ[НаименованиеКолонки] = ТабДок.Область(ИндексСтроки, пИндексКолонки).Значение; Иначе СтрокаТЗ[НаименованиеКолонки] = ТабДок.Область(ИндексСтроки, пИндексКолонки).Текст; КонецЕсли; ИндексКолонки = ИндексКолонки + 1; КонецЦикла; КонецЦикла; Возврат ТабЗначений; КонецФункции; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
// Преобразовать таблицу значений в табличный документ. // // Параметры: // ТабЗначений - <ТаблицаЗначений> - Исходная таблица значений; // ТабДок - <ТабличныйДокумент> - Полученный табличный документ. Если параметр не задан, // то документ создаётся заново и возвращается функцией; // НачалоСтрока - <Число> - Строка начала области; // НачалоСтолбец - <Число> - Столбец начала области; // ВыводитьЗаголовки - <Булево> - Определяет выводить ли имена колонок или нет. // // Возвращаемое значение: // <ТабличныйДокумент> - Полученный табличный документ (возвращает параметр "ТабДок"). // Функция ПреобразоватьТЗвТД(ТабЗначений, ТабДок = Неопределено, Знач НачалоСтрока = Неопределено, Знач НачалоСтолбец = Неопределено, ВыводитьЗаголовки = Ложь) Экспорт Если ТабДок = Неопределено Тогда ТабДок = Новый ТабличныйДокумент; КонецЕсли; // Определение габаритов таблицы НачалоСтрока = ?(НачалоСтрока = Неопределено, 1, НачалоСтрока); НачалоСтолбец = ?(НачалоСтолбец = Неопределено, 1, НачалоСтолбец); // Преобразование ИндексСтроки = НачалоСтрока; Если ВыводитьЗаголовки Тогда ИндексКолонки = НачалоСтолбец; Для Каждого Колонка Из ТабЗначений.Колонки Цикл ТабДок.Область(ИндексСтроки, ИндексКолонки).Текст = ?(ПустаяСтрока(Колонка.Заголовок), Колонка.Имя, Колонка.Заголовок); ИндексКолонки = ИндексКолонки + 1; КонецЦикла; ИндексСтроки = ИндексСтроки + 1; КонецЕсли; Для Каждого Элемент Из ТабЗначений Цикл ИндексКолонки = НачалоСтолбец; Для Каждого Колонка Из ТабЗначений.Колонки Цикл ТабДок.Область(ИндексСтроки, ИндексКолонки).СодержитЗначение = Истина; ТабДок.Область(ИндексСтроки, ИндексКолонки).ТипЗначения = Новый ОписаниеТипов(Колонка.ТипЗначения); ТабДок.Область(ИндексСтроки, ИндексКолонки).Значение = Элемент[Колонка.Имя]; ИндексКолонки = ИндексКолонки + 1; КонецЦикла; ИндексСтроки = ИндексСтроки + 1; КонецЦикла; Возврат ТабДок; КонецФункции; |
В реализации алгоритма был дополнительно использован объект COMSafeArray с типом VT_VARIANT. Этот COM-объект выступает в качестве двумерного массива, в котором удобно хранить значения ячеек. Также использование данного объекта повышает быстродействие операций чтения/записи для ячеек таблицы.
Целиком получившуюся обработку 1С, а также шаблон для загрузки/выгрузки можно скачать по ссылке ниже.
Указанные здесь процедуры и функции я постарался сделать универсальными. Они могут быть применены для широкого круга прикладных задач.
Часть 3. Использование COM-серверов Microsoft Office
Основные объекты серверов Excel и Word
Объекты Excel
Объекты Word
Позднее связывание
Раннее связывание
Практика
показывает, что приложения Microsoft
Office (Excel,
Word, Power
Point и т.п.)
являются одними из наиболее часто
используемых Windows-приложений.
Каждое из них является СОМ-сервером, а
следовательно, любой входящий в него объект
может быть использован вашей программой
как собственный.
Существуют два способа обращения к методам и свойствам СОМ-объекта: путем ссылки
на его библиотеку типов (раннее связывание) и по имени (позднее связывание).
Для Object Pascal предпочтительным является раннее связывание, так как в этом
случае компилятор может проконтролировать правильность обращения к свойствам
и методам внешних объектов, а создаваемый им код исполняется, как правило, быстрее.
В то же время базовый язык обращения к серверам Microsoft Office — Visual Basic
for Application (VBA) не поддерживает работу с указателями и, следовательно,
не может использовать интерфейсы. Специально для такого рода языков (помимо
VBA c указателями не работают также языки JavaScript, SmallTalk и некоторые
другие) в технологию СОМ введены диспинтерфейсы, позволяющие обращаться к методам
и свойствам по имени, а не по адресу. При инсталлировании Office можно установить
справку по VBA, в которой детально описываются интерфейсы серверов Microsoft
Office с указанием назначения методов и свойств, а также параметров обращения
к ним. Фактически это единственные доступные программисту документы, на которые
ему следует опираться при программировании доступа к мощным возможностям серверов
Microsoft Office. Замечу, что при стандартном инсталлировании Microsoft Office
справки по VBA не устанавливаются. Если в каталоге Program Files | Microsoft
Office | Office вы не найдете файлов vbaxl8.hlp1
(справка по Excel), vbawrd8.hlp (справка по Word) и т. п., вы должны их
добавить с помощью аплета Пуск | Настройка | Панель управления | Установка и
удаление программ.
В версию 5 Delphi включены компоненты страницы Servers,
позволяющие обращаться к СОМ-объектам этих
серверов с помощью библиотек типов, однако
эти компоненты практически не
документированы. Более того, сами
библиотеки уже внедрены в пакет dclaxserver50,
так что с помощью этой версии Delphi
мне так и не удалось получить их тексты. Во
всех случаях изучение обширных текстов
библиотек (например, файл Excel_TLB.pas
содержит более 20 тыс. строк) мало что дает
даже опытному программисту.
В этом разделе приводятся краткое
описание основных объектов двух наиболее
популярных серверов — Excel
и Word, а
также примеры использования Excel
в стиле VBA
(по имени) и с помощью компонентов страницы Servers.
Поскольку специально для версии MS
Office 97
язык VBA
был существенно расширен, этот материал
нельзя использовать для работы с более
ранними версиями пакета.
Основные объекты серверов Excel и Word
В терминологии VBA
используются
понятия «объект» и «коллекция». Объект —
это обычный интерфейсный объект СОМ,
имеющий свойства, методы и события.
Коллекция — это группа однотипных объектов.
Например, главный объект сервера Excel
— Application
определяет основные свойства и методы
сервера, а коллекция Worksheets
представляет собой
набор табличных страниц в текущей рабочей
книге и т.д. Представленные ниже иерархии
объектов и коллекций взяты из файлов vbaXXX.hlp. В отличие от объектов VCL
они построены не по принципу наследования,
а по функциональной подчиненности.
Объекты Excel
Сервер Excel — это мощный табличный процессор,
реализующий размещение и обработку
различного рода данных (как числовых, так и
текстовых), в том числе построение
на их основе графиков и диаграмм. При работе
с Excel создается
так называемая рабочая книга (файл данных) с
одним или несколькими листами. Все листы
одной рабочей книги могут быть связаны друг
с другом, что позволяет организовать
совместные вычисления над размещенными на
них данными.
На рис. 1 представлена функциональная структура объектов
и коллекций Excel.
Объект Application имеет многочисленные свойства,
методы и события, управляющие сервером в
целом. Только с его помощью, например, можно
визуализировать полнофункциональное окно
текстового процессора. Его центральное
свойство Workbooks предоставляет доступ ко всем
открытым в процессоре рабочим книгам.
У каждой рабочей книги есть
свойства Worksheets
и Charts,
представляющие собой коллекции листов и
диаграмм. Первоначально коллекция Workbooks
пуста. Чтобы создать хотя бы одну рабочую
книгу, нужно обратиться к методу Workbook.Add,
который создает рабочую книгу с
количеством пустых листов, определяемым
значением свойства Application.SheetsInNewWorkbook. У
каждого рабочего листа есть свойство Cells(I,J), определяющее содержимое
ячейки, лежащей на пересечении I-го
ряда с J-м
столбцом (нумерация рядов и столбцов
начинается с 1). Если при обращении к Cells
номера столбца и ряда опущены, считается,
что речь идет о текущем диапазоне ячеек,
заданном значением свойства Worksheets.Range.
Если необходимо изменить умалчиваемые
свойства столбца или ряда, используются
объекты Worksheets.Columns и
Worksheets.Rows. Помимо рабочих листов с рабочей книгой
связывается объект Charts,
представляющий собой коллекцию диаграмм. С
каждой диаграммой связывается объект SeriesCollection,
хранящий данные, по которым строится
диаграмма.
Объекты Word
Текстовый процессор Word
является популярнейшим средством создания
и оформления (форматирования) текстовых
документов. При работе с Word
фундаментальными понятиями являются
документ, абзац и стиль. Документ
определяет файл данных. Абзац — это
совокупность символов, обрамленная
служебными символами конца строк, разрыва
колонки или разрыва раздела. Наконец, стиль
— это совокупность признаков оформления
текста: его шрифт, положение на странице,
выравнивание и т.п. Стиль — непременный
атрибут каждого абзаца, то есть изменение
стиля абзаца автоматически приводит к его
переформатированию. Однако стиль может
изменяться внутри абзаца — для выделения
группы символов шрифтом, цветом символов и (или)
фона и т.п.
На рис. 2 показана функциональная иерархия объектов Word.
Центральный объект Application
имеет такое же назначение, что и
одноименный объект Excel,
– он определяет свойства, методы и события
на уровне всего сервера. Его свойство Documents представляет собой коллекцию открытых
документов. Посредством метода Open этого объекта можно открыть ранее
созданный документ, а метода Add — создать новый документ, основанный на
стандартном шаблоне Normal.dot. Каждый документ имеет коллекцию абзацев
Paragraphs.
С помощью таких методов этого объекта, как Add, InsertParagraph,
InsertParagraphAfter,
InsertParagraphBefore,
можно вставить новый абзац в уже
существующий текст или добавить абзац в
конец документа. В свою очередь, каждый
абзац имеет многочисленные свойства,
позволяющие нужным образом
отформатировать текст. Как и в Excel,
важную роль в иерархии объектов Word
играет объект Range, определяющий диапазон абзацев. Свойство
Text этого объекта содержит текст диапазона.
Позднее связывание
Приведенный ниже пример взят из моей
практики и, думаю, сможет пригодиться и вам.
В нем прайс-лист крупного оптового
поставщика книг создается с помощью Excel.
Необходимость в обращении к Excel возникла по той причине, что прайс-лист
периодически (примерно раз в две недели)
рассылается многочисленным покупателям,
которые составляют на его основе заказы на
поставку книг. У получателей прайс-листов
нет средств прочтения отчетов в
стандартном для Delphi
формате Quick Report
(файлы с расширением qrp). Экспорт прайс-листов в файлы других
форматов не позволяет получать документы
высокого качества, поэтому я решил для
создания прайс-листов использовать
средства Excel.
На рис. 3 показан прайс-лист в окне Excel, а на рис.
4 — вид формы примера на этапе конструирования.
Перед началом работы над проектом следует скопировать все файлы BOOKS.*
в отдельную папку на жестком диске (потребуется чуть больше 800 Кбайт
свободного пространства) и связать с папкой псевдоним BDE BIBLDATA типа Standard.
Эту процедуру упростит программа SetupBooks.exe, расположенная в том же каталоге
CD-ROM.
Начните новый проект и поместите на форму компоненты Query1, Label1, Button1 и ProgressBar1.
Для компонента Query1 измените значение свойства Name на Books, свяжите его
с псевдонимом BIBLDATA и поместите в свойство SQL такой запрос:
SELECT BookID, bName, bAuthor, bPublish, bOpt, bPages, bYear FROM Books WHERE bQuan>0 ORDER BY
bName
Создайте для него все объекты-поля.
В свойство Caption
компонента Label1
поместите значение Щелкните по кнопке Пуск,
чтобы создать таблицу Excel,
в такое же свойство кнопки — значение Пуск и измените имя компонента ProgressBar1 на pb.
В окне кода в разделе private класса TForm1 поместите поле Excel типа Variant.
В предложении uses укажите ссылку на модуль COMObj и напишите следующий обработчик
события OnClick кнопки Button1 (см. листинг 1).
Теперь небольшие пояснения. Переменные Sheet и Range
введены только для сокращения текста
программы: везде вместо Sheet,
например, можно писать Excel.Workbooks[1].Sheets[1]. С версией Delphi 4 поставлялись файлы XLCONST.PAS и XLCONST.DCU, в которых определены используемые в
документации vbaxl8.hlp константы xlXXX.
С версией 5 эти файлы не поставляются,
поэтому я использую их числовые
эквиваленты. Ширина полей печатного
документа Excel
задается во внутренних единицах,
соответствующих приблизительно 3,5 мм, так
что указанные в операторах Sheet.PageSetup.ХХХMargin значения установят левое, нижнее и
правое поля шириной 1,1 см, а верхнее — 1,4 см.
Ширина столбца определяется в символах
текста, умещающегося в столбце без
отсечения.
Переменная Excel
определяет поле класса TForm1. При создании класса в него
автоматически помещается значение VarEmpty. После завершения работы с Excel
пользователь может закрыть его. Но в моей
программе Excel не визуализировался, его работа
проходила «за кулисами», а созданная
таблица записывалась в указанный
пользователем файл с помощью оператора Excel.Workbooks[1].SaveAs(FileName).
После этого Excel закрывался. Поскольку в нашем случае Excel
показывает свое окно, а пользователь может
его не закрыть, полезно написать такой
обработчик события OnDestroy формы:
procedure TForm1.FormDestroy(Sender: TObject); begin if not VarIsEmpty(Excel) then Excel.Quit end;
Запуская пример, помните, что
создание прайс-листа с помощью Excel
— процесс достаточно длительный. На моем
компьютере (400 МГц, 64 Мбайт) он занял около
минуты (для примера — аналогичный прайс-лист
средствами Quick Report
создается менее чем за 2 с). В конце
обработчика в метку lb
помещается общее время работы.
Раннее связывание
Следующий пример в функциональном плане повторяет предыдущий. В нем также с помощью Excel
создается прайс-лист, но на этот раз используется доступ непосредственно через
интерфейсы сервера. Вас ожидает «сюрприз»: время выполнения второго примера
на 40 с больше! Я не смог найти разумного объяснения этому феномену, но оба
примера находятся на сопровождающем диске, так что вы в любой момент можете
убедиться в этом сами.
Поскольку форма второго примера в точности повторяет форму первого, я не буду
объяснять, что нужно сделать для ее создания. Добавьте только на форму компонент
TExcelApplication и настройте его свойства: Name=Excel, AutoConnect=True, AutoQuit=True.
Если вы используете форму предыдущего примера как шаблон, не вставляйте поле
Excel в класс TForm1. Обработчик Button1Click должен выглядеть так (см. листинг
2).
Как видите, он во многом напоминает
обработчик предыдущего примера. Поэтому
остановлюсь на различиях.
При обращении к свойству SheetsInNewWorkbook,
как и во многих других случаях обращения к
интерфейсным свойствам и методам,
требуется указание идентификатора языка
локализации (lcid).
Значением 0 кодируется умалчиваемый язык.
Этот же идентификатор передается вторым
параметром обращения к методу Excel.Workbooks.Add. Первым параметром нужно указать имя
файла (в формате WideString),
если рабочая книга уже была ранее создана,
или «пустой» параметр EmptyParam,
если книга создается впервые.
Все мои попытки работать с объектами Range оказались неудачными. Чтобы вы не
слишком осуждали меня, я поместил
библиотеку типов Excel_TLB.pas
в каталог размещения примера — полистайте
ее на досуге и попробуйте найти нужное
решение для изменения ширины колонок и
полей листа, а также для раскрашивания
диапазона, выравнивания текста и т.п.
Есть свои нюансы и при обращении к
ячейкам. Во-первых, ими владеет объект Application,
а не Sheet.
Во-вторых, обращение к конкретному элементу
коллекции Cells (как и любой другой коллекции) возможно
только через ее свойство Item.
Подводя итоги, еще раз хочу обратить ваше
внимание на то, что по времени выполнения
позднее связывание хотя бы не проигрывает
раннему — во всяком случае, для
рассмотренных примеров. Если учесть, что
единственными доступными подавляющему
большинству программистов документами по
серверам MS
Office
являются справочные файлы vbaXXX.hlp, можно сделать вывод: использование
вариантов (позднее связывание) проще,
удобнее, а главное — намного понятнее, чем
непосредственная работа с интерфейсами (раннее
связывание).
КомпьютерПресс 6’2001
Содержание
- БП 8.3.5.1383 Ошибка COMОбъект(«Excel.Application»)
- Использование COM-соединения, выгрузка в Excel через COM-объект Excel.Application
- COM-соединение
- Объект Excel.Application
- Постановка задачи
- Алгоритм выгрузки/загрузки в MS Excel
- Пример кода 1С
БП 8.3.5.1383 Ошибка COMОбъект(«Excel.Application»)
Ексель = Новый COMОбъект(«Excel.Application»);
по причине:
-2147221005(0x800401F3): Недопустимая строка с указанием класса
(8) Создай (в блокноте) файл с расширением .vbs
Вставь туда
set xl = CreateObject(«Excel.Application»)
xl.Workbooks.Add
xl.Visible = 1
Сохрани и запусти.
Что получилось?
1) Попробуйте это
При подключении к базе com-объектом вылетает ошибка (файл с ошибкой во вложении, вылетает на строчке кода при создании ком-объекта: Коннектор = Новый COMОбъект(«V8.COMConnector»);)
На форумах по данной ошибке нашла решение, но попробовав это проделать, у меня не получилось уже на первом пункте, возможно не хватает прав. Прошу вас мне помочь.
1. Администрирование — Службы компонентов – Компьютеры – Мой компьютер – Приложения COM+ — Создать приложение – Создать новое приложение – вводим имя «V82.COMConnector»(переключатель «Серверное приложение») – Указанный пользователь (Администратор)
2. В появившейся ветке V82COMConnector – подветка Компоненты – создание нового компонента – Установка новых компонентов — bincomcntr.dll
3. Правой кнопкой по ветке V82COMConnector – Свойства – Безопасность – Снял галку «Принудительная проверка доступа для приложений» — Поставил галку «Применить политику программных ограничений» — Уровень ограничений «Неограниченный»
2) Если не помогло
1. Не установлен Microsoft Excel
2. Для работы ком-объекта необходимо наличие папки
For Windows 2008 Server x64
For Windows 2008 Server x86
1) Проделал.
2) Папка есть, только вместо Desktop — по русски Рабочий стол
Источник
Обучение программированию на 1С
Вообще COM-объекты используют для соединения информационной базы 1С с файлом Word, Excel, Outlook или любой другой программой, поддерживающей данный интерфейс обмена данными. В этой статье рассмотрим задачу выгрузки/загрузки данных из/в MS Excel. Чтобы это осуществить воспользуемся COM-соединением и объектом Excel.Application. Для примера возьмём задачу выгрузки/загрузки данных о номенклатуре. Пример рассмотрим ниже.
Что же такое COM-соединение? Component Object Model (или COM) – это технология (фирмы Microsoft) взаимодействующих компонентов, которые одновременно могут быть использованы в разных приложениях. При этом весь функционал соответствующего компонента наследуется внутрь разрабатываемого приложения. В нашем случае COM-объект Excel.Application используется внутри кода 1С для операций с файлом книги MS Excel.
Объект Excel.Application
У объекта Excel.Application существует ряд методов, которые нам могут пригодиться для реализации нижепоставленной задачи:
- ОбъектExcel.WorkBooks.Open(ИмяФайла) – Открытие книги MS Excel
- ОбъектExcel.ActiveWorkbook.Close() – Закрытие текущей книги
- ОбъектExcel.Quit() – Закрытие COM-объекта
- ОбъектExcel.Sheets(ИмяЛиста) – Получает лист книги
- ЛистExcel.Cells(НачалоСтрока, НачалоСтолбец) – Ячейка таблицы на данном листе
- ЛистExcel.Range(Ячейка1, Ячейка2) – Выделенная область
- ЯчейкаExcel.Value – Значение ячейки таблицы
- ЯчейкаExcel.Text – Текст ячейки таблицы
Постановка задачи
Итак, предположим, что в обработке 1С у нас имеется табличная часть, состоящая из следующих колонок:
- Номенклатура
- Количество
- Цена
- Сумма.
Необходимо реализовать 2 функционала (сделать на форме 2 основные кнопки):
- Выгрузка табличной части в подготовленный файл MS Excel
- Загрузка табличной части из файла.
Алгоритм выгрузки/загрузки в MS Excel
Алгоритм выгрузки следующий:
- Выгружаем табличную часть в таблицу значений
- Создаём новый COM-объект Excel.Application
- Выбираем файл, открываем файл книги MS Excel
- Переходим на заданный лист книги
- Выгружаем данные в файл
- Закрываем книгу, выходим из COM-объекта.
Алгоритм загрузки следующий:
- Создаём новый COM-объект Excel.Application
- Выбираем файл, открываем файл книги MS Excel
- Переходим на заданный лист книги
- Загружаем данные из файла в таблицу значений
- Закрываем книгу, выходим из COM-объекта
- Таблицу значений выгружаем в табличную часть.
Операция выгрузки и загрузки данных о номенклатуре происходит в заранее подготовленный шаблон MS Excel.
Пример кода 1С
Код 1С я постарался разделить на отдельные функции, чтобы, скопировав, с ними можно было работать где угодно. На форме обработки 1С были созданы 3 кнопки:
- Выгрузить
- Загрузить
- Очистить.
В итоге в реализации алгоритма получились следующие основные процедуры и функции 1С:
- ПолучитьExcel – Получает COM-объект MS Excel;
- ЗакрытьExcel – Закрывает использование COM-объекта MS Excel;
- ПолучитьЛистExcel – Получает лист книги Excel;
- ДобавитьТабличныйДокументВExcel – Добавляет табличный документ на лист Excel (нужно для выгрузки данных);
- ПрочитатьОбластьИзExcel – Читает область ячеек с листа Excel (нужно для загрузки данных);
- ШиринаЛистаExcel – Ширина листа Excel;
- ВысотаЛистаExcel – Высота листа Excel;
- ПреобразоватьТДвТЗ – Преобразует табличный документ в таблицу значений;
- ПреобразоватьТЗвТД – Преобразует таблицу значений в табличный документ;
Для начала приведу вспомогательную функцию для открытия/сохранения файла на диске:
#Если Клиент Тогда // Функция выбора файла. // // Параметры: // РежимВыбора — — Выбор каталога, открытие или сохранение файла; // Расширение — , — Список расширений файла. // // Возвращаемое значение: // — Путь к выбранному файлу. // Функция ВыбратьФайлДокумента(РежимВыбора, Расширение = «*») Экспорт ИмяФайла = «»; //ФорматМассив = РазобратьСтрокуВМассивПоРазделителю(Расширение); ФорматМассив = ПреобразоватьВМассив(Расширение); ДиалогФайла = Новый ДиалогВыбораФайла(РежимВыбора); Если РежимВыбора = РежимДиалогаВыбораФайла.Открытие Тогда ДиалогФайла.Заголовок = «Открыть документ»; ИначеЕсли РежимВыбора = РежимДиалогаВыбораФайла.Сохранение Тогда ДиалогФайла.Заголовок = «Сохранить документ»; ИначеЕсли РежимВыбора = РежимДиалогаВыбораФайла.ВыборКаталога Тогда ДиалогФайла.Заголовок = «Выбрать каталог»; КонецЕсли; Фильтр = «»; Для Каждого ЭлементМассив Из ФорматМассив Цикл Если ЭлементМассив = «*» Тогда Фильтр = Фильтр + «|» + НСтр(«ru = «»Все файлы»»; en = «»All files»»»); ИначеЕсли ВРег(ЭлементМассив) = ВРег(«TXT») Тогда Фильтр = Фильтр + «|» + НСтр(«ru = «»Текстовый документ»»; en = «»Text document»»»); ИначеЕсли ВРег(ЭлементМассив) = ВРег(«MXL») Тогда Фильтр = Фильтр + «|» + НСтр(«ru = «»Табличный документ»»; en = «»Table document»»»); ИначеЕсли ВРег(ЭлементМассив) = ВРег(«XLS») ИЛИ ВРег(ЭлементМассив) = ВРег(«XLSX») ИЛИ ВРег(ЭлементМассив) = ВРег(«XLSM») Тогда Фильтр = Фильтр + «|» + НСтр(«ru = «»Табличный документ MS Excel»»; en = «»Table document MS Excel»»»); ИначеЕсли ВРег(ЭлементМассив) = ВРег(«XML») Тогда Фильтр = Фильтр + «|» + НСтр(«ru = «»Документ XML»»; en = «»Document XML»»»); ИначеЕсли ВРег(ЭлементМассив) = ВРег(«HTML») ИЛИ ВРег(ЭлементМассив) = ВРег(«HTM») Тогда Фильтр = Фильтр + «|» + НСтр(«ru = «»HTML документ»»; en = «»HTML document»»»); Иначе Фильтр = Фильтр + «|» + НСтр(«ru = «»Файл » + ВРег(ЭлементМассив) + «»»; en = «»File » + ВРег(ЭлементМассив) + «»»»); КонецЕсли; Фильтр = Фильтр + » (*.» + НРег(ЭлементМассив) + «)|*.» + НРег(ЭлементМассив); КонецЦикла; Фильтр = Сред(Фильтр, 2); ДиалогФайла.Фильтр = Фильтр; ДиалогФайла.МножественныйВыбор = Ложь; Если ДиалогФайла.Выбрать() Тогда ИмяФайла = ?(РежимВыбора = РежимДиалогаВыбораФайла.ВыборКаталога, ДиалогФайла.Каталог, ДиалогФайла.ПолноеИмяФайла); Иначе Текст = «ru = «»Файл не выбран!»»; en = «»File(s) not selected!»»»; Предупреждение(НСтр(Текст)); КонецЕсли; Возврат ИмяФайла; КонецФункции #КонецЕсли
Также в реализации алгоритма были задействованы следующие вспомогательные функции:
// Преобразует в массив переменную любого типа данных. // // Параметры: // Объект — Произвольный — произвольный объект данных; // Проверка — — Осуществление проверки на заполненное значение. // // Возвращаемое значение: // — Массив с теми же данными. // Функция ПреобразоватьВМассив(Объект, Проверка = Ложь) Экспорт ОбъектМассив = Новый Массив; Если НЕ Проверка ИЛИ ЗначениеЗаполнено(Объект) Тогда Если ТипЗнч(Объект) = Тип(«Массив») Тогда ОбъектМассив = Объект; ИначеЕсли ТипЗнч(Объект) = Тип(«СписокЗначений») Тогда ОбъектМассив = Объект.ВыгрузитьЗначения(); ИначеЕсли ТипЗнч(Объект) = Тип(«Строка») Тогда ОбъектМассив = РазобратьСтрокуВМассивПоРазделителю(Объект); ИначеЕсли ТипЗнч(Объект) = Тип(«Структура») Тогда Для Каждого Элемент Из Объект Цикл ОбъектМассив.Добавить(Элемент.Значение); КонецЦикла; Иначе ОбъектМассив.Добавить(Объект); КонецЕсли; КонецЕсли; Возврат ОбъектМассив; КонецФункции;
// Разбирает строку в массив подстрок по разделителю. // При этом пробелы между подстроками не учитываются. // // Параметры: // Стр — исходная строка; // СтрРазделитель — разделитель, по умолчанию «,»; // ИгнорироватьПустые — игнорировать ли пустые места между разделителями. // // Возвращаемое значение: // Массив строк // Функция РазобратьСтрокуВМассивПоРазделителю(Знач Стр, СтрРазделитель = «,», ИгнорироватьПустые = Ложь) Экспорт Результат = Новый Массив; ВхождениеРазделителя = Найти(Стр, СтрРазделитель); Пока ВхождениеРазделителя <> 0 Цикл ЧастьДоРазделителя = СокрЛП(Лев(Стр, ВхождениеРазделителя — 1)); Если НЕ (ИгнорироватьПустые И ПустаяСтрока(ЧастьДоРазделителя)) Тогда Результат.Добавить(ЧастьДоРазделителя); КонецЕсли; Стр = СокрЛП(Сред(Стр, ВхождениеРазделителя + 1)); ВхождениеРазделителя = Найти(Стр, СтрРазделитель); КонецЦикла; Если НЕ (ИгнорироватьПустые И ПустаяСтрока(Стр)) Тогда Результат.Добавить(СокрЛП(Стр)); КонецЕсли; Возврат Результат; КонецФункции;
// Создаёт новую таблицу значений с заданными колонками. // // Параметры: // пКолонки — , , , , — // Набор колонок для таблицы значений. // // Возвращаемое значение: // — Созданная таблица. // Функция ПолучитьТаблицуВывода(пКолонки) Экспорт ТЗ = Новый ТаблицаЗначений; Если пКолонки <> Неопределено Тогда Если ТипЗнч(пКолонки) = Тип(«Строка») Тогда пКолонки = РазобратьСтрокуВМассивПоРазделителю(пКолонки); КонецЕсли; Если ТипЗнч(пКолонки) = Тип(«Структура») Тогда Для Каждого Поле Из пКолонки Цикл СтрокаТабл = ТЗ.Колонки.Добавить(Поле.Ключ, Поле.Значение); КонецЦикла; ИначеЕсли ТипЗнч(пКолонки) = Тип(«СписокЗначений») Тогда Для Каждого Поле Из пКолонки Цикл Если Поле.Пометка Тогда СтрокаТабл = ТЗ.Колонки.Добавить(Поле.Значение, пКолонки.ТипЗначения, Поле.Представление); КонецЕсли; КонецЦикла; ИначеЕсли ТипЗнч(пКолонки) = Тип(«ТаблицаЗначений») Тогда ЕстьНаименование = (пКолонки.Колонки.Найти(«Наименование») <> Неопределено); ЕстьТипЗначения = (пКолонки.Колонки.Найти(«ТипЗначения») <> Неопределено); ЕстьЗаголовок = (пКолонки.Колонки.Найти(«Заголовок») <> Неопределено); ЕстьШирина = (пКолонки.Колонки.Найти(«Ширина») <> Неопределено); Для Каждого Поле Из пКолонки Цикл СтрокаТабл = ТЗ.Колонки.Добавить(?(ЕстьНаименование, Поле.Наименование, «»), ?(ЕстьТипЗначения, Поле.ТипЗначения, Новый ОписаниеТипов), ?(ЕстьЗаголовок, Поле.Заголовок, «»), ?(ЕстьШирина, Поле.Ширина, 0)); КонецЦикла; Иначе Для Каждого Поле Из пКолонки Цикл СтрокаТабл = ТЗ.Колонки.Добавить(Поле); КонецЦикла; КонецЕсли; КонецЕсли; Возврат ТЗ; КонецФункции;
// Создаёт структуру колонок из таблицы значений. // // Параметры: // ТабЗначений — — Любая таблица. // // Возвращаемое значение: // — Созданная таблица. // Функция ПолучитьСтруктуруКолонокИзТаблицы(ТабЗначений) Экспорт СтруктураКолонок = Новый Структура; Для Каждого ЭлементКолонка Из ТабЗначений.Колонки Цикл СтруктураКолонок.Вставить(ЭлементКолонка.Имя, ЭлементКолонка.ТипЗначения); КонецЦикла; Возврат СтруктураКолонок; КонецФункции;
Основные функции обработки алгоритма следующие:
// Получает объект файла MS Excel. // // Параметры: // ИмяФайла — — Путь к файлу XLS. // // Возвращаемое значение: // — Полученный объект. Если объект не найден, то возвращается «Неопределено». // Функция ПолучитьExcel(ИмяФайла) Экспорт ФайлНаДиске = Новый Файл(ИмяФайла); Excel = Неопределено; Если нРег(ФайлНаДиске.Расширение) = «.xls» ИЛИ нРег(ФайлНаДиске.Расширение) = «.xlsx» ИЛИ нРег(ФайлНаДиске.Расширение) = «.xlsm» Тогда Если НЕ ФайлНаДиске.Существует() Тогда Сообщить(«Файл не существует!», СтатусСообщения.Внимание); Возврат Неопределено; КонецЕсли; Попытка Excel = Новый COMОбъект(«Excel.Application»); Excel.WorkBooks.Open(ИмяФайла); Исключение Сообщить(«Не удалось инициализировать Excel!», СтатусСообщения.Внимание); Возврат Неопределено; КонецПопытки; КонецЕсли; Возврат Excel; КонецФункции;
// Закрывает файл MS Excel. // // Параметры: // Excel — — Объект файла MS Excel; // Сохранить — — Указывает сохранять файл при закрытии или нет. По умолчанию // пользователю предлагается выбрать это самому. // Процедура ЗакрытьExcel(Excel, Сохранить = Неопределено) Экспорт Попытка #Если Клиент Тогда Состояние(«Закрытие файла Microsoft Excel. «); #КонецЕсли Если Сохранить = Неопределено Тогда Excel.ActiveWorkbook.Close(); Иначе Excel.ActiveWorkbook.Close(Сохранить); КонецЕсли; Excel.Quit(); Исключение Сообщить(«Ошибка закрытия Excel!», СтатусСообщения.Внимание); КонецПопытки; Excel = Неопределено; КонецПроцедуры;
// Получает лист из файла книги MS Excel. // // Параметры: // Excel — — Объект файла MS Excel; // ИмяЛиста — — Имя листа книги MS Excel. // // Возвращаемое значение: // — Полученный лист. Если объект не найден, то возвращается «Неопределено». // Функция ПолучитьЛистExcel(Excel, ИмяЛиста) Экспорт Попытка ExcelЛист = Excel.Sheets(ИмяЛиста); Исключение Сообщить(«Не удалось прочитать лист Excel!», СтатусСообщения.Внимание); Возврат Неопределено; КонецПопытки; Возврат ExcelЛист; КонецФункции;
// Записывает данные из табличного документа в файл MS Excel. // // Параметры: // ЛистExcel — — Лист из файла MS Excel; // Таблица — — Документ, по порядку следования колонок и строк // соответствующий листу файла MS Excel; // Шапка — — Количество первых строк для шапки в файле MS Excel; // СписокСтолбцов — , — Список номеров столбцов, которые будут выгружены // в файл MS Excel; // СписокСтрокЗапрета — , — Список номеров строк, которые не должны // выгружаться в файл MS Excel. Если этот параметр не задан, то выгружаются все строки; // ПроверятьЗначения — — Определяет будут ли проверяться ячейки табличного // документа на содержание в них значения, а не текстовое представление этого значения. // По умолчанию этот параметр «Ложь». // Процедура ДобавитьТабличныйДокументВExcel(ЛистExcel, Таблица, Шапка, СписокСтолбцов, СписокСтрокЗапрета = Неопределено, ПроверятьЗначения = Ложь) Экспорт Если ТипЗнч(СписокСтолбцов) = Тип(«Строка») Тогда СписокСтолбцов = РазобратьСтрокуВМассивПоРазделителю(СписокСтолбцов); КонецЕсли; Если ТипЗнч(СписокСтрокЗапрета) = Тип(«Строка») Тогда СписокСтрокЗапрета = РазобратьСтрокуВМассивПоРазделителю(СписокСтрокЗапрета); КонецЕсли; ЕстьМассив = (СписокСтрокЗапрета = Неопределено); Если ЕстьМассив Тогда Попытка МассивCOM = Новый COMSafeArray(«VT_VARIANT», 1, Таблица.ВысотаТаблицы — Шапка); Исключение ЕстьМассив = Ложь; КонецПопытки; КонецЕсли; Для Каждого НомерСтолбца Из СписокСтолбцов Цикл Для НомерСтроки = Шапка+1 По Таблица.ВысотаТаблицы Цикл Если СписокСтрокЗапрета = Неопределено ИЛИ (СписокСтрокЗапрета.Найти(Строка(НомерСтроки)) = Неопределено И СписокСтрокЗапрета.Найти(Число(НомерСтроки)) = Неопределено) Тогда Область = Таблица.Область(НомерСтроки, Число(НомерСтолбца)); Значение = ?(ПроверятьЗначения И Область.СодержитЗначение, Область.Значение, Область.Текст); Если ЕстьМассив Тогда МассивCOM.SetValue(0, НомерСтроки-Шапка-1, Значение); Иначе ЛистExcel.Cells(НомерСтроки, Число(НомерСтолбца)).Value = Значение; КонецЕсли; КонецЕсли; КонецЦикла; Если ЕстьМассив Тогда ЛистExcel.Range(ЛистExcel.Cells(Шапка+1, Число(НомерСтолбца)), ЛистExcel.Cells(Таблица.ВысотаТаблицы, Число(НомерСтолбца))).Value = МассивCOM; КонецЕсли; КонецЦикла; КонецПроцедуры;
// Читает область ячеек из MS Excel в табличный документ. // // Параметры: // ЛистExcel — — Лист из файла MS Excel; // ТабДок — — Исходный табличный документ, поле табличного // документа или таблица значений. Если этот параметр не задан, то создаётся // новый табличный документ; // НачалоСтрока — — Начальная строка в файле MS Excel; // НачалоСтолбец — — Начальный столбец в файле MS Excel; // КонецСтрока — — Конечная строка в файле MS Excel; // КонецСтолбец — — Конечный столбец в файле MS Excel. // // Возвращаемое значение: // — Возвращает прочитанный из области в MS Excel табличный // документ, который передавался в эту функцию параметром «ТабДок». // Функция ПрочитатьОбластьИзExcel(ЛистExcel, ТабДок = Неопределено, НачалоСтрока, НачалоСтолбец, КонецСтрока, КонецСтолбец) Экспорт Если ТабДок = Неопределено Тогда ТабДок = Новый ТабличныйДокумент; КонецЕсли; Попытка МассивCOM = Новый COMSafeArray(«VT_VARIANT», КонецСтолбец — НачалоСтолбец + 1, КонецСтрока — НачалоСтрока + 1); ЕстьМассив = Истина; Исключение ЕстьМассив = Ложь; КонецПопытки; Если ЕстьМассив Тогда МассивCOM = ЛистExcel.Range(ЛистExcel.Cells(НачалоСтрока, НачалоСтолбец), ЛистExcel.Cells(КонецСтрока, КонецСтолбец)).Value; Для ИндексКолонка = НачалоСтолбец По КонецСтолбец Цикл Для ИндексСтрока = НачалоСтрока По КонецСтрока Цикл Значение = МассивCOM.GetValue(ИндексКолонка — НачалоСтолбец + 1, ИндексСтрока — НачалоСтрока + 1); ТабДок.Область(ИндексСтрока, ИндексКолонка).СодержитЗначение = Истина; ТабДок.Область(ИндексСтрока, ИндексКолонка).Значение = Значение; КонецЦикла; КонецЦикла; Иначе Для ИндексКолонка = НачалоСтолбец По КонецСтолбец Цикл Для ИндексСтрока = НачалоСтрока По КонецСтрока Цикл Значение = ЛистExcel.Cells(ИндексСтрока, ИндексКолонка).Value; ТабДок.Область(ИндексСтрока, ИндексКолонка).СодержитЗначение = Истина; ТабДок.Область(ИндексСтрока, ИндексКолонка).Значение = Значение; КонецЦикла; КонецЦикла; КонецЕсли; Возврат ТабДок; КонецФункции;
// Определяет ширину листа MS Excel. // // Параметры: // ЛистExcel — — Лист из файла MS Excel. // // Возвращаемое значение: // — Количество столбцов в таблице. // Функция ШиринаЛистаExcel(ЛистExcel) Экспорт ЕстьЗащита = ЛистExcel.ProtectContents; Возврат ?(ЕстьЗащита, ЛистExcel.UsedRange.Columns.Count, ЛистExcel.Cells.SpecialCells(11).Column); КонецФункции;
// Определяет высоту листа MS Excel. // // Параметры: // ЛистExcel — — Лист из файла MS Excel. // // Возвращаемое значение: // — Количество строк в таблице. // Функция ВысотаЛистаExcel(ЛистExcel) Экспорт ЕстьЗащита = ЛистExcel.ProtectContents; Возврат ?(ЕстьЗащита, ЛистExcel.UsedRange.Rows.Count, ЛистExcel.Cells.SpecialCells(11).Row); КонецФункции;
// Преобразовать табличный документ в таблицу значений. // // Параметры: // ТабДок — — Исходный табличный документ; // СтруктураКолонок — , — Структура колонок; // НачалоСтрока — — Строка начала области; // НачалоСтолбец — — Столбец начала области; // КонецСтрока — — Строка конца области; // КонецСтолбец — — Столбец конца области. // // Возвращаемое значение: // — Полученная таблица значений. // Функция ПреобразоватьТДвТЗ(ТабДок, СтруктураКолонок, Знач НачалоСтрока = Неопределено, Знач НачалоСтолбец = Неопределено, Знач КонецСтрока = Неопределено, Знач КонецСтолбец = Неопределено) Экспорт // Определение габаритов таблицы Если НачалоСтрока = Неопределено И НачалоСтолбец = Неопределено Тогда НачалоСтрока = 1; НачалоСтолбец = 1; КонецЕсли; Если НачалоСтрока = Неопределено Тогда НачалоСтрока = 1; Пока НЕ ТабДок.Область(НачалоСтрока, НачалоСтолбец).СодержитЗначение И НачалоСтрока — Исходная таблица значений; // ТабДок — — Полученный табличный документ. Если параметр не задан, // то документ создаётся заново и возвращается функцией; // НачалоСтрока — — Строка начала области; // НачалоСтолбец — — Столбец начала области; // ВыводитьЗаголовки — — Определяет выводить ли имена колонок или нет. // // Возвращаемое значение: // — Полученный табличный документ (возвращает параметр «ТабДок»). // Функция ПреобразоватьТЗвТД(ТабЗначений, ТабДок = Неопределено, Знач НачалоСтрока = Неопределено, Знач НачалоСтолбец = Неопределено, ВыводитьЗаголовки = Ложь) Экспорт Если ТабДок = Неопределено Тогда ТабДок = Новый ТабличныйДокумент; КонецЕсли; // Определение габаритов таблицы НачалоСтрока = ?(НачалоСтрока = Неопределено, 1, НачалоСтрока); НачалоСтолбец = ?(НачалоСтолбец = Неопределено, 1, НачалоСтолбец); // Преобразование ИндексСтроки = НачалоСтрока; Если ВыводитьЗаголовки Тогда ИндексКолонки = НачалоСтолбец; Для Каждого Колонка Из ТабЗначений.Колонки Цикл ТабДок.Область(ИндексСтроки, ИндексКолонки).Текст = ?(ПустаяСтрока(Колонка.Заголовок), Колонка.Имя, Колонка.Заголовок); ИндексКолонки = ИндексКолонки + 1; КонецЦикла; ИндексСтроки = ИндексСтроки + 1; КонецЕсли; Для Каждого Элемент Из ТабЗначений Цикл ИндексКолонки = НачалоСтолбец; Для Каждого Колонка Из ТабЗначений.Колонки Цикл ТабДок.Область(ИндексСтроки, ИндексКолонки).СодержитЗначение = Истина; ТабДок.Область(ИндексСтроки, ИндексКолонки).ТипЗначения = Новый ОписаниеТипов(Колонка.ТипЗначения); ТабДок.Область(ИндексСтроки, ИндексКолонки).Значение = Элемент[Колонка.Имя]; ИндексКолонки = ИндексКолонки + 1; КонецЦикла; ИндексСтроки = ИндексСтроки + 1; КонецЦикла; Возврат ТабДок; КонецФункции;
В реализации алгоритма был дополнительно использован объект COMSafeArray с типом VT_VARIANT. Этот COM-объект выступает в качестве двумерного массива, в котором удобно хранить значения ячеек. Также использование данного объекта повышает быстродействие операций чтения/записи для ячеек таблицы.
Целиком получившуюся обработку 1С, а также шаблон для загрузки/выгрузки можно скачать по ссылке ниже.
Указанные здесь процедуры и функции я постарался сделать универсальными. Они могут быть применены для широкого круга прикладных задач.
Источник