Имя: Пароль:
1C
1С v8
УФ как сделать прогресс-бар
0 Никулин Леонид
 
14.12.15
12:52
Здравствуйте!

Есть обработка, которая может выполняться несколько часов. Попросили добавить на форму ПолеИндикатора (прогресс бар) для визуального отображения сколько уже сделано и вообще не повисла ли программа. УФ. Код обработки выполняется в модуле формы. Компиляция &НаСервере. Если делать то же самое на клиенте индикатор плавно ползет "в реальном времени". Все ок. А у меня получается так.Запускаешь обработку. 0 процентов выполнено. Зависон на время цикла. 100 выполнено.
Вопрос. Умные и талантливые, скажите можно ли добиться "плавности хода))" Возможно я не то что-то делаю
Ниже добавлю код в отдельном сообщении для читаемости

Спасибо!
1 Никулин Леонид
 
14.12.15
12:54
&НаКлиенте
Процедура Погнали(Команда)
    
    // На клиенте все хорошо
    //ТекущееЗначение = 0;    
    //Для Итератор = 1 По ВсегоЭлементов Цикл         
    //            
    //    ПроцентВыполнения = Цел(Итератор * 100 / ВсегоЭлементов);                    
    //    Если ПроцентВыполнения <> ТекущееЗначение Тогда                         
    //        Объект.ИндикаторСостояния = ПроцентВыполнения;
    //        Объект.СтрокаСостояния    = ПроцентВыполнения;
    //        
    //        ОбновитьОтображениеДанных();
    //        ТекущееЗначение = ПроцентВыполнения;
    //    КонецЕсли;
    //КонецЦикла;
    
    ПередачаДанныхССервера();
    
КонецПроцедуры

&НаСервере
Процедура ПередачаДанныхССервера()
    
    ТекущееЗначение = 0;    
    Для Итератор = 1 По ВсегоЭлементов Цикл         
                
        ПроцентВыполнения = Цел(Итератор * 100 / ВсегоЭлементов);                    
        Если ПроцентВыполнения <> ТекущееЗначение Тогда                         
            
            ОбработкаОбъект = РеквизитФормыВЗначение("Объект");          
                        
            ОбработкаОбъект.ИндикаторСостояния = ПроцентВыполнения;
            ОбработкаОбъект.СтрокаСостояния    = ПроцентВыполнения;
            
            ЗначениеВРеквизитФормы(ОбработкаОбъект, "Объект");            
            
            ТекущееЗначение = ПроцентВыполнения;
        КонецЕсли;
    КонецЦикла;
        
КонецПроцедуры
2 los_hooliganos
 
14.12.15
12:55
Сделай обработчик ожидания на клиенте.
Тока запись делай во внешний объект, а не в форму/отчет.
3 ДенисЧ
 
14.12.15
12:55
Нельзя.
4 Никулин Леонид
 
