Решение проблемы ПроверитьВывод() для огромных документов

Печать - Печатные формы документов

46
Пример того, как я ускорил вывод большого табличного документа(100+ страниц)

Каких результатов удалось достичь

Изначально, печатная форма, содержащая ~200 страниц выводилась(речь идет об именно выводе в табличный документ) > 15 минут. В результате оптимизации удалось сократить время до 1-2 минут.

Последовательность действий:

  1. Объявляем ТабличныйДокумент как ранее, настраиваем его свойства(Масштаб, ориентация страницы, поля);
  2. Объявляем еще один табличный документ, назовем его ИтоговыйТабличныйДокумент, копируем в него все свойства ранее созданного;
  3. Выполняем вывод одной страницы в ТабличныйДокумент, проверяем, умещается ли он или нет с помощью метода ПроверитьВывод()
  4. Когда вывод не умещается на странице ТабличныйДокумент, то:
    1. Выполняем его вывод в ИтоговыйТабличныйДокумент методом Вывести(ТабличныйДокумент)
    2. Очищаем ТабличныйДокумент
    3. Выводим шапку(если требуется) в Табличный документ
  5. Пункты 3-4 повторяются в цикле, как и при обычном формировании печатных форм
  6. В конце формирования выводим подвал в ИтоговыйТабличныйДокумент

