Работа с Word из 1С. Работа с таблицами




Одно дело, когда заранее известно количество строк в таблице. И решение, соответственно, тоже простое: создать в шаблоне таблицу и заполнить переменные программно.
Но вот совсем другой подход, когда количество строк или колонок неизвестно.
В этом примере продемонстрировано, как можно создать табличную часть в документе Word.
Выбор, какой из перечисленных далее методов использовать, за Вами.

Одно дело, когда заранее известно количество строк в таблице. И решение, соответственно, тоже простое: создать в шаблоне таблицу и заполнить переменные программно. Ссылка на данный пример //infostart.ru/public/18940/

Но вот совсем другой подход, когда количество строк или колонок неизвестно.

История «Как я к этому пришел»

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

Тогда, еще в 2006 году вопрос решился 5 шаблонами, в табличных частях которых было от 1 до 5 строк (ограничились 5 договорами). Вопрос решился и забылся. Но вот вопрос стал актуален по причине печати нового договора, в котором задействована номенклатура, а количество строк ведь может переваливать добрую сотню наименований. И следовательно  — выход в создании динамической таблицы в шаблоне Word, который и описан двумя самыми простыми способами.

Есть 2 подхода к созданию таблицы.

1) Вам нужна таблица с равной шириной колонок, так сказать созданная автоматически.

2) У вас есть шаблон таблицы (только шапка и 1 строка).

Код создания таблицы с автоформатом.

Процедура СоздатьПример1(Кнопка)
НовоеНапоминание = ПолучитьМакет("Пример1");

Массив = Новый Массив(5);//сделаем таблицу из 5 строк + шапка

MsWord = НовоеНапоминание.Получить();


//макет является ActiveDocwment с загруженым в него Word-файлом
Попытка
//Вставление таблицы с 10 строки
MsWord.Application.Visible = 0;
Word = MsWord.Application;
Док=Word.Documents(1);
Док.Activate();

//подготовка таблицы:
//Вариант №1 Самый простой
Word.Selection.MoveDown(,10); //10 строка - первая строка таблицы
//Конец Варианта №1

//Вариант №2
Word.Bookmarks("ff").Select(); //Где ff - это набор любых символов, вплоть до непечатаемых;)
//Конец Варианта №2

Табл= Word.Selection.Range;
//Формируем заголовок:
Табл.InsertAfter("Сумма*Валюта*Назначение*Дата долга*Вид документа*Номер документа* *Дата оплаты");
Табл.InsertParagraphAfter();
//сама таблица
Для й = 1 по Массив.Количество() Цикл
Табл.InsertAfter(массЗнчСтрокиТЧ[0]+"*"+массЗнчСтрокиТЧ[1]+"*"+массЗнчСтрокиТЧ[2]+"*"+массЗнчСтрокиТЧ[3]+"*"+ массЗнчСтрокиТЧ[4]+ "*"+массЗнчСтрокиТЧ[5]+ "*"+массЗнчСтрокиТЧ[6]+ "*"+массЗнчСтрокиТЧ[7]);
Табл.InsertParagraphAfter();
КонецЦикла;

Табл.ConvertToTable("*");

//Происходит конвертация строки в таблицу

//не нравятся звездочки - используйте другой символ
Док.Tables(1).AutoFormat(1);

ПечатныйНомер = "-"+Формат(ТекущаяДата(),"ДФ=yyyy.MM.dd")+"-"+Формат(ДатаОтчета,"ДФ=yyyy.MM.dd");
Файл = КаталогВременныхФайлов() + "" + ПечатныйНомер + ".doc";

Док.SaveAs(Файл);
Док.Close(0);