14.12.15
12:55
((
5 los_hooliganos
 
14.12.15
12:57
(4) Пусть лучше с сервера шлет на сайт какой-нить. На сайт зашел и глянул скока сделано
6 Никулин Леонид
 
14.12.15
13:02
(2) я об этом думал, но у меня все на сервере. С клиента не получается. У меня цикл на сервере. Можно конечно еще один на клиенте конечно сделать, но это уже будет грубо.
(3) спасибо за комментарий
(4) овчинка выделки не стоит

Всем спасибо!
7 Fragster
 
гуру
14.12.15
13:03
можно каждые хх итераций на сервере сохранять прогресс во временное хранилище, возвращаться на клиента, обновлять индикатор, и уходить обратно на сервер. типа так:

Адрес = СохранитьДанныеДляОбработки(Данные);
Пока ИтерацияОбработки(Адрес) Цикл

КонецЦикла;
Данные = ПолучитьОбрабтанныеДанные(Адрес);

СохранитьДанныеДляОбработки и ИтерацияОбработки - НаСервереБезКонтекста, в итерации данные достаются из хранилища, обрабатывается часть - и кладутся обратно. Если все обработано - возврат Ложь, Иначе - Возврат Истина.
8 los_hooliganos
 
14.12.15
13:05
(7) Это бред. Не нужно так делать.
9 los_hooliganos
 
14.12.15
13:07
(6) Перед стартом на сервер запускай обработку, которая регулярно с регистра сведений будет читать состояние цикла.
10 Никулин Леонид
 
14.12.15
13:08
(7) Спасибо. Обязательно попробую.
(8) это может негативно сказаться на производительности?
11 Fragster
 
гуру
14.12.15
13:10
(8) так можно делать. естественно, "итерация" - достаточно укрупненная.

В идеале, конечно, фоновым заданием, обработкой ожидания и, например, получитьСообщенияПользователя, но это уже без изменения конфигурации нельзя сделать.
12 Fragster
 
гуру
14.12.15
13:11
а вот (9) - уже не надо, для получения из фоновой обработки данных прекрасно можно использовать сообщения пользователю и ХХХвременноехранилище
13 los_hooliganos
 
14.12.15
13:13
(11) Нельзя послать сообщение без изменения конфы??!
А гонять реквизиты высоконагруженной формы можно?
14 Fragster
 
гуру
14.12.15
13:13
для (7) - переход на сервер без контекста - занимает примерно 0.01 секунды, работа со временным хранилищем - в зависимости от объема. соответственно, если мы будем обрабатывать данные в 100 раз дольше, чем (работа со врем. хранилищем + 0.01с), то оверхэд будет 1% на обновление счетчика
15 Fragster
 
гуру
14.12.15
13:14
(13)при использовании НаСервереБезКонтекста - ничего не гоняется
16 Fragster
 
гуру
14.12.15
13:15
(13) нельзя запустить фоновое задание с нужным кодом без изменения конфы, например из внешней обработки
17 los_hooliganos
 
14.12.15
13:17
(16) Суть в том что нам надо поднять даже не обработчик ожидания а сокет, который будет просто сидеть и ждать сообщений. Это идеально для клиент-сервера и в 8.3.7 это уже возможно.
18 oslokot
 
14.12.15
13:17
(16) а из внешней - фоново запустить другую внешнюю? прокатит?
19 los_hooliganos
 
14.12.15
13:19
(18) Строго говоря нет. Ибо фоновые/регламентные задания нужно заранее делать в самой конфе.
20 Fragster
 
гуру
14.12.15
13:21
(18) в теории подсистема ДлительныеОперации из БСП такое позволяет делать, но я не пробовал
21 Fragster
 
гуру
14.12.15
13:22
(17) зачем так много умных слов?
22 Сергиус
 
14.12.15
13:36
(0)Самый оптимальный вариант, как было сказано в (8). А что мешает изменить конфу, добавив один общий модуль, где и будет функция для фоновой загрузки?
23 DexterMorgan
 
14.12.15
13:44
(20) Позволяет, я пробовал и делал, но есть нюанс. По фэншую нужно посылать из фонового на клиент данные о состоянии индикатора через СообщениеПользователю, а принимать используя ФоновоеЗадание.ПолучитьСообщенияПользователю
В БСП фоновое задание в ДлительныхОперациях запускается без ключа, соответственно идентифицировать однозначно запущенное фоновое задание нельзя. Я помещал данные о состоянии индикатора в ХранилищеОбщихНастроек.
24 DexterMorgan
 
14.12.15
13:45
(7) А ты плохое советуешь
25 Fragster
 
гуру
14.12.15
13:47
(24) это не всегда плохо, см (14)
26 vhl
 
14.12.15
13:47
БСП. ДлительныеОперации
27 Fragster
 
гуру
14.12.15
13:50
(23) судя по справке - есть параметр для этих целей, достаточно в обработчике ожидания брать оттуда прогресс, например.

//  ИспользоватьДополнительноеВременноеХранилище – Булево – признак использования
//                           дополнительного временного хранилища для передачи данных
//                           в родительский сеанс из фонового задания. По умолчанию – Ложь.
28 DexterMorgan
 
14.12.15
13:51
(27) Эти все временные хранилища доступны только после завершения фонового задания.
29 Fragster
 
гуру
14.12.15
13:52
(28) судя по справке - нет :)
30 DexterMorgan
 
14.12.15
13:56
(29) Из СП:

Примечание:

Временное хранилище, сформированное в одном сеансе, недоступно из другого сеанса.
Исключением является возможность передачи данных из фонового задания в сеанс, инициировавший фоновое задание, с помощью временного хранилища. Для такой передачи следует в родительском сеансе поместить во временное хранилище пустое значение, передав идентификатор формы. Затем полученный адрес передать в фоновое задание через параметры фонового задания. Далее, если этот адрес использовать в параметре <Адрес>, то результат будет скопирован в сеанс, из которого было запущено фоновое задание.
Данные, помещенные во временное хранилище в фоновом задании, не будут доступны из родительского сеанса до момента завершения фонового задания.
31 DexterMorgan
 
14.12.15
13:59
(29) Так данные будут переданы в родительский сеанс все правильно, только после завершения задания
32 vhl
 
14.12.15
14:14
(23) Все там есть.
&НаКлиенте
Процедура ДлительныеОперации_Старт_Клиент()
    
    ОтключитьОбработчикОжидания("ДлительныеОперации_Обработчик");
        
    РезультатЗапуска = ДлительныеОперации_Старт_Сервер();
    
    ИдентификаторЗадания = РезультатЗапуска.ИдентификаторЗадания;
    АдресХранилища = РезультатЗапуска.АдресХранилища;
    
    Если РезультатЗапуска.ЗаданиеВыполнено Тогда
        ДлительныеОперации_Завершение();
    Иначе    
        ПодключитьОбработчикОжидания("ДлительныеОперации_ОбработчикОжидания", 1, Истина);
    КонецЕсли;
    
КонецПроцедуры

&НаСервере
Функция ДлительныеОперации_Старт_Сервер()
    
    ПараметрыМетода = Новый Структура;      
    ПараметрыМетода.Вставить("ПолноеИмяОбъекта", "Отчет.мойКрутойОтче");
    ПараметрыМетода.Вставить("ДатаНач",ДатаНач);
    ПараметрыМетода.Вставить("ДатаКон",ДатаКон);
    ПараметрыМетода.Вставить("Контрагент",Контрагент);
    ПараметрыМетода.Вставить("Организация",ОрганизацияПТ);
    
    Возврат ДлительныеОперации.ЗапуститьВыполнениеВФоне(
    УникальныйИдентификатор,
    "ДлительныеОперации.ВыполнитьКомандуОтчетаИлиОбработки",
    ПараметрыМетода);
    
КонецФункции

&НаКлиенте
Процедура ДлительныеОперации_ОбработчикОжидания()
    
    Попытка
        Если ЗаданиеВыполнено(ИдентификаторЗадания) = Истина Тогда
            ДлительныеОперации_Завершение();
        Иначе
            Прогресс = ПрочитатьПрогресс(ИдентификаторЗадания);
            Если Прогресс <> Неопределено Тогда
                ПроцентВыполнения = Прогресс.Процент;
                ОтображениеСостояния.Текст = "Вполнение: "+ПроцентВыполнения+"%";
            КонецЕсли;
            
            ПодключитьОбработчикОжидания("ДлительныеОперации_ОбработчикОжидания", 1, Истина);
        КонецЕсли;
    Исключение
        ДлительныеОперации_Завершение(Истина, ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
КонецПроцедуры

&НаКлиенте
Процедура ДлительныеОперации_Завершение(флЕстьОшибки = Ложь, вхТекстОшибки = "")
    
    Результат = ПолучитьИзВременногоХранилища(АдресХранилища);
    
КонецПроцедуры

В модуле отчета:
Процедура ВыполнитьКоманду(ПараметрыВыполнения, АдресРезультата) Экспорт

    Договоры = ПараметрыВыполнения.Договоры;
    ДатаНач = ПараметрыВыполнения.ДатаНач;
    ДатаКон = ПараметрыВыполнения.ДатаКон;
    Контрагент = ПараметрыВыполнения.Контрагент;
    Организация = ПараметрыВыполнения.Организация;

    Результат = СкомпоноватьОтчет(ДатаНач, ДатаКон, Контрагент, Организация);
    Возврат ПоместитьВоВременноеХранилище(Результат, АдресРезультата);
    
КонецПроцедуры
33 DexterMorgan
 
14.12.15
14:20
(32) Блин, вот ты делал? Понятно, что не делал, разуй свои глаза и перечитай (30), для тебя выделю:

"Данные, помещенные во временное хранилище в фоновом задании, не будут доступны из родительского сеанса до момента завершения фонового задания."

Не будут доступны понимаешь?
34 Жан Пердежон
 
14.12.15
14:29
запускаешь задание
ФоновыеЗадания.Выполнить("ДополнительныеОтчетыИОбработки.ВыполнитьКоманду", Параметры, Ключ, "Наименование");

где-то в коде задания ДлительныеОперации.СообщитьПрогресс(100, ТекстСообщения);

в обработчике ожидания
ДлительныеОперации.ПрочитатьПрогресс(ИдентификаторЗадания);
35 Fragster
 
гуру
14.12.15
14:29
короче, в БСП нужно допилить - для возврата УИДа задания (ну, это просто). В самой форме в параметрах при создании на сервере будет ссылка на внешнюю обработку в ДополнительнаяОбработкаСсылка. через код, скопипащенный из формы выбора внешних обработок можно все запустить как надо

    Попытка
        Если ОбщегоНазначения.ИнформационнаяБазаФайловая() Тогда
            Результат.Значение  = ДополнительныеОтчетыИОбработки.ВыполнитьКоманду(ПараметрыВызоваСервера, Неопределено);
            Результат.Выполнено = Истина;
        Иначе
            РезультатФоновогоЗадания = ДлительныеОперации.ЗапуститьВыполнениеВФоне(
                УникальныйИдентификатор,
                "ДополнительныеОтчетыИОбработки.ВыполнитьКоманду",
                ПараметрыВызоваСервера,
                НСтр("ru = 'Дополнительные отчеты и обработки: Выполнение серверного метода обработки'"));
            
            Если РезультатФоновогоЗадания.ЗаданиеВыполнено Тогда
                Результат.Выполнено = Истина;
                Результат.Значение  = ПолучитьИзВременногоХранилища(РезультатФоновогоЗадания.АдресХранилища);
            Иначе
                ФоновоеЗаданиеИдентификатор  = РезультатФоновогоЗадания.ИдентификаторЗадания;
                ФоновоеЗаданиеАдресХранилища = РезультатФоновогоЗадания.АдресХранилища;
            КонецЕсли;
        КонецЕсли;
    Исключение
        Результат.ВызваноИсключение = Истина;
        ДополнительныеОтчетыИОбработки.ЗаписатьОшибку(
            ПараметрыВызоваСервера.ДополнительнаяОбработкаСсылка,
            НСтр("ru = 'Команда %1: Ошибка выполнения:%2'"),
            ПараметрыВызоваСервера.ИдентификаторКоманды,
            Символы.ПС + ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
    КонецПопытки;
36 DexterMorgan
 
14.12.15
14:32
(35) Ну вопрос как без допила, а чем ХранилищеОбщихНастроек плохо?
37 Fragster
 
гуру
14.12.15
14:32
даже допиливать ничего не надо, ИД задания в ДлительныеОперации.ЗапуститьВыполнениеВФоне(...).ИдентификаторЗадания
38 Fragster
 
гуру
14.12.15
14:32
(36) тем, что никто его не чистит
39 DexterMorgan
 
14.12.15
14:34
(38) ну надо чистить перед запуском, все дела
40 DexterMorgan
 
14.12.15
14:37
(37) Ох ты точно, да не вот это я не видел.

смоттрел что тут
Задание = ФоновыеЗадания.Выполнить("РаботаВБезопасномРежиме.ВыполнитьМетодКонфигурации", ПараметрыЗадания,, НаименованиеЗадания);

ключа нет и не смотрел что функция выполняет, тогда конечно
41 DexterMorgan
 
14.12.15
14:37
(40) что функция возвращает*
42 DexterMorgan
 
14.12.15
14:38
(32) сорри, я думал ты мне про временное хранилище тоже пишешь
43 Andreyyy
 
14.12.15
14:38
44 Никулин Леонид
 
14.12.15
14:39
А можно еще раз для тех кто в танке. Так как все таки попробовать?
45 Никулин Леонид
 
14.12.15
14:43
(43) Ого. А я не знал что на Мисте есть такая штука. Каталог прям как на вражеском сайте. Буду курить. Там кажись понятно...
46 DexterMorgan
 
14.12.15
14:43
(45) это инфостарт, а не миста =)
47 vhl
 
14.12.15
14:46
(33) это рабочий код из рабочей базы. Можешь продолжать городить огороды с хранилищами настроек
48 Никулин Леонид
 
14.12.15
14:46
Вот черт! А шапка Мисты. Кругом обман! Я уж думал на Мисте тоже самое организовали
49 DexterMorgan
 
14.12.15
14:47
(47) ну извинился же в (42), был неправ
50 Никулин Леонид
 
14.12.15
15:11
https://yadi.sk/d/eGdJFRAC0KYZO то что доктор прописал. Достал из поста 43.
Всем большое спасибо!