Как это выглядит в программе

    ТабДокумент = Новый ТабличныйДокумент;
    ТабДокумент.ИмяПараметровПечати = "ПАРАМЕТРЫ_ПЕЧАТИ_ИнвентаризационнаяОписьВРазрезеГоловныхИзделий";
    ТабДокумент.ОриентацияСтраницы  = ОриентацияСтраницы.Портрет;
    ТабДокумент.МасштабПечати = 90;
    Макет   = ПолучитьМакет("ИнвентаризационнаяОпись");
    
    // Документ используется для вывода по страницам
    ИтоговыйТабДок = Новый ТабличныйДокумент;
    ЗаполнитьЗначенияСвойств(ИтоговыйТабДок, ТабДокумент); 
    
    НомерСтрокиНачало = ТабДокумент.ВысотаТаблицы + 1;
    Запрос = Новый Запрос;
    Запрос.Текст=
    "ВЫБРАТЬ
    |    ИнвентаризацияНЗП.Организация,
    |    ИнвентаризацияНЗП.Подразделение,
    |    ИнвентаризацияНЗП.Ссылка,
    |    ИнвентаризацияНЗП.Номер,
    |    ИнвентаризацияНЗП.Дата,
    |    ИнвентаризацияНЗП.Заказ,
    |    ИнвентаризацияНЗП.ВводитьЗаказыПоСтрокам,
    |    ИнвентаризацияНЗП.Заказ.Представление КАК ЗаказПредставление,
    |    ИнвентаризацияНЗП.Организация.Представление КАК ОрганизацияПредставление,
    |    ИнвентаризацияНЗП.Подразделение.Представление КАК ПодразделениеПредставление
    |ИЗ
    |    Документ.ИнвентаризацияНЗП КАК ИнвентаризацияНЗП
    |ГДЕ
    |    ИнвентаризацияНЗП.Ссылка = &ТекДок";
    Запрос.УстановитьПараметр("ТекДок", СсылкаНаОбъект);
    
    Шапка = Запрос.Выполнить().Выбрать();
    Шапка.Следующий();
    
    ИнфоОрг = УправлениеКонтактнойИнформацией.СведенияОЮрФизЛице(Шапка.Организация, СсылкаНаОбъект.Дата);
    
    Область = Макет.ПолучитьОбласть("Шапка");
    Область.Параметры.ПечНомерДок      = Шапка.Номер;
    Область.Параметры.ПечДатаДок       = Шапка.Дата;
    Область.Параметры.ПечОрганизация   = ИнфоОрг.ПолноеНаименование;
    Область.Параметры.ПечПодразделение = Шапка.ПодразделениеПредставление;
    
    Область.Параметры.КодОКПО          = ИнфоОрг.КодПоОКПО;
    Область.Параметры.Организация      = Шапка.Организация;
    Область.Параметры.Подразделение    = Шапка.Подразделение;
    
    ТабДокумент.Вывести(Область);
    ОбластьТабШапка = Макет.ПолучитьОбласть("ТабШапка");
    ТабДокумент.Вывести(ОбластьТабШапка);
    
    Индекс       = 0;
    ВсегоТМЦ     = 0;
    ВсегоКолФакт = 0;
    ВсегоКолОПУ  = 0;
    ВсегоКолОтк  = 0;
    КолФактСтр   = 0;
    СтрокНаЛисте = 5;// Изменим, подбирается опытным путем
    НПП = 0;
    ВсегоСтраниц = 0;    
    
    
    ВсегоИзделий = ДанныеДляПечати.Строки.Количество();
    
    ОбластьПодвал = Макет.ПолучитьОбласть("ПодвалСтраницы");
    
    Для Каждого СтрокаДЗ1 Из ДанныеДляПечати.Строки Цикл
        
        Состояние("Производится вывод печатной формы (изделие "+ (ДанныеДляПечати.Строки.Индекс(СтрокаДЗ1) + 1) + "/" + ВсегоИзделий + "). Стр. " + ВсегоСтраниц);
        
        Область  = Макет.ПолучитьОбласть("СтрокаПродукция");
        Область.Параметры.ПечНоменклатура = СтрокаДЗ1.НоменклатураПредставление;
        Область.Параметры.Номенклатура    = СтрокаДЗ1.Номенклатура;
        Область.Параметры.ПечКолБух          = Формат(СтрокаДЗ1.Количество, "ЧЦ=15; ЧДЦ=3");
        Область.Параметры.ПереченьЗаказов = СтрокаДЗ1.ПереченьЗаказов;
        ТабДокумент.Вывести(Область);
        
        Для Каждого СтрокаДЗ2 Из СтрокаДЗ1.Строки Цикл
            
            // Делаем через проверить вывод
            Индекс   = Индекс + 1;
            ВсегоТМЦ = ВсегоТМЦ + 1;
            НПП      = НПП + 1;
            Область  = Макет.ПолучитьОбласть("Строка");
            Область.Параметры.ПечНомер        = Формат( НПП, "ЧЦ=6; ЧН=");
            Область.Параметры.ПечНоменклатура = СтрокаДЗ2.НоменклатураПредставление;
            Область.Параметры.Номенклатура    = СтрокаДЗ2.Номенклатура;
              
            
            //Область.Параметры.ПечШифрИВЦ      = Шифр;
            Область.Параметры.ПечКодТМЦ       = СокрЛП(СтрокаДЗ2.НоменклатураКод);
            Область.Параметры.ПечКодЕИ        = СтрокаДЗ2.ЕдиницаИзмеренияКод;
            Область.Параметры.ПечЕИ           = СтрокаДЗ2.ЕдиницаИзмерения;
            
            Область.Параметры.ПечКолБух       = Формат(СтрокаДЗ2.Количество, "ЧЦ=15; ЧДЦ=3");
            
            // Если с подвалом не умещается - выводим подвал, начинаем новую страницу
            МассивДляПроверки = Новый Массив;
            МассивДляПроверки.Добавить(Область);
            //МассивДляПроверки.Добавить(ОбластьПодвал);
            Если ТабДокумент.ПроверитьВывод(МассивДляПроверки) = ЛОЖЬ Тогда
                
                // Подвал страницы просили не выводить
                //ОбластьПодвал.Параметры.КолНомСтр  = Индекс;
                //ОбластьПодвал.Параметры.ИтогКолСтр = КолФактСтр;
                //ТабДокумент.Вывести( ОбластьПодвал);
                Индекс     = 0;
                КолФактСтр = 0;
                ТабДокумент.ВывестиГоризонтальныйРазделительСтраниц();
                СтрокНаЛисте = 10; // Изменено - подбирается опытным путем  Это было раньше (На первом листе 9 строк, на остальных 30)
                
                ВсегоСтраниц = ВсегоСтраниц + 1;
                
                // Переносим изменения в итоговый документ, очищаем оригинал, выводим шапку на след.странице
                ИтоговыйТабДок.Вывести(ТабДокумент);
                
                ТабДокумент.Очистить();
                ТабДокумент.Вывести(ОбластьТабШапка);
                
            КонецЕсли;

            ОбработкаПрерыванияПользователя();// На всякий случай
            
            ТабДокумент.Вывести(Область);
            
            КолФактСтр   = КолФактСтр   + СтрокаДЗ2.Количество;
            ВсегоКолФакт = ВсегоКолФакт + СтрокаДЗ2.Количество;

        КонецЦикла;
        
    КонецЦикла;
    
    Область = Макет.ПолучитьОбласть("Итого");
    Область.Параметры.ПечКолФактИтого = Формат( ВсегоКолФакт, "ЧЦ=15; ЧДЦ=3");
    
    // Подвал страницы просили не выводить
    //ТабДокумент.Вывести( Область);
    //Если Индекс > 0 Тогда
    //    ОбластьПодвал = Макет.ПолучитьОбласть("ПодвалСтраницы");
    //    ОбластьПодвал.Параметры.КолНомСтр  = Индекс;
    //    ОбластьПодвал.Параметры.ИтогКолСтр = КолФактСтр;
    //    ТабДокумент.Вывести( ОбластьПодвал);
    //КонецЕсли;
    
    Область = Макет.ПолучитьОбласть("Подвал");
    Область.Параметры.ВсегоТМЦ      = ВсегоТМЦ;
    Область.Параметры.ИтогоКолОпись = ВсегоКолФакт;
    ТабДокумент.ВывестиГоризонтальныйРазделительСтраниц();
    ТабДокумент.Вывести( Область);
    //УправлениеПечатью.ЗадатьОбластьПечатиДокумента(ТабДокумент, НомерСтрокиНачало, Новый СписокЗначений, СсылкаНаОбъект);
    
    // Выведем всяческие подвалы
    ИтоговыйТабДок.Вывести(ТабДокумент);

