Рейтинг:  5 / 5

Звезда активнаЗвезда активнаЗвезда активнаЗвезда активнаЗвезда активна
 

Добрый день.

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

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

Собственно Вы получите тут следующие навыки:

1. Вставка своих данных в шаблон через методы поиска и замены

2. Выделять произвольные области и копировать их

3. Выводить на печать табличные данные с произвольным количеством строк

 

ну что, погнали?

Первым делом, давайте договоримся: мы тут учимся и нам для понимания материала нужно отсеять шелуху. Так что, для обучения мы будем делать не печатную форму, а просто обработку с кнопкой, по нажатию на которую откроется документ MS Word. Еще мы не будем брать данные из БД, а будем писать в документ всякую фигню, строго зашитую в коде.

Для начала как и ранее создадим заготовку в MS Word. Предлагаю набросать документ как у меня на картинке:

1С Печать в MS Word подготовка шаблона

Учебная задача такова: вывести второй абзац N раз и каждый раз писать номер абзаца в конце, т.е. заполнять параметр разным значением. В таблице среднюю строку вывести M раз и, соответственно, заполнять её названием товара и количеством. На рисунке выше я красным отметил изменяемые данные.

Как я сказал Выше параметры мы будем делать не через DocVariable, а через свои теги. Тегом в нашем случае будет имя параметра окруженное кракозябрами. Кракозябры нужны для того, чтобы не перепутать имя параметра с реальным содержимым документа и не заменить его на значение параметра. В моем примере мы будем окружать имя параметра знаком "%".

Добавим в конец первого абзаца текст "%номерАбзаца%". По сути, это и есть вставка параметра в документ. Выглядит гораздо проще, чем добавление переменной документа.

В среднюю строку впишем слова "%тмц%" и "%количество%" в соответствующие колонки.

Вот что у нас получится:

1С печать в MS Word подготовка шаблона

Теперь подготовим документ для клонирования (дублирования, копирования, размножения...) его кусков. Для указания того, что мы хотим клонировать, мы будем использовать закладки. Нам их нужно две: одна для клонирования абзаца, другая для строки таблицы.

Создать закладку легко:

1. выделяем нужный врагмент

2. жмем "вставка"

3. жмем "закладки"

4. пишем имя закладки

5. жмем "добавить"

1С печать в word готовый шаблон через закладки и теги

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

Если в настроках MS Word указано отображение закладок, то текст обрамится квадратными скобками. Но по умолчанию закладки не видны, для этого делаем так:

Отображение скобок закладок

  1. Нажмите кнопку Microsoft Office Значок кнопки, а затем выберите пункт Параметры Word.
  1. Щелкните Дополнительно, а затем установите флажок Отображение закладок в области Отображение содержимого документа.
  2. Нажмите кнопку ОК.

Закладки, назначенные элементам, отображаются на экране в квадратных скобках ([…]). Закладка, назначенная позиции, имеет вид I-образного указателя.

Я назвал закладки "Абзац" и "строчка".

С документом покончено, теперь лезем в 1С в конфигуратор.

Создаем новую обработку.

Добавляем макет с двоичными данными и грузим туда наш шаблон.

Создаем основную форму.

Создаем два реквизита формы с типом "число": "ПовторыАбзаца" и "ПовторыТаблицы".

Тащим их на форму.

Создаем команду и тоже тащим её на форму.

Создаем клиентский обработчик команды Процедура Команда1()

Т.к. макет можно вытащить только на сервере, то пишем функцию, возвращающую макет:

&НаСервере
Функция ПолучитьМакетСервер()
Возврат РеквизитФормыВЗначение("Объект").ПолучитьМакет("Макет");
КонецФункции

Вызываем её.

Как и в предыдущей статье временный документ сохраняем на диск из макета:

Макет = ПолучитьМакетСервер();
временныйПуть = КаталогВременныхФайлов();
имяВременногоФайла = временныйПуть + "dog1s.doc";
Макет.Записать(имяВременногоФайла);

Создаем OLE объект для работы с MS Word:

Word = Новый COMОбъект("Word.Application");
ТекДок = Word.Documents.ADD(имяВременногоФайла);

И открываем наш шаблон.

теперь немного теории:

У OLE объекта Word есть свойство Selection, которое содержит объект, который позволяет выделять текст, копировать его и вставлять.

Сунем его в переменную:

селекция = Word.Selection;

У selection есть свойства start и end. Они указывают положение курсора в документе. Есть метод copy()/cut(), который копирует/вырезает то, что между start и end в буфер обмена. И есть метод paste(), который вставляет вместо текста между start и end содержимое буфера. Тип данный у start и end - число, это номер символа. Можно на этом и остановиться и подобрать их значения, но это не удобно, ведь мы отметили текст закладками и можем взять эти циферки оттуда.

