Учим БСП печатать активные ссылки и подложку в документе WORD

13.03.23

Разработка - БСП (Библиотека стандартных подсистем)

Небольшое расширение БСП для печати в WORD. Добавлена печать активных ссылок, подложки документа, и фона страницы.

Скачать файл

ВНИМАНИЕ: Файлы из Базы знаний - это исходный код разработки. Это примеры решения задач, шаблоны, заготовки, "строительные материалы" для учетной системы. Файлы ориентированы на специалистов 1С, которые могут разобраться в коде и оптимизировать программу для запуска в базе данных. Гарантии работоспособности нет. Возврата нет. Технической поддержки нет.

Наименование По подписке [?] Купить один файл
Учим БСП печатать активные ссылки и подложку в документе WORD:
.cfe 10,05Kb ver:1.0.1
5
5 Скачать (1 SM) Купить за 1 850 руб.

Стандартный функционал БСП при печати делает все гиперссылки неактивными, оставляя их оформление, а также теряет оформление страницы документа (фон и подложку). Данное расширение исправляет эти проблемы. Для чего это нужно, например для красивых прайсов, с последующим их преобразование в PDF и рассылки клиентам.

В расширении были модифицированы следующие общего модуля "УправлениеПечатьюСлужебный":

  • ОбработатьРазделДокумента()
  • РазбитьТекстШаблонаНаОбласти()
  • СобратьФайлДокументаDOCX()
  • ИнициализироватьСтруктуруПечатнойФормы()

 

Разберем доработки в порядке вызова их при печати.
При инициализации макета происходит вызов процедуры РазбитьТекстШаблонаНаОбласти() именно в ней теряется вся "магия" ссылок. Проблема в том, что БСП при разборе текста делит его на два типа "параграф" и все остальное. Научим ее понимать ссылки, комментариям с "{","}" обозначен доработанный код.

&Вместо("РазбитьТекстШаблонаНаОбласти")
Процедура Расш1_РазбитьТекстШаблонаНаОбласти(ЧтениеXML, СтруктураДокумента, ПараметрыАнализа)
	
	УровеньТэгаБлок       = -1;
	УровеньТэгаОбласть    = -1;
	УровеньАбзаца         = "0";
	ТекущийУровень        = 0;
	ПропуститьТэг         = Ложь;
	ТекстРаздела          = ""; 
    //{
	ЭтоСсылка		  = Ложь; // Флаг разбора ссылки
	текБлокРазбора		  = "";   // возможные значения "Блок", "АбзацХ", где Х - порядковый номер
	//}
	
	СтруктураРазбораXML = ИнициализироватьРазборXML();
	
	СброситьСтатусыТэгов1С(СтруктураРазбораXML);
	
	ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Заголовок", "");
		
	Если ПараметрыАнализа.ТипАнализа <> 1 Тогда
		ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Блок", "");
		УровеньТэгаБлок = 0;
	КонецЕсли;
	
	Пока ЧтениеXML.Прочитать() Цикл
		