Бонусом идет печатная форма для УПП 1.3, в которой присутствует этот кусок кода

46

Скачать файлы

Наименование Файл Версия Размер
Инвентаризационная опись в разрезе головных изделий
.epf 33,91Kb
06.11.17
1
.epf 33,91Kb 1 Скачать

См. также

Специальные предложения

Комментарии
Избранное Подписка Сортировка: Древо
1. Armando 1387 06.11.17 22:43 Сейчас в теме
На 8.3.11 не проверяли? Там что-то оптимизировали на эту тему:

Оптимизирована работа метода табличного документа ПроверитьВывод().
Источник: http://downloads.v8.1c.ru/content//Platform/8_3_11_2700/V8Update.htm#0bacf61e-057e-11e7-a3f7-0050569f678a
SITR-utyos; +1 Ответить
2. SITR-utyos 1125 07.11.17 07:08 Сейчас в теме
(1) Нет, на 8.3.11 не проверял. Последняя платформа, что у меня стоит 8.3.10.2639 - там такая же проблема.
Спасибо, за заметку
3. mifka186 6 07.11.17 09:41 Сейчас в теме
Что-то подобное в расчетном листке организации ЗУП 2.5 используется.

Если ВыводитьПоСтраницам Тогда
			
	ОбластьПриемник = ТабличныйДокументДляПроверки.Область(ТабличныйДокументДляПроверки.ВысотаТаблицы + 1, ,ТабличныйДокументДляПроверки.ВысотаТаблицы + (НомерСтрокиКонцаРЛ - НомерСтрокиНачалаРЛ) + 1, );
	ТабличныйДокументДляПроверки.ВставитьОбласть(ОбластьРЛ, ОбластьПриемник, , истина);
		
	КоличествоСтраниц = 0;
	Попытка
		КоличествоСтраниц = ТабличныйДокументДляПроверки.КоличествоСтраниц();
	Исключение
	КонецПопытки;
			
	Если КоличествоСтраниц > 1 тогда
				
		ТабличныйДокумент.Область(НомерСтрокиНачалаРЛ, , НомерСтрокиНачалаРЛ,).НачалоСтраницы = истина;
				
		ТабличныйДокументДляПроверки.Очистить();
			
		Для сч = 0 по НастройкаШириныКолонокРасчетногоЛистка.ВГраница() Цикл
			ОбластьКолонкиРЛ                  = ТабличныйДокументДляПроверки.Область(, сч+1, , сч+1);
			ОбластьКолонкиРЛ.ШиринаКолонки    = НастройкаШириныКолонокРасчетногоЛистка[сч];
			ОбластьКолонкиРЛ.РазмещениеТекста = ПолучитьТипРазмещенияТекста(НастройкаРазмТекстаКолонокРасчетногоЛистка[сч]);
		КонецЦикла;
				
		ОбластьПриемник = ТабличныйДокументДляПроверки.Область(ТабличныйДокументДляПроверки.ВысотаТаблицы + 1, ,ТабличныйДокументДляПроверки.ВысотаТаблицы + (НомерСтрокиКонцаРЛ - НомерСтрокиНачалаРЛ) + 1, );
		ТабличныйДокументДляПроверки.ВставитьОбласть(ОбластьРЛ, ОбластьПриемник, , истина);
				
	КонецЕсли;
			
КонецЕсли;
Показать
4. madonov 159 07.11.17 09:49 Сейчас в теме
Плюс за идею. Взял на вооружение.
5. nvv1970 07.11.17 11:14 Сейчас в теме
Работа с табличным документом, текстовым документом деградирует пропорционально росту его объема. Поэтому можно применять не только указанный метод, но и использовать для организации печати страниц двумерный массив табличных документов. Так можно определить последовательность вывода по строкам, столбам, чёт/нечет и т.д. на сколько хватит фантазии.
sm.artem; +1 Ответить
6. BigB 176 07.11.17 12:09 Сейчас в теме
Каждый месяц генерирую примерно > 600 тысяч квитанций пачками по 1000 листов в пачке.
На каждой странице (внизу) есть адрес доставки и кому.
Квитанция должна занимать не более одной страницы.
Я поступаю так: если адрес доставки больше 150 тогда делаю проверку на количество страниц и если произошел перенос адреса на другую страницу - уменьшаю шрифт, пока не влезет в одну страницу.
Вот такой кусок кода у меня:
//Автоматическое изменение размера шрифта адреса доставки
Если СтрДлина(Выборка.АдресДоставки)>150 И ТДП.КоличествоСтраниц()>ХХ Тогда
	Y=Формат(ТДП.Области.Подвал.Низ,"ЧГ=0");
	ОбластьДоставки=ТДП.Область("R"+Y+"C2:R"+Y+"C10");
	Пока Истина Цикл
		ОбластьДоставки.Шрифт=Новый Шрифт(ОбластьДоставки.Шрифт,ОбластьДоставки.Шрифт.Имя,ОбластьДоставки.Шрифт.Размер-1);
		Если ТДП.КоличествоСтраниц()=ХХ Тогда
			Прервать
		ИначеЕсли ОбластьДоставки.Шрифт.Размер<7 Тогда
			Сообщить("Л/С "+Выборка.НомерЛС+" Не удалось разместить на одной странице адрес доставки:"+Символы.ПС+Выборка.АдресДоставки);
			Прервать
		КонецЕсли;
	КонецЦикла;
КонецЕсли;
Показать
jaroslav.h; sm.artem; AlexGroovy; Danil.Potapov; +4 Ответить
7. vis_tmp 28 08.11.17 06:33 Сейчас в теме
Спасибо, интересный метод ускорения печати больших отчётов!
8. AlexGroovy 08.11.17 11:11 Сейчас в теме
А где именно в коде оптимизация ? Я понял,если бы вы избежали ПроверитьВывод(),но у он у вас остался и находится в цикле.Смысл в том,что всё выводится в итоговый табличный документ?
9. корум 311 08.11.17 11:52 Сейчас в теме
(8)
А где именно в коде оптимизация ? Я понял,если бы вы избежали ПроверитьВывод(),но у он у вас остался и находится в цикле.Смысл в том,что всё выводится в итоговый табличный документ?

нет, не понял.
Смысл в том, что не тормозит.
ПроверитьВывод() 3 страниц 0,01 сек, ПроверитьВывод() 300 страниц не 1 сек, а 100.
ПроверитьВывод() для 3 страниц 100 раз - 1 сек.
11. AlexGroovy 08.11.17 14:13 Сейчас в теме
А как у вас получается область на 300 страниц сразу,если вы в цикле как и в типовом механизме добавляете по области строчке и сразу переносите другие на новую страницу?
13. madonov 159 09.11.17 02:36 Сейчас в теме
(11) да не область на 300 страниц. А сам табличный документ на 300 страниц.

БольшойТабличныйДокумент.ПроверитьВывод(Область)
работает гозадо медленнее чем
МалыйТабличныйДокумент.ПроверитьВывод(Область)

Автор предлагает не вызывать ПроверитьВывод() для большого документа на 300 страниц, а вызывать эту функцию только для малого табличного документа, который равен последней странице большого.

Ускорение происходит не за счет того, что уменьшается количество вызовов функции ПроверитьВывод(), а за счет того, что каждый вызов занимает в разы меньше времени.
echo77; klinval; корум; AlexGroovy; +4 Ответить
14. AlexGroovy 09.11.17 09:54 Сейчас в теме
(13)Спасибо большое за ответ =)
10. BigB 176 08.11.17 12:35 Сейчас в теме
(0) Уберите из названия "для огромных документов".
Поверьте мне - 200 страниц это мизерный документ.
Не используйте ПроверитьВывод().
Вместо этого используйте КоличествоСтраниц() в разумных пределах и отчет будет формироваться очень быстро.
12. madonov 159 09.11.17 02:28 Сейчас в теме
(10) предположим, что выводим область и при помощи КоличествоСтраниц() видим, что количество страниц увеличилось.
И как без ПроверитьВывод() определить целиком ли новая новая область на новой странице или её "разорвало" на разные и требуется вставка разрыва страницы?
15. apostal86 200 09.11.17 09:59 Сейчас в теме
Идея интересная. Надо запомнить
16. androgin 10.11.17 00:55 Сейчас в теме
Простите, а если длина наименования постоянно разная и может занимать 1,2,3 строки, то как вы это обойдете?
На одном листе может быть 40 строк, а следующем 50, а третьем ваще 35.
Тут уже параметр СтрокНаЛисте не имеет смысла
17. echo77 988 10.11.17 05:59 Сейчас в теме
(16) В примере переменная СтрокНаЛисте нигде не используется, если посмотреть циклы внимательное. Это наследие типовой формы инвентаризации - там сделано именно так
Оставьте свое сообщение