Дерево значений в таблицу значений или в табличную часть и обратно Для одной организации надо было реализовать документы, где вместо табличной части надо использовать дерево и все это на управляемых формах. Но дерево нельзя сохранить в базе в текущем виде. Пришлось использовать табличную часть документа для хранения данных дерева. И при открытии формы получать данные из ТЧ и выводить их в дерево. Далее все манипуляции производить с деревом и при сохранении документа помещать данные в обратно в ТЧ.
Поиск по интернету не дал нужного варианта, пришлось реализовавыть свой механизм, используя информацию которая была на просторах интернета.
Для реализации такого механизма в ТЧ был добавлен реквизит “КлючСвязи” (обязательный реквизит) с типом число, куда помещался “НомерСтроки” (стандартный реквизит ТЧ) родителя (верхний уровень). А самый верхний элемент дерева имеет “КлючСвязи” равный 0.
На картинке ниже видно структуру дерева и структуру ТЧ
Нагрузка на сервер осуществляется при окрытии и при сохранении документа. А с деревом работают уже на клиенте.
На рабочей базе обрабатывается около 200 строк в одном документе.
Открытие и сохранение документа происходит моментально. С большем количеством строк не тестировалось .
Чтобы алгорит правильно работал, у рекизита фомы с типом дерево значений должны быть все реквизиты табличной части, кроме “КлючСвязи” и “НомерСтроки”. Иначе платформа выдаст ошибку. В дерево можо добавлять свои реквизиты отличные от ТЧ, они будут использоваться только в дереве.
Ниже приведен код преобразования дерева в таблицу и обратно .
Код 1C v 8.2 УП &НаКлиенте
Процедура КомандаТаблицуВДерево(Команда)
КомандаТаблицуВДеревоНаСервере();
КонецПроцедуры
&НаСервере
Процедура КомандаТаблицуВДеревоНаСервере()
Дерево = ТаблицаВДерево(РеквизитФормыВЗначение("Объект"), "Товары");//Товары - имя табличной части
ЗначениеВРеквизитФормы(Дерево, "ДеревоЗначений");//ДеревоЗначений - реквизит формы с типом дерево значений
Элементы.ДеревоЗначений.Обновить();
КонецПроцедуры
&НаКлиенте
Процедура КомандаДеревоВТаблицу(Команда)
КомандаДеревоВТаблицуНаСервере();
КонецПроцедуры
&НаСервере
Процедура КомандаДеревоВТаблицуНаСервере()
Объект.Товары.Очистить();
ДОбъект = РеквизитФормыВЗначение("Объект");
ДеревоВТаблицу(ДОбъект, РеквизитФормыВЗначение("ДеревоЗначений"), "Товары");
ЗначениеВРеквизитФормы(ДОбъект, "Объект");
КонецПроцедуры
Формирование дерева из таблицы значений
Код 1C v 8.2 УП //ФОРМИРОВАНИЕ ДЕРЕВА ИЗ ТАБЛИЦЫ
&НаСервере
Функция ТаблицаВДерево(ДокОбъект, НаименованиеТабличнойЧастиДокумента, КлючСвязи = NULL, ЭлементРодитель = NULL) Экспорт
//ПОДГОТОВКА КОЛОНОК ДЕРЕВА
КолонкиТаблицы = ДокОбъект.Метаданные().ТабличныеЧасти[НаименованиеТабличнойЧастиДокумента].Реквизиты;
ДеревоЗначений2 = Новый ДеревоЗначений;
Для каждого Кол из КолонкиТаблицы Цикл
Если Кол.Имя = "НомерСтроки" ИЛИ Кол.Имя = "КлючСвязи" Тогда
Продолжить;
Иначе
ДеревоЗначений2.Колонки.Добавить(Кол.Имя, Новый ОписаниеТипов(Кол.Тип));
КонецЕсли;
КонецЦикла;//ДеревоЗначений.Строки.Очистить();
Если КлючСвязи = NULL И ЭлементРодитель = NULL Тогда
//ПЕРВЫЙ ВЫЗОВ ПРОЦЕДУРЫ (КОРНЕВЫЕ ЭЛЕМЕНТЫ)
ИсточникВыборки = ДеревоЗначений2.Строки;
КлючСвязи = 0; // ЭЛЕМЕНТ ВЕРХНЕГО УРОВНЯ ИМЕЕТ НОМЕР СТРОКИ РОДИТЕЛЯ 0 (ОБЯЗАТЕЛЬНЫЙ РЕКВИЗИТ)
Иначе
//ВНУТРЕННИЙ ВЫЗОВ ПРОЦЕДУРЫ (ПОДЧИНЕННЫЕ ЭЛЕМЕНТЫ)
ИсточникВыборки = ЭлементРодитель.Строки;
КонецЕсли;
Фильтр = Новый Структура("КлючСвязи", КлючСвязи);
М = ДокОбъект[НаименованиеТабличнойЧастиДокумента].НайтиСтроки(Фильтр);
Если М.Количество() = 0 Тогда
Возврат ДеревоЗначений2;
КонецЕсли;
Для каждого Стр из М Цикл
Элемент = ИсточникВыборки.Добавить();
Для каждого Кол из КолонкиТаблицы Цикл
Если Кол.Имя = "НомерСтроки" ИЛИ Кол.Имя = "КлючСвязи" Тогда
Продолжить;
Иначе
Элемент[Кол.Имя] = Стр[Кол.Имя];
КонецЕсли;
КонецЦикла;
ТаблицаВДерево(ДокОбъект, НаименованиеТабличнойЧастиДокумента, Стр.НомерСтроки, Элемент); //ДОБАВЛЕНИЕ ПОДЧИНЁННЫХ ЭЛЕМЕНТОВ В ДЕРЕВО
КонецЦикла;
Возврат ДеревоЗначений2;
КонецФункции
Формирование таблицы из дерева
Код 1C v 8.2 УП //ФОРМИРОВАНИЕ ТАБЛИЦЫ ИЗ ДЕРЕВА
&НаСервере
Процедура ДеревоВТаблицу(ДокОбъект, ДеревоЗначений, НаименованиеТабличнойЧастиДокумента, СтрокаДерева = NULL, КлючСвязи = NULL) Экспорт
Если СтрокаДерева = NULL И КлючСвязи = NULL Тогда
//ПЕРВЫЙ ВЫЗОВ ПРОЦЕДУРЫ (КОРНЕВЫЕ ЭЛЕМЕНТЫ)
ПервыйВызов = Истина;
ДокОбъект[НаименованиеТабличнойЧастиДокумента].Очистить();
ИсточникВыборки = ДеревоЗначений.Строки;
КлючСвязи = 0; // ЭЛЕМЕНТ ВЕРХНЕГО УРОВНЯ ИМЕЕТ НОМЕР СТРОКИ РОДИТЕЛЯ 0 (ОБЯЗАТЕЛЬНЫЙ РЕКВИЗИТ)
Иначе
//ВНУТРЕННИЙ ВЫЗОВ ПРОЦЕДУРЫ (ПОДЧИНЕННЫЕ ЭЛЕМЕНТЫ)
ПервыйВызов = Ложь;
ИсточникВыборки = СтрокаДерева.Строки;
КонецЕсли;
Для каждого Стр из ИсточникВыборки Цикл
НС = ДокОбъект[НаименованиеТабличнойЧастиДокумента].Добавить();
Для каждого Кол из ДокОбъект.Метаданные().ТабличныеЧасти[НаименованиеТабличнойЧастиДокумента].Реквизиты Цикл
Если Кол.Имя = "КлючСвязи" Тогда
НС.КлючСвязи = КлючСвязи
ИначеЕсли Кол.Имя = "НомерСтроки" Тогда
Продолжить;
Иначе
НС[Кол.Имя] = Стр[Кол.Имя];
КонецЕсли;
КонецЦикла;
Если НЕ Стр.Строки.Количество() = 0 Тогда
ДеревоВТаблицу(ДокОбъект,,НаименованиеТабличнойЧастиДокумента, Стр, НС.НомерСтроки);
КонецЕсли;
КонецЦикла;
КонецПроцедуры
Категория:
Работа с Деревом Значений Работа с MS Word через OLE В качестве примера использования можно указать вот такую ситуацию: в зависимости от типа клиента (договора, документа и т.п) формируются разные тексты договоров с разным количеством таблиц. В реальности, конечно должены использоваться и макет и описанные здесь динамические механизмы.
В моем примере я заранее создал новый пустой документ.
Тестировалось на Office 2007.
Код 1C v 8.х
// "ПутьКФайлу" - строка. Полное имя файла в формате MSWord.
// "Ссылка" - ДокументСсылка (в моем случае - счет).
Процедура ВыполнитьОбработку() Экспорт
Попытка
Объект = ПолучитьCOMОбъект(ПутьКФайлу);
// Покажем документ. Для красоты.
Объект.Application.Visible = 1;
Word = Объект.Application;
Doc = Объект.Application.Documents(1);
Doc.Activate();
// Готовим переменную в которой будет содержимое нашего документа
// (текст, таблицы и проч).
Text = Word.S_election;
// Очистим документ
// Ctrl-A
Text.WholeStory();
// Del
Text.Delete(1, 1);
// Двигаемся на 3 строки ниже. Документ пустой, поэтому добавляем
// строки "Переводами коретки"
Text.TypeText(Символы.ВК);
Text.TypeText(Символы.ВК);
Text.TypeParagraph(); // другой вариант того же действия
// Выводим текст.
Text.TypeText("Обычный текст, набранный первую очередь");
// Курсор в конце строки
// Эмулируем нажатие Shift+Home - выделяем строку
Text.HomeKey(, 1);
// Форматирование выделенной строки
Text.Font.Bold = 9999998;
Text.Font.Size = 14;
Text.Font.Name = "Verdana";
// Сдвигаем курсор. Сдвинуть курсор по строкам возможно, только,
// если эти строки уже содержат текст, иначе ничего не произойдет.
Text.MoveUp(,2); // вверх на 2 строки
//Word.S_election.MoveDown(,числострок); // вниз
//Word.S_election.MoveLeft(,числострок); // влево
//Word.S_election.MoveRight(,числострок);// вправо
// Добавление текста. Текст выводится начиная с текщей позиции
// курсора.
Text.HomeKey(, 1);
Text.TypeText("Обычный текст, набранный во вторую очередь");
Text.MoveDown(,1); // вниз на 2 строки
Text.EndKey(); // в конец строки
Text.TypeParagraph(); // и в начало следующей строки
// Очищаем форматирование
Text.ClearFormatting();
// Добавляем таблицу.
// Получаем текущую позицию курсора
Position = Text.Range();
// Параметры: Позиция, число строк, число колонок,
// последние 2 параметра отвечают за автоподбор высоты и отображение
// границ таблицы
Table = Doc.Tables.Add(Position, 1, 6, 1, 2);
// Устанавливаем ширину колонок
Table.Columns(1).PreferredWidth=10;
Table.Columns(2).PreferredWidth=50;
Table.Columns(3).PreferredWidth=10;
Table.Columns(4).PreferredWidth=10;
Table.Columns(5).PreferredWidth=10;
Table.Columns(6).PreferredWidth=10;
// Задаем заголовки колонок
Row1=Table.Rows(1);
Row1.Cells(1).Range.Text="№ п/п";
Row1.Cells(2).Range.Text="Наименование";
Row1.Cells(4).Range.Text="Кол-во";
Row1.Cells(3).Range.Text="Ед. изм.";
Row1.Cells(5).Range.Text="Цена,руб.";
Row1.Cells(6).Range.Text="Сумма,руб.";
// Построчно выводим содержимое таблицы Товары
НомерСтроки = 1;
Для каждого СтрокаТовары Из Ссылка.Товары Цикл
Row=Table.Rows.Add();
Row.Cells(1).Range.Text=НомерСтроки;
// Выравнивание по левому краю
Row.Cells(1).Range.ParagraphFormat.Alignment = 1;
// В качестве текста можно передать только значение "простого" формата
// все агрегатные объекты, переданные как текст, что нормально для платформы 1с
// вызовут исключение.
Row.Cells(2).Range.Text=СтрокаТовары.Номенклатура.Наименование
+?(ЗначениеЗаполнено(СтрокаТовары.ХарактеристикаНоменклатуры),
" ("+СтрокаТовары.ХарактеристикаНоменклатуры+")","");
Row.Cells(4).Range.Text=Строка(СтрокаТовары.Количество);
Row.Cells(4).Range.ParagraphFormat.Alignment = 1;
Row.Cells(3).Range.Text=?(ЗначениеЗаполнено(СтрокаТовары.Номенклатура.БазоваяЕдиницаИзмерения)
,СтрокаТовары.Номенклатура.БазоваяЕдиницаИзмерения.Наименование,"-");
Row.Cells(3).Range.ParagraphFormat.Alignment = 1;
Row.Cells(5).Range.Text=Формат(СтрокаТовары.Цена,"ЧДЦ=2");
Row.Cells(5).Range.ParagraphFormat.Alignment = 1;
Row.Cells(6).Range.Text=Формат(СтрокаТовары.Сумма,"ЧДЦ=2");
Row.Cells(6).Range.ParagraphFormat.Alignment = 1;
НомерСтроки=НомерСтроки+1;
КонецЦикла;
// Задаем форматирование первой строки
// Если сделать это сразу, то все новые строки таблицы будут
// формироваться с тем же форматом
Row1.Range.Font.Bold = 9999998;
Row1.Range.Font.Size = 14;
Row1.Range.Font.Name = "Verdana";
Row1.Range.ParagraphFormat.Alignment = 1;
// Последняя строка...
Row = Table.Rows.Add();
Row.Range.Font.Bold = 9999998;
Row.Cells(1).Range.Text="Итого:";
Исключение
Doc.Save();
Сообщить(ОписаниеОшибки());
Объект.Application.Quit();
Объект = Неопределено;
КонецПопытки;
Попытка // эта конструкция выдает исключительную ситуацию, но при этом
// результат все-равно работает))
// объединяем ячейки в конце таблицы
Table.cell(НомерСтроки+1, 1).Merge(Table.cell(НомерСтроки+1, 5));
Исключение
КонецПопытки;
Попытка
Row.Cells(1).Range.ParagraphFormat.Alignment = 3;
Row.Cells(2).Range.Text=Формат(Ссылка.Товары.Итог("Сумма"), "ЧДЦ=2");
Row.Cells(2).Range.ParagraphFormat.Alignment = 1;
Doc.Save();
Объект.Application.Quit();
Объект = Неопределено;
Исключение
Doc.Save();
Сообщить(ОписаниеОшибки());
Объект.Application.Quit();
Объект = Неопределено;
КонецПопытки;
КонецПроцедуры
Часто при создании документа из макета используют метод замены кусков текста. В примере представлен другой вариант выполнения того же действия - с использованием закладок. Также представлен пример построения нумерованного списка, вставки картинки, настройки ее параметров.
Пример использования описанных возможностей прост. При формировании коммерческого предложения бывает необходимо описать список условий, добавить изображение образца продукции.
Для отображения закладок включите эту опцию в настройках вашего Word'а.
В моем примере я заранее создал новый пустой документ, путь к документу и картинке прописан в тексте. Не забудте указать свои пути.
Код 1C v 8.х Процедура ВыполнитьОбработку() Экспорт
Попытка
//Объект = ПолучитьCOMОбъект(ПутьКФайлу);
Объект = ПолучитьCOMОбъект("C:\Users\NKrylov\Desktop\Тест.docx");
// Покажем документ.
Объект.Application.Visible = 1;
Word = Объект.Application;
ThisDocument = Word.Documents(1);
ThisDocument.Activate();
// Отключим проверку грамматики и вывод информации о грамматических ошибках.
ThisDocument.GrammarChecked=0;
ThisDocument.ShowGrammaticalErrors=0;
// Готовим переменную в которой будет содержимое документа (текст).
S_election = Word.S_election;
// Очистим документ
// Ctrl-A
S_election.WholeStory();
// Del
S_election.Delete(1, 1);
// Уменьшим междустрочный интервал.
S_election.ParagraphFormat.LineSpacingRule = 0; // 1 по умолчанию
S_election.ParagraphFormat.SpaceAfter = 0; // 10 по умолчанию
// Разметим документ. Это можно сделать и предварительно в макете
ThisDocument.Bookmarks.Add("Закладка1", S_election.Range());
S_election.TypeParagraph();
S_election.TypeText("34r3 ");
S_election.HomeKey(, 1);
ThisDocument.Bookmarks.Add("Закладка2", S_election.Range());
S_election.EndKey();
S_election.TypeParagraph();
ThisDocument.Bookmarks.Add("Закладка3", S_election.Range());
S_election.TypeParagraph();
ThisDocument.Bookmarks.Add("Закладка4", S_election.Range());
S_election.EndKey();
// Так можно работать с текстом только в конкреной области документа - это и будет замена метода Find-Execute.
ThisDocument.Bookmarks("Закладка3").Range.S_elect();
S_election = Word.S_election;
Bookmark = ThisDocument.Bookmarks("Закладка3");
Table = ThisDocument.Tables.Add(Bookmark.Range(),1,5,1,2);
Table.Rows(1).Cells(1).Range.Text = 1;
Table.Rows(1).Cells(2).Range.Text = 2;
Table.Rows(1).Cells(3).Range.Text = 3;
Table.Rows(1).Cells(4).Range.Text = 4;
Table.Rows(1).Cells(5).Range.Text = 5;
// После вывода таблицы, появится "лишняя строка", удалим ее
// в результате курсор встанет в область закладки 4
S_election.MoveDown(, 1);
S_election.Delete(1, 1);
// Этот текст будет выведен не с последней позиции курсора, а в активной области.
// в данном случае - в области закладки 2
ThisDocument.Bookmarks("Закладка2").Range.S_elect();
S_election = Word.S_election;
Text = S_election.Range.Text;
S_election.TypeText(Text + " sdcsdcs");
// При выводе текста закладка "сбросилась". Восстановим.
// "Победить" эту проблему я так и не смог((
// Хотя на практике, закладка больше и не понадобится.
// Дважды выводить текст в одну и ту же область - не имеет смысла.
S_election.HomeKey(, 1);
ThisDocument.Bookmarks.Add("Закладка2", S_election.Range());
S_election.EndKey();
// В области закладки 4 сформируем нумерованный список
ThisDocument.Bookmarks("Закладка4").Range.S_elect();
S_election = Word.S_election; // активная (выделенная) область будет начинаться
// от закладки 4)
// Добавим текст "для опытов"
// 1
S_election.TypeText("sdcsdcsdcsdc");
S_election.TypeParagraph();
// 2
S_election.TypeText("sdcsdcsdcsdc");
S_election.TypeParagraph();
// 3
S_election.TypeText("sdcsdcsdcsdc");
S_election.TypeParagraph();
// 4
S_election.TypeText("sdcsdcsdcsdc");
S_election.TypeParagraph();
// Выделяем введенный текст
S_election.MoveUp(,4,1);
// Настроим шаблон объекта галереи списков
// Галереи списков бывают несккольких типов, 2 - нумерованные списки
ListTemplate = Word.ListGalleries(2).ListTemplates(1).ListLevels(1);
// Формат нумератора списка - точка после символа нумерации
ListTemplate.NumberFormat = "%1.";
// стиль нумератора - арабские цифры
ListTemplate.NumberStyle = 0; // wdListNumberStyleArabic
// 4 - маленькие латинские буквы.
// 2 - маленькие римские цифры.
// 58- меленькие русские буквы.
// Font = Template.Font; // можно указать форматирование текста списка
// Применим шаблон к выделенному тексту
S_election.Range.ListFormat.ApplyListTemplateWithLevel( Word.ListGalleries(2).ListTemplates(1));
// Перейдем в конец текста
S_election.EndKey(6);
// Добавим картинку
// Параметры: путь к файлу, создавать ссылку на картинку, сохранять с файлом
Picture = S_election.InlineShapes.AddPicture("C:\Users\NKrylov\Desktop\Новый.bmp", Ложь, Истина);
// Зададим размер
Picture.Height = 100;
Picture.Width = 150;
// Чтобы установить обтекание текста, конвертируем рисунок в фигуру
Shape = Picture.ConvertToShape();
Shape.WrapFormat.Type = 0; // по контуру...
ThisDocument.Save();
//Объект.Application.Quit();
Объект = Неопределено;
Исключение
ThisDocument.Save();
Сообщить(ОписаниеОшибки());
//Объект.Application.Quit();
Объект = Неопределено;
КонецПопытки;
КонецПроцедуры
Автор:
Крылов Николай Категория:
Работа с Microsoft Office и OpenOffice Выгрузка в PDF из 1С (Средствами OpenOffice) Возникла задача отправлять счета почтой. PDFcreator не подошёл поскольку не удалось вместить счёт на одну страницу по ширине. Решил попробовать OpenOffice. Как сохранять в PDF нашёл быстро, а вот как уместить счёт на одну страницу вширь искал долго.
В версии 1С 8.2.232 появилась возможность сохранять табличный документ в xls файл на сервера под линуксом. А вот работать с Опеном офисом из-под линукса пока не получается. Собственно комментари ненужны. Вот весь код. Самое интересное это бодание со стилями страниц в Опене Офисе. Жаль что этот фрагмент работает только на клиенте. На сервере вопрос не решается *08
Код 1C v 8.2 УП Процедура КнопкаВыполнитьНажатие(Кнопка)
Если Письмо.Основание.Пустая() Тогда
Возврат
КонецЕсли;
// Открыть OpenOffice
Попытка
ServiceManager = Новый COMОбъект("com.sun.star.ServiceManager");
Исключение
Возврат // опен офис не установлен :-(
КонецПопытки;
// получим печатную форму и запишем её во временный XLS файл
Заказ = Письмо.Основание.ПолучитьОбъект();
//Получим печатную форму
Расшифровка=Новый Структура;
Расшифровка.Вставить("СсылкаНаВнешнююОбработку",Константы.ПФСчетаДляКлиента.Получить());
Расшифровка.Вставить("ВидПечатнойФормы",Перечисления.ВидыДополнительныхВнешнихОбработок.ПечатнаяФорма);
Расшифровка.Вставить("НомерСтроки",1);
тд = УниверсальныеМеханизмы.НапечататьВнешнююФорму(Заказ, Расшифровка);
ВременныйФайл =ПолучитьИмяВременногоФайла();
ВременныйФайлXLS =ВременныйФайл + ".xls";
ВременныйФайлPDF =ВременныйФайл + ".pdf";
тд.Записать(ВременныйФайлXLS, ТипФайлаТабличногоДокумента.XLS97);
// Преобразовываем временный xls файл В PDF
Desktop = ServiceManager.createInstance("com.sun.star.frame.Desktop");
НастройкиОткрытия = Новый COMSafeArray("VT_VARIANT", 1);
PropertyValue = ServiceManager.Bridge_GetStruct("com.sun.star.beans.PropertyValue");
PropertyValue.Name = "Hidden";
PropertyValue.Value = Истина;
НастройкиОткрытия.SetValue(0, PropertyValue);
ВременныйФайлXLS_какУРЛ = "file:///" + СтрЗаменить(ВременныйФайлXLS, "\", "/"); // приводим путь к файлу из виндового формата в опен офисный
// Откроем файл в опене офисе
ОпенОфис = Desktop.LoadComponentFromURL(ВременныйФайлXLS_какУРЛ, "_blank", 0, НастройкиОткрытия);
//ПараметрыСтраницы = ОпенОфис.createInstance("com.sun.star.style.PageStyle");
//ПараметрыСтраницы.ScaleToPagesX = 1;
//
// Установим масштаб, чтобы счёт помещался на одной странице вширь
// страниц почему-то много, поэтому устанавливаем масштаб для всех
Стили = ОпенОфис.StyleFamilies.getByName("PageStyles");
Для поз = 0 по Стили.count - 1 Цикл
МойСтиль = Стили.getByIndex(поз);
МойСтиль.ScaleToPagesX = 1; // уместить на одной странице вширь
//МойСтиль.PageScale = 50; // масштаб 50%
КонецЦикла;
НастройкиСохранения = Новый COMSafeArray("VT_VARIANT", 1);
PropertyValue = ServiceManager.Bridge_GetStruct("com.sun.star.beans.PropertyValue");
PropertyValue.Name = "FilterName";
PropertyValue.Value = "calc_pdf_Export";
НастройкиСохранения.SetValue(0, PropertyValue);
ВременныйФайлPDF_какУРЛ = "file:///" + СтрЗаменить(ВременныйФайлPDF, "\", "/"); // приводим путь к файлу из виндового формата в опен офисный
ОпенОфис.storeToURL(ВременныйФайлPDF_какУРЛ, НастройкиСохранения); // сохранили PDF файл
ОпенОфис.close(-1);
ОпенОфис = Неопределено;
// С опеном офисом разобрались. Прикрепляем вложение к письму и удаляем временные файлы.
//Файл = Новый Файл(ВременныйФайлPDF);
объектПисьмо = Письмо.ПолучитьОбъект();
стрВложение = объектПисьмо.Вложения.Добавить();
стрВложение.ИмяФайла = "Счёт " + Строка(Заказ.Номер) + ".pdf";
стрВложение.Файл = Новый ХранилищеЗначения(Новый ДвоичныеДанные(ВременныйФайлPDF));
объектПисьмо.Записать();
Попытка
УдалитьФайлы(ВременныйФайлXLS);
УдалитьФайлы(ВременныйФайлPDF);
Исключение
КонецПопытки;
КонецПроцедуры
Автор:
Трактор
Функция позволяющая выполнить выгрузку табличного документа в PDF средствами OpenOffice
Код 1C v 8.х // Функция превращает табличный документ в PDF документ
// Возвращаемое значение: тип "Строка" - имя созданного PDF файла, 0 - в случае ошибки
// Параметры: ДанныеВыгрузки - Табличный или текстовый документ, который нужно выгрузить в PDF
// ПутьВыгрузки - тип "Строка", путь для сохраниения PDF файла (без имени и расширения файла)
// ИмяФайлаБезРасширения - тип "Строка", имя для вновь сформированного PDF файла
// Тестировалось на OpenOffice 3.x
Функция ВыгрузитьТабличныйДокументВPDF(ДанныеВыгрузки, ПутьВыгрузки, ИмяФайлаБезРасширения)
Если НЕ ЗначениеЗаполнено(ПутьВыгрузки) Тогда
ПутьВыгрузки = КаталогВременныхФайлов();
КонецЕсли;
ПутьВыгрузки = ?(Прав(ПутьВыгрузки, 1) = "\", ПутьВыгрузки, ПутьВыгрузки + "\");
РасширениеXSL = ".xls";
РасширениеPDF = ".pdf";
ПолноеИмяФайлаXLS = ПутьВыгрузки + ИмяФайлаБезРасширения + РасширениеXSL;
//Выгрузка данных печати в файл XLS
#Если Клиент Тогда
Состояние("Создание временного файла...");
#КонецЕсли
Попытка
Если ТипЗнч(ДанныеВыгрузки) = Тип("ТабличныйДокумент") Тогда
ДанныеВыгрузки.Записать(ПолноеИмяФайлаXLS, "XLS");
ИначеЕсли ТипЗнч(ДанныеВыгрузки) = Тип("ТекстовыйДокумент") Тогда
ДанныеВыгрузки.Записать(ПолноеИмяФайлаXLS, "XLS");
Иначе
#Если Клиент Тогда
Сообщить("Данные для выгрузки переданы в неподдерживаемом формате. Дальнейшее выполнение невозможно." + Символы.ПС + ОписаниеОшибки());
#КонецЕсли
Возврат 0;
КонецЕсли;
Исключение
#Если Клиент Тогда
Сообщить("Произошла ошибка при выгрузке временного файла. Возможно ошибка доступа к папке, в которую происходит запись." + Символы.ПС + ОписаниеОшибки());
#КонецЕсли
Возврат 0;
КонецПопытки;
Попытка
#Если Клиент Тогда
Состояние("Открытие компоненты OpenOffice...");
#КонецЕсли
ServiceManager = Новый COMОбъект("com.sun.star.ServiceManager");
Скрипт = Новый COMОбъект("MSScriptControl.ScriptControl");
Скрипт.language = "javascript";
Скрипт.AddObject("OpenOffice", ServiceManager);
//Открытие временного файла без отображения его окна
#Если Клиент Тогда
Состояние("Открытие временного файла...");
#КонецЕсли
Скрипт.eval("Массив=new Array()");
Массив = Скрипт.eval("Массив");
Скрипт.eval("Массив[0] = OpenOffice.Bridge_GetStruct('com.sun.star.beans.PropertyValue')");
Скрипт.eval("Массив[0].Name = 'Hidden'");
Скрипт.eval("Массив[0].Value = true");
Скрипт.AddCode("function SetItem(ind,val){Массив[ind]=val}");
Скрипт.AddObject("ServiceManager",ServiceManager);
Desktop = ServiceManager.createInstance("com.sun.star.frame.Desktop");
Document = Desktop.LoadComponentFromURL("file:///" + ПолноеИмяФайлаXLS, "_blank", 0, Массив);
//Сохранение в PDF встроенными средствами OpenOffice
#Если Клиент Тогда
Состояние("Запись в PDF...");
#КонецЕсли
Скрипт.eval("Массив2=new Array()");
Массив2 = Скрипт.eval("Массив2");
Скрипт.eval("Массив2[0] = OpenOffice.Bridge_GetStruct('com.sun.star.beans.PropertyValue')");
Скрипт.eval("Массив2[0].Name = 'FilterName'");
Скрипт.eval("Массив2[0].Value = 'writer_pdf_Export'");
ПолноеИмяФайлаPDF = "file:///" + СтрЗаменить(ПолноеИмяФайлаXLS, РасширениеXSL, РасширениеPDF);
ПолноеИмяФайлаPDF = СтрЗаменить(ПолноеИмяФайлаPDF, ВРег(РасширениеXSL), РасширениеPDF);
ПолноеИмяФайлаPDF = СтрЗаменить(ПолноеИмяФайлаPDF, "\", "/");
Document.storeToURL(ПолноеИмяФайлаPDF, Массив2);
Document.close(-1); //Закрыть документ
//Контрольная очистка переменных
Document = Неопределено;
Desktop = Неопределено;
//Удаление временного файла
#Если Клиент Тогда
Состояние("Удаление временного файла...");
#КонецЕсли
Попытка
УдалитьФайлы(ПолноеИмяФайлаXLS);
Исключение
#Если Клиент Тогда
Сообщить("Произошла ошибка при удалении временного файла. Возможно, потребуется удалить его вручную." + Символы.ПС + ОписаниеОшибки());
#КонецЕсли
КонецПопытки;
ПолноеИмяФайлаPDF = СтрЗаменить(ПолноеИмяФайлаPDF, "file:///", "");
ПолноеИмяФайлаPDF = СтрЗаменить(ПолноеИмяФайлаPDF, "/", "\");
#Если Клиент Тогда
Состояние("Выгрузка выполнена.");
Предупреждение("Выгрузка выполнена." + Символы.ПС + ПолноеИмяФайлаPDF);
#КонецЕсли
Возврат ПолноеИмяФайлаPDF;
Исключение
Document.close(-1);
#Если Клиент Тогда
Предупреждение(ОписаниеОшибки());
#КонецЕсли
Возврат 0;
КонецПопытки
КонецФункции
Автор:
doom_2001 Категория:
Работа с Microsoft Office и OpenOffice Пример построения в Word нумерованного списка, закладок, вставки картинки, настройки ее параметров. Часто при создании документа из макета используют метод замены кусков текста. В примере представлен другой вариант выполнения того же действия - с использованием закладок. Также представлен пример построения нумерованного списка, вставки картинки, настройки ее параметров.
Пример использования описанных возможностей прост. При формировании коммерческого предложения бывает необходимо описать список условий, добавить изображение образца продукции.
Для отображения закладок включите эту опцию в настройках вашего Word'а.
В моем примере я заранее создал новый пустой документ, путь к документу и картинке прописан в тексте. Не забудьте указать свои пути.
Тестировалось на Office 2007.
Некоторые переменные переименованы по стандарту Office: Text --> S_election. Doc --> ThisDocument.
Вот текст модуля:
Код 1C v 8.х Процедура ВыполнитьОбработку() Экспорт
Попытка
//Объект = ПолучитьCOMОбъект(ПутьКФайлу);
Объект = ПолучитьCOMОбъект("C:\Users\NKrylov\Desktop\Тест.docx");
// Покажем документ.
Объект.Application.Visible = 1;
Word = Объект.Application;
ThisDocument = Word.Documents(1);
ThisDocument.Activate();
// Отключим проверку грамматики и вывод информации о грамматических ошибках.
ThisDocument.GrammarChecked=0;
ThisDocument.ShowGrammaticalErrors=0;
// Готовим переменную в которой будет содержимое документа (текст).
S_election = Word.S_election;
// Очистим документ
// Ctrl-A
S_election.WholeStory();
// Del
S_election.Delete(1, 1);
// Уменьшим междустрочный интервал.
S_election.ParagraphFormat.LineSpacingRule = 0; // 1 по умолчанию
S_election.ParagraphFormat.SpaceAfter = 0; // 10 по умолчанию
// Разметим документ. Это можно сделать и предварительно в макете
ThisDocument.Bookmarks.Add("Закладка1", S_election.Range());
S_election.TypeParagraph();
S_election.TypeText("34r3 ");
S_election.HomeKey(, 1);
ThisDocument.Bookmarks.Add("Закладка2", S_election.Range());
S_election.EndKey();
S_election.TypeParagraph();
ThisDocument.Bookmarks.Add("Закладка3", S_election.Range());
S_election.TypeParagraph();
ThisDocument.Bookmarks.Add("Закладка4", S_election.Range());
S_election.EndKey();
// Так можно работать с текстом только в конкреной области документа - это и будет замена метода Find-Execute.
ThisDocument.Bookmarks("Закладка3").Range.S_elect();
S_election = Word.S_election;
Bookmark = ThisDocument.Bookmarks("Закладка3");
Table = ThisDocument.Tables.Add(Bookmark.Range(),1,5,1,2);
Table.Rows(1).Cells(1).Range.Text = 1;
Table.Rows(1).Cells(2).Range.Text = 2;
Table.Rows(1).Cells(3).Range.Text = 3;
Table.Rows(1).Cells(4).Range.Text = 4;
Table.Rows(1).Cells(5).Range.Text = 5;
// После вывода таблицы, появится "лишняя строка", удалим ее
// в результате курсор встанет в область закладки 4
S_election.MoveDown(, 1);
S_election.Delete(1, 1);
// Этот текст будет выведен не с последней позиции курсора, а в активной области.
// в данном случае - в области закладки 2
ThisDocument.Bookmarks("Закладка2").Range.S_elect();
S_election = Word.S_election;
Text = S_election.Range.Text;
S_election.TypeText(Text + " sdcsdcs");
// При выводе текста закладка "сбросилась". Восстановим.
// "Победить" эту проблему я так и не смог((
// Хотя на практике, закладка больше и не понадобится.
// Дважды выводить текст в одну и ту же область - не имеет смысла.
S_election.HomeKey(, 1);
ThisDocument.Bookmarks.Add("Закладка2", S_election.Range());
S_election.EndKey();
// В области закладки 4 сформируем нумерованный список
ThisDocument.Bookmarks("Закладка4").Range.S_elect();
S_election = Word.S_election; // активная (выделенная) область будет начинаться
// от закладки 4)
// Добавим текст "для опытов"
// 1
S_election.TypeText("sdcsdcsdcsdc");
S_election.TypeParagraph();
// 2
S_election.TypeText("sdcsdcsdcsdc");
S_election.TypeParagraph();
// 3
S_election.TypeText("sdcsdcsdcsdc");
S_election.TypeParagraph();
// 4
S_election.TypeText("sdcsdcsdcsdc");
S_election.TypeParagraph();
// Выделяем введенный текст
S_election.MoveUp(,4,1);
// Настроим шаблон объекта галереи списков
// Галереи списков бывают несккольких типов, 2 - нумерованные списки
ListTemplate = Word.ListGalleries(2).ListTemplates(1).ListLevels(1);
// Формат нумератора списка - точка после символа нумерации
ListTemplate.NumberFormat = "%1.";
// стиль нумератора - арабские цифры
ListTemplate.NumberStyle = 0; // wdListNumberStyleArabic
// 4 - маленькие латинские буквы.
// 2 - маленькие римские цифры.
// 58- меленькие русские буквы.
// Font = Template.Font; // можно указать форматирование текста списка
// Применим шаблон к выделенному тексту
S_election.Range.ListFormat.ApplyListTemplateWithLevel( Word.ListGalleries(2).ListTemplates(1));
// Перейдем в конец текста
S_election.EndKey(6);
// Добавим картинку
// Параметры: путь к файлу, создавать ссылку на картинку, сохранять с файлом
Picture = S_election.InlineShapes.AddPicture("C:\Users\NKrylov\Desktop\Новый.bmp", Ложь, Истина);
// Зададим размер
Picture.Height = 100;
Picture.Width = 150;
// Чтобы установить обтекание текста, конвертируем рисунок в фигуру
Shape = Picture.ConvertToShape();
Shape.WrapFormat.Type = 0; // по контуру...
ThisDocument.Save();
//Объект.Application.Quit();
Объект = Неопределено;
Исключение
ThisDocument.Save();
Сообщить(ОписаниеОшибки());
//Объект.Application.Quit();
Объект = Неопределено;
КонецПопытки;
КонецПроцедуры
Написал Nikola23 - http://infostart.ru/public/68072/ Категория:
Работа с Microsoft Office и OpenOffice Создание документа Word без использования макетов и пример создания таблицы и её оформление. Кроме прочего в статье присутствует пример создания таблицы с любым количеством колонок и столбцов. Несколько строк с форматированием текста и таблицы. Создание "объединенных" ячеек.
В качестве примера использования можно указать вот такую ситуацию: в зависимости от типа клиента (договора, документа и т.п) формируются разные тексты договоров с разным количеством таблиц. В реальности, конечно должены использоваться и макет и описанные здесь динамические механизмы.
В моем примере я заранее создал новый пустой документ.
Тестировалось на Office 2007.
Исп. переменные: "ПутьКФайлу" - строка. Полное имя файла в формате MSWord.
"Ссылка" - ДокументСсылка (в моем случае - счет).
Вот текст модуля:
Код 1C v 8.х Процедура ВыполнитьОбработку() Экспорт
Попытка
Объект = ПолучитьCOMОбъект(ПутьКФайлу);
// Покажем документ. Для красоты.
Объект.Application.Visible = 1;
Word = Объект.Application;
Doc = Объект.Application.Documents(1);
Doc.Activate();
// Готовим переменную в которой будет содержимое нашего документа
// (текст, таблицы и проч).
Text = Word.S_election;
// Очистим документ
// Ctrl-A
Text.WholeStory();
// Del
Text.Delete(1, 1);
// Двигаемся на 3 строки ниже. Документ пустой, поэтому добавляем
// строки "Переводами коретки"
Text.TypeText(Символы.ВК);
Text.TypeText(Символы.ВК);
Text.TypeParagraph(); // другой вариант того же действия
// Выводим текст.
Text.TypeText("Обычный текст, набранный первую очередь");
// Курсор в конце строки
// Эмулируем нажатие Shift+Home - выделяем строку
Text.HomeKey(, 1);
// Форматирование выделенной строки
Text.Font.Bold = 9999998;
Text.Font.Size = 14;
Text.Font.Name = "Verdana";
// Сдвигаем курсор. Сдвинуть курсор по строкам возможно, только,
// если эти строки уже содержат текст, иначе ничего не произойдет.
Text.MoveUp(,2); // вверх на 2 строки
//Word.S_election.MoveDown(,числострок); // вниз
//Word.S_election.MoveLeft(,числострок); // влево
//Word.S_election.MoveRight(,числострок);// вправо
// Добавление текста. Текст выводится начиная с текщей позиции
// курсора.
Text.HomeKey(, 1);
Text.TypeText("Обычный текст, набранный во вторую очередь");
Text.MoveDown(,1); // вниз на 2 строки
Text.EndKey(); // в конец строки
Text.TypeParagraph(); // и в начало следующей строки
// Очищаем форматирование
Text.ClearFormatting();
// Добавляем таблицу.
// Получаем текущую позицию курсора
Position = Text.Range();
// Параметры: Позиция, число строк, число колонок,
// последние 2 параметра отвечают за автоподбор высоты и отображение
// границ таблицы
Table = Doc.Tables.Add(Position, 1, 6, 1, 2);
// Устанавливаем ширину колонок
Table.Columns(1).PreferredWidth=10;
Table.Columns(2).PreferredWidth=50;
Table.Columns(3).PreferredWidth=10;
Table.Columns(4).PreferredWidth=10;
Table.Columns(5).PreferredWidth=10;
Table.Columns(6).PreferredWidth=10;
// Задаем заголовки колонок
Row1=Table.Rows(1);
Row1.Cells(1).Range.Text="№ п/п";
Row1.Cells(2).Range.Text="Наименование";
Row1.Cells(4).Range.Text="Кол-во";
Row1.Cells(3).Range.Text="Ед. изм.";
Row1.Cells(5).Range.Text="Цена,руб.";
Row1.Cells(6).Range.Text="Сумма,руб.";
// Построчно выводим содержимое таблицы Товары
НомерСтроки = 1;
Для каждого СтрокаТовары Из Ссылка.Товары Цикл
Row=Table.Rows.Add();
Row.Cells(1).Range.Text=НомерСтроки;
// Выравнивание по левому краю
Row.Cells(1).Range.ParagraphFormat.Alignment = 1;
// В качестве текста можно передать только значение "простого" формата
// все агрегатные объекты, переданные как текст, что нормально для платформы 1с
// вызовут исключение.
Row.Cells(2).Range.Text=СтрокаТовары.Номенклатура.Наименование
+?(ЗначениеЗаполнено(СтрокаТовары.ХарактеристикаНоменклатуры),
" ("+СтрокаТовары.ХарактеристикаНоменклатуры+")","");
Row.Cells(4).Range.Text=Строка(СтрокаТовары.Количество);
Row.Cells(4).Range.ParagraphFormat.Alignment = 1;
Row.Cells(3).Range.Text=?(ЗначениеЗаполнено(СтрокаТовары.Номенклатура.БазоваяЕдиницаИзмерения)
,СтрокаТовары.Номенклатура.БазоваяЕдиницаИзмерения.Наименование,"-");
Row.Cells(3).Range.ParagraphFormat.Alignment = 1;
Row.Cells(5).Range.Text=Формат(СтрокаТовары.Цена,"ЧДЦ=2");
Row.Cells(5).Range.ParagraphFormat.Alignment = 1;
Row.Cells(6).Range.Text=Формат(СтрокаТовары.Сумма,"ЧДЦ=2");
Row.Cells(6).Range.ParagraphFormat.Alignment = 1;
НомерСтроки=НомерСтроки+1;
КонецЦикла;
// Задаем форматирование первой строки
// Если сделать это сразу, то все новые строки таблицы будут
// формироваться с тем же форматом
Row1.Range.Font.Bold = 9999998;
Row1.Range.Font.Size = 14;
Row1.Range.Font.Name = "Verdana";
Row1.Range.ParagraphFormat.Alignment = 1;
// Последняя строка...
Row = Table.Rows.Add();
Row.Range.Font.Bold = 9999998;
Row.Cells(1).Range.Text="Итого:";
Исключение
Doc.Save();
Сообщить(ОписаниеОшибки());
Объект.Application.Quit();
Объект = Неопределено;
КонецПопытки;
Попытка // эта конструкция выдает исключительную ситуацию, но при этом
// результат все-равно работает))
// объединяем ячейки в конце таблицы
Table.cell(НомерСтроки+1, 1).Merge(Table.cell(НомерСтроки+1, 5));
Исключение
КонецПопытки;
Попытка
Row.Cells(1).Range.ParagraphFormat.Alignment = 3;
Row.Cells(2).Range.Text=Формат(Ссылка.Товары.Итог("Сумма"), "ЧДЦ=2");
Row.Cells(2).Range.ParagraphFormat.Alignment = 1;
Doc.Save();
Объект.Application.Quit();
Объект = Неопределено;
Исключение
Doc.Save();
Сообщить(ОписаниеОшибки());
Объект.Application.Quit();
Объект = Неопределено;
КонецПопытки;
КонецПроцедуры
Написал Nikola23 - http://infostart.ru/public/67727/ Категория:
Работа с Microsoft Office и OpenOffice