...		
		Если ЧтениеНачалаРаздела(СтруктураРазбораXML, ЧтениеXML) Тогда
			СтруктураРазбораXML.БлокирующийПоток = "Раздел";
			ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Раздел", "", Ложь);
			ПеренестиОткрывающиеТэгиЗаписиВПоток(СтруктураРазбораXML, "Заголовок", "Раздел", "w:body");
		КонецЕсли;
		
		// начало разбора ссылки {
		Если ЧтениеНачалаБлокаСсылки(СтруктураРазбораXML, ЧтениеXML) Тогда
			ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Ссылка");   
			//ОстановитьЗаписьВПоток(СтруктураРазбораXML, "Абзац" + УровеньАбзаца);
						
			ОстановитьЗаписьВПоток(СтруктураРазбораXML, текБлокРазбора);
			ЭтоСсылка = Истина;
			
		КонецЕсли;  
		// }
		
		Если ЧтениеНачалаЛюбогоБлокаКромеПараграфа(СтруктураРазбораXML, ЧтениеXML) И ТекущийУровень = УровеньТэгаБлок Тогда
			ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Блок");   
			текБлокРазбора = "Блок";   // укажем текущий блок {}
		КонецЕсли;
		
		Если ЧтениеНачалаПараграфа(СтруктураРазбораXML, ЧтениеXML) Тогда
			УровеньАбзаца = Формат(Число(УровеньАбзаца) + 1, "ЧН=0; ЧГ=0");
			СтруктураРазбораXML.ТекущийУровеньАбзаца = УровеньАбзаца;
			
			СброситьСтатусыТэгов1С(СтруктураРазбораXML, Истина);
			ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Абзац" + УровеньАбзаца);
			ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "Строки" + УровеньАбзаца);
			ОстановитьЗаписьВПоток(СтруктураРазбораXML, "Строки" + УровеньАбзаца); 
			текБлокРазбора = "Абзац" + УровеньАбзаца;   // укажем текущий блок {}
		КонецЕсли;
		
...		
		// учтем флаг разбора ссылки {
		//Если ЧтениеНачалаСтроки(СтруктураРазбораXML, ЧтениеXML) Тогда
		Если ЧтениеНачалаСтроки(СтруктураРазбораXML, ЧтениеXML) И НЕ ЭтоСсылка Тогда
		// }			
			ВозобновитьЗаписьВПоток(СтруктураРазбораXML, "Строки" + УровеньАбзаца);
			ИнициализироватьЗаписьВПоток(СтруктураРазбораXML, "СтрокаПарам" + УровеньАбзаца);
			ОстановитьЗаписьВПоток(СтруктураРазбораXML, "Абзац" + УровеньАбзаца);
			СтруктураРазбораXML.ИмяПотокаФормата = "СтрокаПарам" + УровеньАбзаца;
		КонецЕсли;
		
...		
		// учтем флаг разбора ссылки {
		//Если ЧтениеКонцаСтроки(СтруктураРазбораXML, ЧтениеXML) Тогда
		Если ЧтениеКонцаСтроки(СтруктураРазбораXML, ЧтениеXML) И НЕ ЭтоСсылка Тогда
		// }	
			Если СтруктураРазбораXML.СтатусТэга1С = 0 И СтруктураРазбораXML.РазобранныеСтроки.Количество() = 0 Тогда
				ПеренестиЗаписьВПоток(СтруктураРазбораXML, "Строки" + УровеньАбзаца, "Абзац" + УровеньАбзаца);
			ИначеЕсли СтруктураРазбораXML.РазобранныеСтроки.Количество() > 0 Тогда
...
			КонецЕсли;
			
...
		КонецЕсли;
		
		Если ЧтениеКонцаПараграфа(СтруктураРазбораXML, ЧтениеXML) Тогда
...
		КонецЕсли;
		
		// завершение разбора ссылки {
		Если ЧтениеКонцаБлокаСсылки(СтруктураРазбораXML, ЧтениеXML) Тогда 
			
			Если текБлокРазбора = "" Тогда 
				текБлокРазбора = "Строки" + УровеньАбзаца;
			КонецЕсли;	
			
			ВозобновитьЗаписьВПоток(СтруктураРазбораXML, текБлокРазбора);
			ЗавершитьЗаписьВПоток(СтруктураРазбораXML, "Ссылка");
			ПеренестиЗаписьВПоток(СтруктураРазбораXML, "Ссылка", текБлокРазбора); 
			ЭтоСсылка = Ложь;
		КонецЕсли;	
		// }
		
...	
КонецПроцедуры
С помощью двух простых функций определяем начало и конец блока ссылки, листинг ниже:
Функция ЧтениеНачалаБлокаСсылки(СтруктураРазбораXML, ЧтениеXML)
	
	Если Не ПустаяСтрока(СтруктураРазбораXML.БлокирующийПоток) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Возврат ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И ЧтениеXML.Имя = "w:hyperlink";
	