//МассивДокументов.Добавить(Файл);  //добавлял в массив путь к файлу и после всех манипуляций открывал каждый файл
ЗапуститьПриложение("""" + Файл + """");

Исключение
Сообщить(ОписаниеОшибки());
Word.Quit();
КонецПопытки;

КонецПроцедуры

Код создания таблицы с наследуемым форматом.

Процедура СоздатьПример2(Кнопка)
НовоеНапоминание = ПолучитьМакет("Пример2");

Массив = Новый Массив(5);//добавим 4 строки

MsWord = НовоеНапоминание.Получить();
//макет является ActiveDocwment с загруженым в него Word-файлом
Попытка

MsWord.Application.Visible = 0;
Word = MsWord.Application;
Док=Word.Documents(1);
Док.Activate();


Если Массив.Количество()>1 Тогда
//Переместиться вниз на 10 строк от начала документа
Word.Selection.MoveDown(,10); //10 строка - первая строка таблицы
//назад на 1 символ (окончание строки таблицы)
Word.Selection.MoveLeft(,1);
//кво документов которые необходимо забить в табличную часть
Word.Selection.InsertRows(Массив.Количество()-1);

Word.Selection.MoveLeft(,1);
Для й = 11 по Массив.Количество()+9 Цикл
ЗаполнитьСтрокуТЧ(0,Word);
Word.Selection.MoveRight(,1);
КонецЦикла;
КонецЕсли;

ПечатныйНомер = "-"+Формат(ТекущаяДата(),"ДФ=yyyy.MM.dd")+"-"+Формат(ДатаОтчета,"ДФ=yyyy.MM.dd");

//Таблицу заполнять не буду, только шапку

Замена = Док.Content.Find;
Замена.Execute("", Ложь, Истина, Ложь, , , Истина, , Ложь, "ООО 'Пупкин inc.'");

Замена = Док.Content.Find;
Замена.Execute("", Ложь, Истина, Ложь, , , Истина, , Ложь, Формат(ТекущаяДата(),"Л=uk; ДЛФ=D"));

Замена = Док.Content.Find;
Замена.Execute("", Ложь, Истина, Ложь, , , Истина, , Ложь, ПечатныйНомер );

Файл = КаталогВременныхФайлов() + "" + ПечатныйНомер + ".doc";

Док.SaveAs(Файл);
Док.Close(0);

//МассивДокументов.Добавить(Файл);  //добавлял в массив путь к файлу и после всех манипуляций открывал каждый файл
ЗапуститьПриложение("""" + Файл + """");
Исключение
Сообщить(ОписаниеОшибки());
Word.Quit();
КонецПопытки;

КонецПроцедуры

Процедура ЗаполнитьСтрокуТЧ(знчЭл,Word)

Если знчЭл массЗнчСтрокиТЧ.Количество()-1 Тогда
текЭлем = массЗнчСтрокиТЧ[знчЭл];
Rng = Word.Selection.Range;
Rng.InsertAfter(текЭлем);
ДлинаЗнч = СтрДлина(текЭлем)+1;

Word.Selection.MoveRight(,ДлинаЗнч);

Если знчЭл < массЗнчСтрокиТЧ.Количество()-1 Тогда
знчЭл = знчЭл + 1;
ЗаполнитьСтрокуТЧ(знчЭл,Word);
КонецЕсли;
КонецЕсли;

КонецПроцедуры


56 Comments

  1. JIGIT

    По возможности — пример…

    Заранее благодарен

    Reply
  2. endym

    Мне не сложно;) будет вечерком.

    Reply
  3. endym

    Добавил простенький примерчик. Жду комментов))))

    Reply
  4. Evg-Lylyk

    Покрасьте код http://infostart.ru/public/19856/

    еще скриншоты бы не помешали

    Reply
  5. endym

    Код подкрашу, а вот скриншоты к чему? это статья.

    Reply
  6. Душелов

    (5) На статью не тянет.

    Reply
  7. endym

    Это пример, часть работающего кода. Решил поделиться с теми, кому это может пригодиться. Зачем выпендриваться и придираться к словам? (6)

    Reply
  8. Evg-Lylyk

    (7) Материал нормальный только пожалуйста оформите нормально

    Раскрасте с помощью обработки http://infostart.ru/public/19856/

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

    Reply
  9. endym

    (8) я то и раскрасил вот той обработкой.

    а что показывать в скриншотах? листочек word? 😉 это же пример.. так сказать заготовка.

    Если уж так надо — могу сделать 4 скрина: 2 (по 1 на каждый вариант) «до» и «после».

    Причина почему я выложил — нигде толком не было объяснения как же быть в ситуации когда нужна таблица в договоре, а количество строк/столбцов варьируется.

    З.Ы. подобные ссылки видны справа.

    использовал материал команд VBA для Word.

    Reply
  10. Душелов

    (7) На момент написания комментария кода не было.

    А было 5 строк текста и приложенная обработка — это больше к «программе» относилось, чем статье. И последите за словами, перед Вами никто не «выпендривался»

    Reply
  11. endym

    (10) Изначально выложил только код.

    После попросили (1) пример, для чего прикрепил обработку.

    Reply
  12. Поручик

    Автор, глянь на это

    http://infostart.ru/public/18940/

    В своё время здорово выручила.

    Reply
  13. endym

    (12) видел, и что? это готовый шаблон, который надо заполнять ручками. а если не знать сколько реквизитов, т.е. выбирать через * все поля? как тогда?

    в данном примере(если можно так назвать) , повторюсь, описывается возможность создания строк в ЛЮБОМ МЕСТЕ даже не зная сколько строк выйдет всего.

    Если есть пожелания — выслушаю. ссылку добавлю в шапку.

    Reply
  14. KVS

    Полезный пример. Спасибо

    Reply
  15. Boroda

    Спасибо! Пример очень пригодится и в качестве ученого материала. и в качестве его практической реализации в отчётах, которых последнее время треуется всё больше и сложнее.

    Reply
  16. Vovanich

    {ВнешняяОбработка.ПечатьАктаНаСписание.МодульОбъекта(225)}: Ошибка при вызове метода контекста (InsertRows): Произошла исключительная ситуация (Microsoft Word): Метод или свойство недоступны, поскольку некоторые или все объекты не ссылаются на таблицу. Как раз нужно сделать ВПФ Требования накладной в макете Ворд. Вставил твой код и вот такая ошибка.

    Reply
  17. endym

    (16) Очень интересно. хотелось бы узнать как появилась такая ошибка. Можно по-подробнее?

    Reply
  18. Vovanich

    Сорри…Вопрос снят таблицу в макете разместил не там где надо вот он и поругался.

    Reply
  19. Vovanich

    Материал очень полезный, но пожалста можно привести пример кода который будет в создаваемую таблицу в макете запихивать данные из моей ТабЗнач.В общем задача такая сделать ВПФ списания материалов из документа Требование накладная. Запросом все данные получил нарисовал стандартный табличный макетик, но заказчик хочет чтоб в Ворде это все выводилось..Если не трудно пособите.

    Reply
  20. endym

    (19)

    не трудно, надо только ваши исходники;))

    Reply
  21. Vovanich

    куда обработку положить?или прям в сообщение код вставить?

    Reply
  22. endym

    (21)весь в работе.

    Сегодня посмотрел обработку по печати Акта.

    А где Ваш макет word’овский? Ведь ресурс чтобы помогать а не делать за кого-то работу)

    Reply
  23. kuz.mina

    Спасибо за материал! но у меня возникла проблема:

    В документе 5 листов, таблица на последнем(150 строка), но дальше чем на 44 строке(последняя строка первого листа) программа не видит таблицу:

    {ВнешняяОбработка.Договор_поставки.МодульОбъекта(363)}: Ошибка при вызове метода контекста (InsertRows): Произошла исключительная ситуация (Microsoft Word): Метод или свойство недоступны, поскольку некоторые или все объекты не ссылаются на таблицу.

    Как добавить таблицу на последний лист?

    Reply
  24. endym

    (23)Как добавить таблицу на последний лист?

    Можно воспользоваться «шаблоном таблицы» или если используете таблицу с автоформатом — тогда перейти на последнюю страницу командой контрл+ енд

    Reply
  25. kuz.mina

    (24) я как раз и делаю через шаблон. если таблица находится не на первой странице, программа ее не находит

    Reply
  26. endym

    (25) Значит word не находит текст для замены, хоть на 99 странице будет текст в таблице.

    данный механизм успешно работает при заполнении договоров купли-продажи в 15 и более листов)

    Reply
  27. stanru2

    Добрый день!

    Спасибо за полезный пример, мне он помог.

    По второй части хочу уточнить вот какой момент.

    Если документ ворд состоит из некоего текста и шаблона таблицы, и текст динамически генерирует одинэсом, то заранее неизвестно, в каком месте документа будет таблица. Поэтому использовать

    Word.Selection.MoveDown(,10); //10 строка — первая строка таблицы

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

    Word.Bookmarks(«ff»).Select();

    ЗЫ и строку в таблице можно добавлять по мере необходимости 🙂 Но это вкусовщина уже, работает и так, и эдак.

    Reply
  28. endym

    (27)Полностью согласен, но! в моем примере таблица на десятой строке;)

    можно даже вставить непечатаемый символ и отслеживать его. Мой пример не является аксиомой, а лишь механизмом для дальнейшего развития темы;)

    UPD: (27) добавил в шапке в первом примере 😉

    Reply
  29. stanru2

    (28) и этот пример очень полезен! Пожалуй, один из самых наглядных среди n страниц поиска яндекса. Мне ранее не требовалось делать экспорт в вород, благодаря примеру разобрался быстро.

    Можно еще в конце статьи добавить ссылок на объектную модель ворда.

    А не подскажете, есть ли где пример «пряморукого» импорта из ворда (надо импортировать не тупо текст, текст получается в одном свойстве. Надо анализировать формат текста и в соотв. с ним разносить строки по реквизитам)? Перерыл пол-гугла, не нашел ничего толкового. В результате сделал перебор текста построчно через paragraphs. В каждом параграфе у первого слова проверяется формат, и дальше уже дело техники. Работает прямо скажем небыстро 🙁 А хочется сделать максимально хорошо.

     тд = новый ТекстовыйДокумент;
    текст = док.Content.FormattedText;
    
    ЭлементыФормы.Индикатор1.МаксимальноеЗначение = текст.paragraphs.Count;
    
    
    для с = 1 по ЭлементыФормы.Индикатор1.МаксимальноеЗначение цикл
    
    ЭлементыФормы.Индикатор1.Значение = с;
    текСтр = текст.paragraphs(с).Range.Text;
    если (текст.paragraphs(с).Range.Words(1).Underline = 1) тогда
    текСлово = сокрлп(текст.paragraphs(с).Range.Words(1).Text);
    если (текСлово<>»») и (текСлово<>Символы.ВК) тогда
    текСтр = «$»+текСтр;
    КонецЕсли;
    КонецЕсли;
    тд.ДобавитьСтроку(текСтр);
    
    КонецЦикла;

    Показать

    Reply
  30. alecs2004

    Полезный пример. Спасибо

    Reply
  31. necropunk

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

    Reply
  32. Alex Prikol

    спасибо.

    видно, автор копнул глубоко, кое что пригодится

    Reply
  33. endym

    (29) я уже где-то встречал парсер ворда, думаю что он не сложнее парсера mt940 и подобных форматов;)

    у Word’a есть команды на VBA, которыми можно позиционироваться на каждом элементе, будь то слово, таблица, рисунок…

    Reply
  34. stanru2

    (33) у меня определенные трудности были не с тем, как обработать данные, а с тем, как их получить 🙂 Объектная модель ворда для меня непривычна и незнакома, вот и сложности возникли 🙂

    Reply
  35. SERJ_1CC

    То что надо, именно это и искал, примерчик очень хороший… Благодарю плюсом!!!

    Reply
  36. gurovvv

    спасибо!

    просто,удобно. для начала обучения работы с вордом — отличный вариант.

    Reply
  37. pavel_pss

    Предлагаю так же посмотреть и мой вариант http://infostart.ru/public/95012/

    Reply
  38. endym

    (37) apalon_pss, мне кажется или это лишь часть описанного в моей статье?;))

    Reply
  39. lelusha

    спасибо! простой пример и очень понятно. отличный вариант. Автору спасибо, поможет для обучения работы с вордом —

    Reply
  40. Гость

    А как в макете настроить чтобы применить вариант: Word.Bookmarks(«ff»).Select(); //Где ff — это набор любых символов

    Reply
  41. endym

    Нужно просто ввести понравившиеся вам символы в любом месте макета.

    Word.Bookmarks(«ff»).Select() — это команда ищет в макете символы ff

    Reply
  42. gull22

    Дорога ложка к обеду, спасибо за информацию.

    Reply
  43. monkbest

    (41) нет, она не ищет символы ff. она ищет метку с именем ff :)) вставлять метки в документе <> написать имя в текте документа

    смотрите http://prosto1s.ru/index.php/24-pechat-v-word-chast-2-metod-zameny-tegov-klonirovanie-abzatsev-stok-tablitsy

    там написано как добавлять метки

    Reply
  44. endym

    (43) monkbest, именно ищет текст и заменяет его на все что захочет пользователь.

    З.Ы. метки это совсем другое;) матчасть рулит

    Reply
  45. monkbest

    (44) Word.Bookmarks(«ff»).Select();

    Bookmarks — коллекция меток документа

    через скобочки с именем метки, можно получить саму метку

    у неё есть метод select, который возвращает выделение области от начала метки до конца метки

    это выделение можно скопировать в буфер, вырезать, вставить на его место то что уже лежит в буфере (cut() copy() paste())

    Reply
  46. script

    Вот интересно как сделать две таблицы программно ?

    По метке мы заменили одну таблицу, а если нужно вставить еще одну ниже.

    Или таблицы нужно создавать в цикле, одна под одной как быть?

    Метка уже не сработает, потому что ее перезаписали и на ее месте находится первая таблица.

    Получается что метка служит всего навсего начальной областью куда нужно вставить первую таблицу но что дальше?

    Reply
  47. endym

    Если Вы заранее знаете что там будет еще одна таблица — тогда добавить еще метку и обработать по уже известному алгоритму)

    Метки обрабатываются последовательно.

    Reply
  48. kuza_87

    Друзья, кто-нибудь подскажет, можно ли в текст документа вставить специальный символ? Например символ бесконечности, евро или фунта стерлингов.

    Reply
  49. endym

    (48) kuza_87,

    Можно. Используй комбинацию Аль+

    Reply
  50. DedMoroz1983

    Долго формируется таблица.

    Reply
  51. pyrkin_vanya

    А как заполнить данные в таблице из табличной части нужного объекта?

    Reply
  52. pyrkin_vanya

    (27) не получается определить закладку. У меня пишет, что метод объекта не обнаружен Bookmarks. Попробовал заменить в вашей обработке, тоже самое. Может можно как-то еще определить с какой строки начинается таблица? Или может я просто не правильно пишу?

    Word.Bookmarks(«ff»).Select();

    Reply
  53. endym

    (52) «ff» это любой текст.

    Можете вставить хоть «Тут должна быть таблица»

    и в макете эта фраза должна присутствовать.

    А какой офис установлен?

    Reply
  54. pyrkin_vanya

    (53) я уж не совсем дурачок :). Я создал закладку на первой строке таблицы с названием ff. Офис 16 года. Не работает. Если честно, то метод слишком запутан. Я реализовал по-другому. Все чудесно работает. Но у меня четкое количество колонок. Хотя, думаю, если поковыряться то можно и произвольное сделать 🙂

     НомерТаблицы = 1;
    ТаблицаТоваров = Word.ActiveDocument.Tables(НомерТаблицы);
    Сч = 1;
    Для каждого ТекСтрока_Товар Из СсылкаНаДокумент.Товары Цикл
    Сч = Сч + 1;
    СтрокаТаблицы = ТаблицаТоваров.Rows.Add();
    
    // Номенклатура
    Word.Application.ActiveDocument.Tables(НомерТаблицы).Rows(Сч).Cells(1).Range.Text = Строка(ТекСтрока_Товар.Номенклатура);
    // ЕдИзм
    Word.Application.ActiveDocument.Tables(НомерТаблицы).Rows(Сч).Cells(2).Range.Text = Строка(ТекСтрока_Товар.Номенклатура.ЕдиницаИзмерения);
    // КолВо
    Word.Application.ActiveDocument.Tables(НомерТаблицы).Rows(Сч).Cells(3).Range.Text = Строка(Формат(ТекСтрока_Товар.КоличествоУпаковок, «ЧДЦ=; ЧГ=0»));
    // Цена
    Word.Application.ActiveDocument.Tables(НомерТаблицы).Rows(Сч).Cells(4).Range.Text = Строка(Формат(ТекСтрока_Товар.Цена, «ЧЦ=15; ЧДЦ=2»));
    // Сумма
    Word.Application.ActiveDocument.Tables(НомерТаблицы).Rows(Сч).Cells(5).Range.Text = Строка(Формат(ТекСтрока_Товар.Сумма, «ЧЦ=15; ЧДЦ=2»));
    
    // выделяем область яцеек с 1 по 5 для всех строк убираем шрифт «Жирный»
    Word.Application.ActiveDocument.Range(Word.Application.ActiveDocument.Tables(НомерТаблицы).Cell(Сч,1).Range.Start,Word.Application.ActiveDocument.Tables(НомерТаблицы).Cell(Сч,5).Range.End).Font.Bold = Ложь;
    
    // выделяем область яцеек с 1 по 1. Параметр варьируется от 0 до 3. (левый край, центр, правый край, по ширине  соответственно). Номенклатура
    Word.Application.ActiveDocument.Range(Word.Application.ActiveDocument.Tables(НомерТаблицы).Cell(Сч,1).Range.Start,Word.Application.ActiveDocument.Tables(НомерТаблицы).Cell(Сч,1).Range.End).ParagraphFormat.Alignment = 0;
    
    // выделяем область яцеек с 1 по 1. Параметр варьируется от 0 до 3. (левый край, центр, правый край, по ширине  соответственно). Номенклатура
    Word.Application.ActiveDocument.Range(Word.Application.ActiveDocument.Tables(НомерТаблицы).Cell(Сч,4).Range.Start,Word.Application.ActiveDocument.Tables(НомерТаблицы).Cell(Сч,5).Range.End).ParagraphFormat.Alignment = 2;
    КонецЦикла;
    

    Показать

    Reply
  55. pyrkin_vanya

    (54) Все оказалось куда проще. Достаточно прописать это для создания колонки

    КолонкаТаблицы = ТаблицаТоваров.Columns.Add();

    Я как 1С-ник не могу добавлять строку или колонку как процедуру. Машинально переменную пишу 🙂 Хотя можно и без нее.

    Reply
  56. endym

    (55) Возможно за 8 лет офис и обрел новые функции VBA, хотя не исключено что я мог это пропустить;)

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *