Каталог решений - Этюды по программированию. Взаимодействие с Microsoft Word

Этюды по программированию. Взаимодействие с Microsoft Word

Этюды по программированию. Взаимодействие с Microsoft Word

В наличии

Часто приходится заниматься созданием сложных документов Word с таблицами, вложенными фрагментами, хитрым оформлением и прочими радостями жизни. Это — попытка как-то структурировать полученный опыт, чтобы не приходилось перерывать ворох старых обработок в поисках крупиц истины. Надеюсь, эта статья будет полезна и Вам.

Категория:

Описание

Этюды по программированию. Взаимодействие с Microsoft Word.

 

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

 

Получение шаблона.

В конфигурациях на основе БСП удобно хранить шаблон в справочнике ”Файлы”. Подсистема работы с присоединенными файлами позволяет назначить различные права на папки из этого справочника.

Файл можно найти по имени, или прикрепить  как дополнительный реквизит к справочникам и документам. (При создании дополнительного реквизита указать тип “Файл”).

Запрос = Новый Запрос;
	Запрос.Текст = 
	"ВЫБРАТЬ
	|	ДополнительныеСведения.Значение КАК Значение
	|ИЗ
	|	РегистрСведений.ДополнительныеСведения КАК ДополнительныеСведения
	|ГДЕ
	|	ДополнительныеСведения.Свойство.Наименование = &Наименование
	|	И ДополнительныеСведения.Объект = &Ссылка";
	
	Запрос.УстановитьПараметр("Ссылка", ДанныеПечати.Партнер);// Укажите ваш объект с прикрепленным дополнительным реквизитом шаблона.

	Запрос.УстановитьПараметр("Наименование", "Шаблон спецификации (Сделки с клиентами)"); //Укажите ваше название реквизита
	
	РезультатЗапроса = Запрос.Выполнить();
	
	ВыборкаДетальныеЗаписи = РезультатЗапроса.Выбрать();
	
	Если  ВыборкаДетальныеЗаписи.Следующий() Тогда
		Файл= ВыборкаДетальныеЗаписи.Значение;
		ДанныеФайлаИДвоичныеДанные = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИДвоичныеДанные(Файл);
		
		ДанныеФайла = ДанныеФайлаИДвоичныеДанные.ДанныеФайла;
		ДвоичныеДанные = ДанныеФайлаИДвоичныеДанные.ДвоичныеДанные;
		ИмяВременногоФайла = КаталогВременныхФайлов()+"макет.mxl";
		ДвоичныеДанные.Записать(ИмяВременногоФайла);
		Макет =Новый ТабличныйДокумент;
		Макет.Прочитать(ИмяВременногоФайла); 
		КонецЕсли;
	КонецЕсли;


Открытие объекта  документа из временного файла.

       Word = Новый COMОбъект("Word.Application");
                Попытка
                               док = Word.Documents.Open(ИмяВременногоФайла);
                               Док.SaveAs(ИмяВременногоФайла);
                Исключение
                               СообщениеОбОшибке = НСтр("Файл шаблона, указанный в константе, не найден: "+ИмяВременногоФайла+"
                                                              |Подробности:'")
                                                   + КраткоеПредставлениеОшибки(ИнформацияОбОшибке());
                               Word.Quit();
                               ВызватьИсключение СообщениеОбОшибке;
                КонецПопытки;
                РабочийКаталогПользователя = РаботаСФайламиСлужебныйКлиент.РабочийКаталогПользователя();
               
               
                Word.Visible = 1;
                Word.Options.CheckSpellingAsYouType = 0;
                Word.Options.CheckGrammarAsYouType =  0;
                Word.Options.CheckGrammarWithSpelling =  0;
                Selection = Word.Selection;

         Работа с таблицами по  макету таблицы:

          1. Макет таблицы. Создаем файл с шаблоном WORD. В файле должна быть таблица с шапкой, пустой строкой и (опционально) подвалом, например следующего вида:

    1. Поиск нужной таблицы в документе. Так как в документе обычно много таблиц, нужную таблицу нужно найти и заполнить
    Для Каждого Таб из док.Tables цикл
    Если СтрНайти(Таб.Cell(1, 1).Range.Text,"№")>0 И СтрНайти(Таб.Cell(1, 2).Range.Text,"Наименование")>0 Тогда
    //… Заполнение таблицы
           ТЗ= ПолучитьТЧТовары(Объект.СсылкаНаОбъект);
                           Таб.Rows(Таб.Rows.Count).Select();  //Выделям строку, на место которой будем вставлять новые строки
                           //Таб.Rows(1).Select(); 
                           Строка=Таб.Rows.Count;
                           Итерация=1;
                           Для Каждого стр Из ТЗ Цикл
                                           Если Итерация>1 Тогда
                                                          Selection.InsertRowsBelow( 1); //
                                           КонецЕсли;
                                           Таб.Cell(Строка, 1).Range.Text = стр.НомерСтроки;
                                           Таб.Cell(Строка, 2).Range.Text = стр.НоменклатураНаименование+" "+ТекстовоеОписаниеБезКомплектации(стр.ТекстовоеОписание);
                                           Таб.Cell(Строка, 2).Range.Paragraphs.Alignment = 0;
                                           текКол = ?(стр.Количество = 0,1,стр.Количество );
                                           Таб.Cell(Строка, 3).Range.Text =?((стр.ЦенаВключаетНДС), Формат((стр.Сумма - стр.СуммаНДС), "ЧДЦ=2"),Формат(стр.Сумма, "ЧДЦ=2"));
                                           Таб.Cell(Строка, 3).Range.Paragraphs.Alignment = 1;   
                                           Таб.Cell(Строка, 4).Range.Text =Формат(стр.СуммаНДС, "ЧДЦ=2");
                                           Таб.Cell(Строка, 4).Range.Paragraphs.Alignment = 1;   
                                           Таб.Cell(Строка, 5).Range.Text = ?((стр.ЦенаВключаетНДС), Формат((стр.Сумма ), "ЧДЦ=2"),Формат((стр.Сумма+ стр.СуммаНДС), "ЧДЦ=2"));
                                           Таб.Cell(Строка, 5).Range.Paragraphs.Alignment = 1;   
                                           Строка = Строка + 1;
                                          Итерация=Итерация+1;
                           КонецЦикла;
           КонецЦикла;
    

       Работа с таблицами 2. Вставляем невидимую таблицу по месту закладки:

  1.  

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

              

    	Если Док.Bookmarks.Exists("ТаблицаПродукции") Тогда
    		Поз = Док.GoTo(-1,,, "ТаблицаПродукции");
    		Колонок = 2;
    		Таб = Док.Tables.Add(Поз, 1, Колонок);
    		//Таб.Cell(1, 1).Range.Text = "Наименование";
    		//Таб.Cell(1, 2).Range.Text = "Кол-во";
    		//Таб.Cell(1, 3).Range.Text = "Ед.";
    		Таб.Range.Paragraphs.Alignment = 1;
    		Таб.Columns(1).Width=270;
    		Таб.Columns(2).Width=80;
    		Строка = 1;
    		Для Каждого стр Из ДанныеПоБП.НоменклатураБрак Цикл
    			Таб.Rows.Add();
    			Таб.Cell(Строка, 1).Range.Text = стр.Наименование;
    			Таб.Cell(Строка, 2).Range.Text =""+ стр.КоличествоБрака+"";
    			Таб.Cell(Строка, 2).Range.Paragraphs.Alignment = 0;
    			Строка = Строка + 1;
    		КонецЦикла;
    	КонецЕсли;

     

  2.  Работа с таблицами 3. Объединяем одинаковые значения в столбцах:

  3.  

    Пример для вывода такой таблицы: 

  4.  

     Стоимость:

     

    Материал, плотность

    Печать

    Лак

    Тираж, в тыс. шт.

    Количество печатных листов

    Стоимость одной тыс. шт., с НДС в руб.

    Нева 3201

    СМУК

    ВД глянц. выб.

    200

    1

    4407,97

    Нева 320

    ВД глянц. выб. 1

     

     

     

     

     

     

    СМУК2

    ВД глянц. выб.

     

     

     

  5. //...
    				ОбъединениеСтрокВКолонке(Таб, ТЗ,3,"Лак");
    				ОбъединениеСтрокВКолонке(Таб, ТЗ,2,"Печать");
    				ОбъединениеСтрокВКолонке(Таб, ТЗ,1,"МатериалПлотность");
    //...
    &НаКлиенте
    Процедура ОбъединениеСтрокВКолонке(Знач Таб, Знач ТЗ,НомерКолонки,ИмяКолонки)
    	
    	Перем Y, НачалоВертикальногоБлока, п1, СодержимоеЯчейки, СодержимоеЯчейкиПредыдущей, Х;
    	
    		СодержимоеЯчейкиПредыдущей="";
    		КоличествоСтрок=ТЗ.Количество();
    		НачалоВертикальногоБлока=КоличествоСтрок;
    		НачалоВертикальногоБлокаПредыдущее=КоличествоСтрок;
    
    		КоличествоИзменений=0;
    		Для Y =1 по КоличествоСтрок Цикл
    			YR= КоличествоСтрок-Y+1;
    			СодержимоеЯчейки=ТЗ[YR-1][ИмяКолонки];
    			ИзменениеСодержимого=Ложь;
    			Если СодержимоеЯчейки<> СодержимоеЯчейкиПредыдущей Тогда
    				КоличествоИзменений=КоличествоИзменений+1;
    				ИзменениеСодержимого=Истина;
    				СодержимоеЯчейкиПредыдущей=СодержимоеЯчейки;
    				НачалоВертикальногоБлокаПредыдущее=НачалоВертикальногоБлока;
    				НачалоВертикальногоБлока=YR;
    			КонецЕсли;
    			
    			Если ИзменениеСодержимого И НачалоВертикальногоБлокаПредыдущее-НачалоВертикальногоБлока>1  Тогда
    				п1=Таб.cell(НачалоВертикальногоБлокаПредыдущее+2, НомерКолонки);
    				Попытка // эта конструкция выдает исключительную ситуацию, но при этом
    					// результат все-равно работает))
    					// объединяем ячейки в конце таблицы
    					Таб.cell(НачалоВертикальногоБлока+3, НомерКолонки).Merge(п1);
    				Исключение
    				КонецПопытки;
    				Таб.cell(НачалоВертикальногоБлока+3, НомерКолонки).Range.Text=ТЗ[YR][ИмяКолонки];
    			ИначеЕсли YR=1 И  НачалоВертикальногоБлока-YR>=1 Тогда
    				п1=Таб.cell(YR+2, НомерКолонки);
    				Попытка // эта конструкция выдает исключительную ситуацию, но при этом
    					// результат все-равно работает))
    					// объединяем ячейки в конце таблицы
    					Таб.cell(НачалоВертикальногоБлока+2, НомерКолонки).Merge(п1);
    				Исключение
    				КонецПопытки;
    				п1.Range.Text=ТЗ[YR][ИмяКолонки];
    			КонецЕсли
    	   КонецЦикла;
    
    КонецПроцедуры
    

     

  6. Вставляем фрагмент из другого документа WORD:
  7. Обеспечиваем в нужном месте шаблона закладку.Процедура для вставки фрагмента:
    1. Процедура ВставитьПодшаблонИзСправочникаФайл(ИмяЗакладки,Word)
             Selection = Word.Selection;
             Для Каждого Закладка из Word.ActiveDocument.Bookmarks Цикл
                             Если Найти(Закладка.Name,ИмяЗакладки) Тогда
                                             Файл = НайтиФайлПодшаблонаНаСервере();
                                             Если ЗначениеЗаполнено(Файл) Тогда
                                                            ДанныеФайлаИДвоичныеДанные = РаботаСФайламиСлужебныйВызовСервера.ДанныеФайлаИДвоичныеДанные(Файл);
                                                            ДанныеФайла = ДанныеФайлаИДвоичныеДанные.ДанныеФайла;
                                                            ДвоичныеДанные = ДанныеФайлаИДвоичныеДанные.ДвоичныеДанные;
                                                            Попытка
                                                                            ИмяВременногоФайлаШаблона = КаталогВременныхФайлов()+"Шкафы КРУ сборка1.doc";
                                                                            ДвоичныеДанные.Записать(ИмяВременногоФайлаШаблона);
                                                            Исключение
                                                                            Попытка
                                                                                            ИмяВременногоФайлаШаблона = КаталогВременныхФайлов()+"Шкафы КРУ сборка2.doc";
                                                                                            ДвоичныеДанные.Записать(ИмяВременногоФайлаШаблона);
                                                                            Исключение
                                                                            КонецПопытки;
                                                            КонецПопытки;
                                                           
                                                           
                                                            Ворд2 = Новый COMОбъект("Word.Application");
                                                            Попытка
                                                                            док2 = Ворд2.Documents.Open(ИмяВременногоФайлаШаблона);
                                                                            НомерСтрокиТаб=3;
                                                                            Для Каждого Таб из док2.Tables цикл
                                                                            //заполняем таблицу        
                                                                            КонецЦикла;
                                                                           
                                                                            Ворд2.ActiveDocument.Select();
                                                                            Ворд2.Selection.Copy();
                                                                            Закладка.Range.Select();
                                                                            Selection.paste();
                                                                            Ворд2.ActiveDocument.Close(0);
                                                                            Ворд2.Quit();
                                                            Исключение
                                                                            ПредупреждениеСерв("Файл  не найден: "+ИмяВременногоФайлаШаблона);
                                                                            Ворд2.Quit();
                                                            КонецПопытки;
                                                            Попытка
                                                                            УдалитьФайлы(ИмяВременногоФайлаШаблона); 
                                                            Исключение
                                                                            ПредупреждениеСерв(ОписаниеОшибки());
                                                            КонецПопытки;
                                             КонецЕсли;
                             КонецЕсли;
             КонецЦикла;
      КонецПроцедуры

      Замена текста шаблона на нужный нам текст WORD:

      1. Предназначенный для замены текст шаблона ограничиваем квадратными скобками. Вместо текста пишем название маркера, по которому мы будем находить этот фрагмент.
      2.  В 1С создаем таблицу маркеров, которая будет содержать два обязательных поля “ Маркер” и “Значение”

Вызываем следующий код:

         Для Каждого стр Из Маркеры Цикл
                              Если ТипЗнч(стр.Значение) = Тип("Дата") Тогда
                                              Значение = СокрЛП(Формат(стр.Значение, "ДФ=""dd.MM.yyyy 'г.'"""));
                              Иначе
                                              Значение = СокрЛП(стр.Значение);
                              КонецЕсли;
                               док.content.find.execute("["+стр.Маркер+"]",,,,,,,,, Строка(Значение), 2);
                               док.Sections(1).Headers(1).Range.Find.Execute("["+стр.Маркер+"]",,,,,,,,, Строка(Значение), 2);
         КонецЦикла;
Вставка рисунка из макета:
  1. Создаем в конфигураторе макет-двоичные данные, в него загружаем нужный рисунок.
  2. Вызываем функцию, текст которой приведен ниже. В качестве аргумента selection удобно передавать выделение ячейки таблицы, это позволяет красиво расположить рисунок в тексте. Сама таблица может быть и невидимой. Например, следующий вызов:
 

///…

ВставитьМакет( Док,Таб.Cell(Строка, 3).Range, ИмяМакета);  

///…

&НаКлиенте

Функция ВставитьМакет( Знач Док,Знач Selection,Знач ИмяМакета)

               Перем Picture, Shape;

               Попытка

                               ИмяВременногоФайла= СохранитьМакетВоВременныйФайл(ИмяМакета);                            

                               Picture = Selection.InlineShapes.AddPicture(ИмяВременногоФайла,, Истина);

                               //Picture.LockAspectRatio = -1;      //сохрняем пропорции

                           Picture.Height= 150;

                               Picture.Width  = 150;              //устанавливаем ширину

                         // Чтобы установить обтекание текста, конвертируем рисунок в фигуру

                                  Shape = Picture.ConvertToShape();

                            Shape.WrapFormat.Type = 5;// перед текстом…

               Исключение

                               Сообщить("Не удалось подгрузить временный файл:"+ИмяВременногоФайла);

               КонецПопытки;

               Попытка

               УдалитьФайлы(ИмяВременногоФайла);

               Исключение

                               Сообщить("Не удалось удалить временный файл:"+ИмяВременногоФайла+"

                               |"+ОписаниеОшибки());

               КонецПопытки;

               // Зададим размер

               Возврат Selection;

КонецФункции

P.S.: Надеюсь, вам понравится эта и другие мои статьи и разработки на //infostart.ru/profile/48714/.

has been added to your cart:
Оформление заказа