КонецФункции

Функция ЧтениеКонцаБлокаСсылки(СтруктураРазбораXML, ЧтениеXML)
	
	Если Не ПустаяСтрока(СтруктураРазбораXML.БлокирующийПоток) Тогда
		Возврат Ложь;
	КонецЕсли;
	
	Возврат ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента И ЧтениеXML.Имя = "w:hyperlink";
	
КонецФункции

 

После инициализации макета, происходит инициализация печатной формы, в процессе которой данные макета копируются.

В процедуре ИнициализироватьСтруктуруПечатнойФормы() нужно закомментировать очистку текста колонтитулов получаемую из макета. Это нужно чтобы не потерять подложку страницы, т.к. она хранится в колонтитулах. БСП учитывает только те колонтитулы которые привязаны к разделам документа, а остальные безжалостно очищает.

 

&Вместо("ИнициализироватьСтруктуруПечатнойФормы")
Процедура Расш1_ИнициализироватьСтруктуруПечатнойФормы(ПечатнаяФорма, Макет)
	
	ИмяКаталога        = ПечатнаяФорма.ИмяКаталога;
	СтруктураДокумента = ПечатнаяФорма.СтруктураДокумента;
	
...
	
	Для Каждого Колонтитул Из Макет.СтруктураДокумента.Колонтитулы Цикл
		
		ДобавитьВСтруктуруДокументаКолонтитул(СтруктураДокумента, Колонтитул.Значение);
		СтруктураКолонтитула = СтруктураДокумента.Колонтитулы.Получить(Колонтитул.Ключ);
		////Если СтруктураКолонтитула <> Неопределено Тогда
		////	СтруктураКолонтитула.Текст = "";
		////КонецЕсли;
		
	КонецЦикла;
	
...

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

После того, как мы сформируем макет, и заполним его данными произойдет вызов функции СобратьФайлДокументаDOCX(). Внутри нее происходит формирование структуры документа. Здесь нужно заменить обработку колонтитулов из разделов документа на структуру. Так же здесь происходит вызов последней интересующей нас функции ОбработатьРазделДокумента()

&Вместо("СобратьФайлДокументаDOCX")
Функция Расш1_СобратьФайлДокументаDOCX(ПечатнаяФорма)
	
	ИзменяемыеФайлы = Новый Соответствие;
	ИзменяемыеФайлы.Вставить("СвязиКонтента", ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\word\_rels\document.xml.rels"));
	ИзменяемыеФайлы.Вставить("ТипыКонтента",  ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\[Content_Types].xml"));
	ИзменяемыеФайлы.Вставить("Документ",      ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\word\document.xml"));
	
	// обработка колонтитулов {

	КолонтитулВыведен = Новый Соответствие;
	Для Каждого ЭлементКолонтитула Из ПечатнаяФорма.СтруктураДокумента.Колонтитулы Цикл
		
		Колонтитул = ЭлементКолонтитула.Значение;
		
		ИмяФайла = ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\word\") + Колонтитул.ИмяВнутр + ".xml";
		Если ПустаяСтрока(Колонтитул.Текст) Тогда
			Продолжить;
		КонецЕсли;
		
		ЗаписьXML = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);
		ЗаписьXML.Записать(Колонтитул.Текст);
		ЗаписьXML.Закрыть();
		
		КолонтитулВыведен.Вставить(ЭлементКолонтитула.Ключ, ИСТИНА);
		
	КонецЦикла;
	
	////// Удаляем файлы пустых колонтитулов
	////КолонтитулВыведен = Новый Соответствие;
	////
	////Для Каждого Раздел Из ПечатнаяФорма.СтруктураДокумента.Разделы Цикл
	////	
	////	Для Каждого ЭлементКолонтитула Из Раздел.Значение.Колонтитулы Цикл
	////		
	////		Колонтитул = ЭлементКолонтитула.Значение;
	////		
	////		ИмяФайла = ПечатнаяФорма.ИмяКаталога + УстановитьРазделительПути("\word\") + Колонтитул.ИмяВнутр + ".xml";
	////		Если ПустаяСтрока(Колонтитул.Текст) Тогда
	////			Продолжить;
	////		КонецЕсли;
	////		
	////		ЗаписьXML = Новый ЗаписьТекста(ИмяФайла, КодировкаТекста.UTF8);
	////		ЗаписьXML.Записать(Колонтитул.Текст);
	////		ЗаписьXML.Закрыть();
	////		
	////		КолонтитулВыведен.Вставить(ЭлементКолонтитула.Ключ, ИСТИНА);
	////		
	////	КонецЦикла;
	////	
	////КонецЦикла;           

	// обработка колонтитулов }
	
...
	
	ПечатнаяФорма.СтруктураДокумента.ТипыКонтента = ЗаписьXML.Закрыть(); 
	
	// Формирование документа печатной формы
	
	ПорядковыйНомер = 1;
	
	ЗаписьXML = ИнициализироватьЗаписьXML("", ИзменяемыеФайлы.Получить("Документ"));
	
	НомерРаздела           = Неопределено;
	КоличествоОбластей     = ПечатнаяФорма.СтруктураДокумента.ПрисоединенныеОбласти.Количество();
	ИдентификаторДокумента = ПечатнаяФорма.СтруктураДокумента.ИдентификаторДокумента;
	
	Для Каждого Область Из ПечатнаяФорма.СтруктураДокумента.ПрисоединенныеОбласти Цикл
		
	...		
		Если ВывестиПромежуточныйРаздел = Истина И ЭтоПоследняяОбласть = Ложь Тогда
			
			РазделКВыводу = ПечатнаяФорма.СтруктураДокумента.Разделы.Получить(НомерРаздела);
			
			Если РазделКВыводу <> Неопределено Тогда
				
				ТекстРаздела = ОбработатьРазделДокумента(ПечатнаяФорма.СтруктураДокумента, РазделКВыводу);
				
	...				
			КонецЕсли;
			
		КонецЕсли;
		
	...
		
		// Запись заключительного раздела
		
		Если ЭтоПоследняяОбласть Тогда
			
			РазделКВыводу = ПечатнаяФорма.СтруктураДокумента.Разделы.Получить(Область.НомерРаздела);
			Если РазделКВыводу <> Неопределено Тогда
				ТекстРаздела = ОбработатьРазделДокумента(ПечатнаяФорма.СтруктураДокумента, РазделКВыводу);
				ЗаписьXML.ЗаписатьБезОбработки(ТекстРаздела);
			КонецЕсли;
			
		КонецЕсли;
		
		ПорядковыйНомер = ПорядковыйНомер + 1;
		НомерРаздела = Область.НомерРаздела;
		
	КонецЦикла;
	
	ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрытие тэга </w:body>
	ЗаписьXML.ЗаписатьКонецЭлемента(); // Закрытие тэга </w:document>
	
	ЗаписьXML.Закрыть();
	
	ПутьКДокументу = ПолучитьИмяВременногоФайла("DOCX");
	
	СобратьКонтейнерДокументаDOCX(ПутьКДокументу, ПечатнаяФорма.ИмяКаталога);
	
	Возврат ПутьКДокументу;

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

В этой функции нужно добавить пропуск обработки тэгов background. Формирование итогового документа происходит из xml-блоков, количество которых равно количеству областей добавленных в макете при выводе. А каждый такой блок представляет собой полноценный xml-документ, xml-заголовок которого формируется путем копирования заголовка макета. Сам тег background отвечающий за фон страницы располагается до секции body, и если его не удалять, то нарушается xml-структура получаемого документа.

&Вместо("ОбработатьРазделДокумента")
Функция Расш1_ОбработатьРазделДокумента(СтруктураДокумента, Раздел)
	
	ТипыКолонтитулов = ТипыКолонтитулов();
	
	ЧтениеXML = ИнициализироватьЧтениеXML(Раздел.Текст);
	ЗаписьXML = ИнициализироватьЗаписьXML("",,,Ложь);
	
	ПропуститьТэг = Ложь;
	Пока ЧтениеXML.Прочитать() Цикл
		
		Если ПропуститьТэг = Истина Тогда
			ПропуститьТэг = Ложь;
			Продолжить;
		КонецЕсли;
		
		Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И (ЧтениеXML.Имя = "w:document" ИЛИ ЧтениеXML.Имя = "w:body") Тогда
			Продолжить;
		КонецЕсли;

		// обработка цвета фона {
		Если ЧтениеXML.ТипУзла = ТипУзлаXML.НачалоЭлемента И (ЧтениеXML.Имя = "w:background") Тогда
			Продолжить;
		КонецЕсли;
		// }
		
...		
		Если ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента И (ЧтениеXML.Имя = "w:document" ИЛИ ЧтениеXML.Имя = "w:body") Тогда
			Продолжить;
		КонецЕсли;   
		
		// обработка цвета фона {
		Если ЧтениеXML.ТипУзла = ТипУзлаXML.КонецЭлемента И (ЧтениеXML.Имя = "w:background") Тогда
			Продолжить;
		КонецЕсли;
		// }
		
		ЗаписатьЭлементXML(ЧтениеXML, ЗаписьXML);
		
	КонецЦикла;
	
	ТекстРаздела = ЗаписьXML.Закрыть();
	
	Возврат ТекстРаздела;

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

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

PS. Не проверял работоспособность при использовании колонтитулов в макете.

Проверено на БСП 3.1.5.306.

См. также

БСП (Библиотека стандартных подсистем) Программист Платформа 1С v8.3 Бесплатно (free)

В статье описан алгоритм для включения документа или справочника в систему БСП. Будет полезно программистам 1С, начинающим работать с БСП.

24.10.2024    1078    PROSTO-1C    0    

12

БСП (Библиотека стандартных подсистем) Работа с интерфейсом Программист Платформа 1С v8.3 Бесплатно (free)

В материале описан универсальный механизм работы с добавленными элементами на общую форму «ФормаОтчета». Думаю, облегчит работу многим разработчикам.

08.10.2024    977    PROSTO-1C    4    

10

БСП (Библиотека стандартных подсистем) Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

В статье рассмотрим пошаговую инструкцию создания дополнительного отчета с фоновым формированием результата.

04.10.2024    1828    MadRave    11    

23

БСП (Библиотека стандартных подсистем) Программист Стажер Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Пример отслеживания прогресса фонового выполнения дополнительной обработки с использованием программного интерфейса длительных операций БСП.

10.09.2024    1815    MadRave    1    

17

БСП (Библиотека стандартных подсистем) Программист Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

А что, если долгожданная реализация Паузы в 1С смутно напоминает старую, проверенную? А?!

06.09.2024    1253    n_mezentsev    10    

8

БСП (Библиотека стандартных подсистем) Платформа 1С v8.3 Конфигурации 1cv8 Бесплатно (free)

Добавим дополнительные свойства в новый документ средствами БСП

02.09.2024    4103    John_d    10    

52

БСП (Библиотека стандартных подсистем) Программист Платформа 1С v8.3 Бесплатно (free)

Всё больше организаций выбирает для серверов под 1С операционные системы Linux. Одним из отличий систем Windows и Linux является отсутствие COM объектов, которые зачастую использовались для формирования печатных форм офисных документов (Word). Конечно, можно выполнять печать и на клиенте, но есть риск импортозамещения. В работе у меня случались проблемы с зависанием процесса Word, поэтому я не люблю его использовать.

29.07.2024    5353    PROSTO-1C    12    

52
Оставьте свое сообщение