Для обращения к закладкам у документа есть метод Bookmarks, который возвращает закладку, которая имеет свойства start и end.

Для замены наших тегов/кракозябр будем использовать метод Execute(...), у него много параметров, нам достаточно двух из них "что меняем", "на что меняем". этот метод доступен у свойства content у документа.

Теперь вооружившись всем выше сказанным пишем код, вот процедура вывода целиком:

&НаКлиенте

Процедура Команда1(Команда)
Word = Новый COMОбъект("Word.Application");
Макет = ПолучитьМакетСервер();
временныйПуть = КаталогВременныхФайлов();
имяВременногоФайла = временныйПуть + "dog1s.doc";
Макет.Записать(имяВременногоФайла);
ТекДок = Word.Documents.ADD(имяВременногоФайла);
селекция = Word.Selection;
//работаем с копированием абзацев
символНачалаАбзацаЭталона = ТекДок.Bookmarks("Абзац").Start;
селекция.Start = символНачалаАбзацаЭталона;
символКонцаАбзацаЭталона = ТекДок.Bookmarks("Абзац").End;
селекция.End = символКонцаАбзацаЭталона;
селекция.Cut();
Для ж=1 По ПовторыАбзаца Цикл
селекция.Start = символНачалаАбзацаЭталона;
селекция.End = символНачалаАбзацаЭталона;
селекция.Paste();
//заполняем параметр
ТекДок.Content.Find.Execute("%номерАбзаца%" ,,,,,,,,,СокрЛП(ПовторыАбзаца-ж+1),2);
КонецЦикла;
//работаем с копированием строки таблицы
символНачалаСтрокиЭталона = ТекДок.Bookmarks("строчка").Start;
селекция.Start = символНачалаСтрокиЭталона;
символКонцаСтрокиЭталона = ТекДок.Bookmarks("строчка").End;
селекция.End = символКонцаСтрокиЭталона;
селекция.Cut();
Для ж=1 По ПовторыТаблицы Цикл

селекция.Start = символНачалаСтрокиЭталона;
селекция.End = символНачалаСтрокиЭталона;
селекция.Paste();
//заполняем параметр
ТекДок.Content.Find.Execute("%тмц%" ,,,,,,,,, "ТМЦ ИМЯ №" + СокрЛП(ПовторыТаблицы-ж+1),2);
ТекДок.Content.Find.Execute("%количество%" ,,,,,,,,, "2 штук",2);
КонецЦикла;
//удали закладки из результата
ТекДок.Bookmarks("Абзац").Delete();
ТекДок.Bookmarks("строчка").Delete();
Word.Visible=Истина;
КонецПроцедуры

Пару комментариев по коду:

Сначала вырезаем образец из документа. Запоминаем в переменной позицию, где он был.

Помещаем курсор в сохраненную позицию.

Нужное число раз вставляем его в сохраненную ранее позицию.

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

Вывод нескольких абзацев ничем не отличается от вывода строк таблицы.

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

Собственно экспериментируйте, пробуйте. Удачи!

 

Вложения
ATTACH_DOWNLOAD_THIS_FILE_SПечатьВВорд2.epf[ ]17 kB

Авторизуйтесь пожалуйста

Комментарии   

+5 # Иван Клинцов 06.08.2014 06:56
Отличная статья. Автору огромная благодарность за бескорыстный труд!!
0 # CEKC_HA_TPABE 12.02.2015 13:17
Стоп! Ещё раз по порядку: создали два реквизита ПовторыАбзаца и ПовторыТаблицы, вытащили на форму, ок! Нажимаем на кнопку "Команда1", обработчик дошел до цикла ".. по ПовторыАбзаца Цикл". Разве этот реквизит, который никак не заполняли, не равен нулю?!
0 # Антон Филоненко 12.02.2015 14:25
Цитата:
Создаем два реквизита формы с типом "число": "ПовторыАбзаца" и "ПовторыТаблицы".
Тащим их на форму.
Таким образом эти переменные у нас определны и имею то значение, которое пользователь ввел в поля до нажатия кнопки.
0 # CEKC_HA_TPABE 13.02.2015 06:09
Немного странно будет, если при выводе печатной формы какого-либо документа пользователю дополнительно надо будет вводить какие-либо значения...
0 # Антон Филоненко 13.02.2015 08:22
Ну ясное дело:) в реальной печатно форме вы будите выводить столько строк, сколько надо, сколько вернет запрос и заполнять вы их будите не номерами строк, а реальными данными. Надо понимать, что это образец, и цикл тут такой, чтобы не привязываться к метаданным конфигурации, чтобы он в любой базе запустился
0 # CEKC_HA_TPABE 12.02.2015 13:22
Стоп ещё раз! :oops: ПовторыТаблицы можно получить по количеству строк в результате запроса и это количество присвоить в этот реквизит :lol: Статья супер, автор красавчик! ;-)