29.09.2020, 21:22 | #1 |
Участник
|
DAX09: некорректное отображение полоски ProgressBar
Привет.
Вроде ничего сложного но не могу разобратся, почему у меня некорректно отображается полоска прогресс бара в методе run классе наследнике RunBase. Начальные значения: strTo = 1, strFrom = 4. Т.е. 4 итерации, все просто. Соответственно и полоска прогресс бара для 1 итерации должна нанимать 25%, для 2 - 50%, 3 - 75%, 4 - 100%. Но почему так некорректно отображается? Что даже итерацию 4 - не показывает. Приложил скриншеты. X++: public void run() { ... Counter curRow, countRows, numRows; ... void progressUpdate(Counter _curr, Counter _num) { real percent = decRound((_curr / _num) * 100, 2); ; progress.incCount(); progress.setText(strfmt("%1 из %2 (%3)", _curr, _num, strFmt("%1%", percent))); } ; ... numRows = strTo - strFrom + 1; progress = new RunbaseProgress(); progress.setCaption("Импорт"); progress.setAnimation(#AviUpdate); progress.setTotal(numRows); startLengthyOperation(); ... for (curRow = strFrom; curRow <= strTo; curRow++) { countRows++; progressUpdate(countRows, numRows); ... } ... endLengthyOperation(); ... } Последний раз редактировалось oleggy; 29.09.2020 в 21:25. |
|
29.09.2020, 22:11 | #2 |
Administrator
|
Ответ-то вроде лежит на поверхности. Судя по индикатору (если не исследовать внутренности кода) - внутренний счетчик прогресс-бара начинается с 1 (а если полезть изучать код, то это можно будет увидеть). И первый вызов progress.incCount() увеличивает его до 2 (а это 50% из 4-х).
Поменяйте местами progress.setText и progress.incCount() - и получите желаемое. Можно еще будет между ними поставить (чисто для целей отладки) явный вызов progress.update(true) для перерисовки формы на экране, хотя в общем-то он и так вызывается из каждого метода
__________________
Возможно сделать все. Вопрос времени Последний раз редактировалось sukhanchik; 29.09.2020 в 22:14. |
|
01.10.2020, 14:02 | #3 |
Участник
|
|
|
02.10.2020, 12:45 | #4 |
Administrator
|
Судя по скриншотам - это так. И поэтому собственно "зависание" на 100%-ах
__________________
Возможно сделать все. Вопрос времени |
|
02.10.2020, 12:56 | #5 |
Участник
|
Цитата:
Я открыл код которых мильён с прогрессом. И там все норм - с ноля начинается. Тотал - 4, и значит надо 4 итерации чтобы заполнить прогресс. А что случилось у автора темы не понятно.. толи он нам чего-то не договаривает между точек толи... Ну можем сойтись на том, у него то как раз RunbaseProgress начинается с единицы.. кастомизация) Последний раз редактировалось Perc; 02.10.2020 в 12:59. |
|
02.10.2020, 14:42 | #6 |
Участник
|
У вас проблемы с доверием.
По поводу скриншетов - они абсолютно достоверны. То что я указал точки (...) не для того что бы что то скрыть - там был код который абсолютно не относится и затрудняет восприятие проблемы. У меня 4 итерации. Начиная с 1 по 4 включительно. Нумерация в цикле с 1 по 4 включительно. Я же код не зря предьявил. Вопрос почему на первой итерации уже было 50% прогресса? Последний раз редактировалось oleggy; 02.10.2020 в 14:47. |
|
02.10.2020, 15:07 | #7 |
Участник
|
вам уже ответили:
Цитата:
Сообщение от sukhanchik
Ответ-то вроде лежит на поверхности. Судя по индикатору (если не исследовать внутренности кода) - внутренний счетчик прогресс-бара начинается с 1 (а если полезть изучать код, то это можно будет увидеть). И первый вызов progress.incCount() увеличивает его до 2 (а это 50% из 4-х).
а чтобы увидеть значение счетчика внутри прогресса - методом progress.getCount_RU() |
|
02.10.2020, 15:34 | #8 |
Участник
|
Цитата:
Воспользуйтесь отладчиком, посмотрите. |
|
02.10.2020, 18:24 | #9 |
Участник
|
Перевел весь свой код в просто джоб. Что бы предметно дебажить.
X++: Counter countRows, numRows; Counter strFrom = 1, strTo = 4; RunbaseProgress progress = new RunbaseProgress(); #AviFiles void progressUpdate(Counter _curr, Counter _num) { str percent = strFmt("%1%", decRound((_curr / _num) * 100, 2)); progress.setText(strfmt("@SYS66083", _curr, _num, percent)); progress.incCount(); //progress.update(true); } ; progress.setCaption("Импорт"); progress.setAnimation(#AviUpdate); numRows = strTo - strFrom + 1; progress.setTotal(numRows); startLengthyOperation(); for (countRows = 1; countRows <= numRows; countRows++) { progressUpdate(countRows, numRows); sleep(2000); } endLengthyOperation(); } Цитата:
Поэтому смотрел через дебаг. Нумерация у меня идет с нуля. Перед первым выполнением progress.incCount() значение progress.oprProgress.lapProgress равно 0. Как вы видете после запуска джоба я вижу только три изменения окна прогресс бара. ТРИ. Но если я раскомменчу progress.update(true) отображает корректно ЧЕТЫРЕ окна. Четыре итерации. Т.е. 1 - 25%, 2 - 50%, 3 - 75%, 4 - 100%. Я почему тему поднял, просто хотелось понять: 1. почему ТАК криво отображается прогресс бар? 2. после какого оператора происходит обновление окна Импорт? Какой метод это делает? Или после какого метода это происходит? Последний раз редактировалось oleggy; 02.10.2020 в 19:48. |
|
02.10.2020, 20:18 | #10 |
Участник
|
Цитата:
Видимо необходимость в перерисовке окна вычисляется каким то алгоритмом инициируемым при вызове любой из этих функций. От чего этот момент зависит точно - надо дотошно код смотреть. Но фокус получился в том что перерисовка произошла после первой функции в итерации. А на вызове второй алгоритм сказал - к черту, только что обновляли. Как сделать чтобы текст и движок корректно синхронизировались даже сходу не скажу. Update(true) в общем случае не рекомендуется, если случай большого количества мелких итерации. |
|
02.10.2020, 20:22 | #11 |
Участник
|
бедняжка
добавьте X++: //mazzy 13.12.2019: по образцу getTotal() public int64 getCount(int _idx = 1) { if (oprProgress) return oprProgress.getCount_RU(_idx); else if (oprProgressEmbedded ) return oprProgressEmbedded.getCount_RU(_idx); else if ( oprProgressServer ) return oprProgressServer.getCount(_idx); else return 0; } Цитата:
Сообщение от oleggy
Нумерация у меня идет с нуля.
Перед первым выполнением progress.incCount() значение progress.oprProgress.lapProgress равно 0. Как вы видете после запуска джоба я вижу только три изменения окна прогресс бара. ТРИ. Но если я раскомменчу progress.update(true) отображает корректно ЧЕТЫРЕ окна. Цитата:
Заглянул внутрь. Вспомнил. Заодно вспомнил про тему (Не)перерисовка окна клиента AX 2009 при длительных операциях - вариант решения Поностальгировал. Вернемся к вопросам. Прогресс-бар - это GUI-форма. Обновление GUI-формы - дело относительно не быстрое. Даже перерисовка консольного прогресс бара занимает время. Нормальные прогресс-бары не отрисовывают КАЖДОЕ изменение прогресса, а обновляют по таймеру, чтобы отрисовка не выполнялась дольше, чем полезная работа. Вот и в Аксапте у метода update есть параметр force: если сказать force=true, то update перерисует форму в обязательном порядке если сказать force=false, то update будет перерисовывать только когда пройдет некоторое время с предыдущей отрисовки. поначалу updateInterval равен трем попугаям для сервера и одному попугаю для клиента. по ходу пьесы, progressBar пытается отрегулировать updateInterval так, чтобы он был больше, чем время перерисовки окна. а также пытается показать себя сильно умным ГЛАВНОЕ: метод update(false) НЕ перерисовывает окно при каждом изменении. теперь собственно что происходит: 1. методы setText() и incCount() унутре себя вызывают update(false) следовательно возможна ситуация, когда на первом методе окно будет перерисовно, а на втором - не будет. так и получается рассогласованное изображение окна. но вполне согласованое состояние внутри. 2. когда вы явно вызываете update(true), то окно будет принудительно перерисовано. И каким бы оно ни было нарисовано в предыдущих строках, здесь оно будет нарисовано в согласованном состоянии. 3. попробуйте тест на очень много значений с принудительной отрисовкой и с отрисовкой по умолчанию. замерьте время выполнения. скорее всего вы удивитесь как много времени уходит на отрисовку прогрессБара. мало того, и на обслуживание этой счетчиков тоже тратится время и дополнительно напрягается сборщик мусора. на некоторых проектах даже запрещают использовать прогресс-бар совсем (не рекомендую). 4. что делать: не ориентироваться на точные значения прогресс-бара. выводить текст для того, чтобы примерно представлять где мы находимся (даты обрабатываемых проводок, код товаров в алфавитном порядке и тп) увеличивать updateInterval (рекомендую 5-10 секунд) 5. что можно улучшить: в стандартной аксапте катастрофически не хватает метода, который меняет одновременно и текст, и счетчик. такой метод обычно и добавляют на проектах. Последний раз редактировалось mazzy; 02.10.2020 в 20:25. |
|
|
За это сообщение автора поблагодарили: sukhanchik (10), oleggy (1). |
02.10.2020, 23:26 | #12 |
Administrator
|
Спасибо за подробное разъяснения! Почерпнул для себя много интересного
__________________
Возможно сделать все. Вопрос времени |
|
03.10.2020, 05:27 | #13 |
Участник
|
Цитата:
Сообщение от mazzy
добавьте
X++: //mazzy 13.12.2019: по образцу getTotal() public int64 getCount(int _idx = 1) { if (oprProgress) return oprProgress.getCount_RU(_idx); else if (oprProgressEmbedded ) return oprProgressEmbedded.getCount_RU(_idx); else if ( oprProgressServer ) return oprProgressServer.getCount(_idx); else return 0; } X++: public int64 getCount(int _idx = 1) { if (oprProgress) return oprProgress.getCount_RU(_idx); else if (oprProgressEmbedded ) return oprProgressEmbedded.getCount_RU(_idx); else return 0; } Я прав? Или для сервера такой функционал тоже нужен - getCount. |
|
03.10.2020, 07:59 | #14 |
Участник
|
Изменил код с учетом добавленного метода getCount и стало по другому (!):
X++: { Counter currRow; Counter strFrom = 1, strTo = 4; RunbaseProgress progress = new RunbaseProgress(); #AviFiles void progressUpdate() { str percent = strFmt("%1%", decRound((progress.getCount() / progress.getTotal()) * 100, 2)); progress.setText(strfmt("@SYS66083", progress.getCount(), progress.getTotal(), percent)); progress.incCount(); } ; progress.setCaption("Импорт"); progress.setAnimation(#AviUpdate); progress.setTotal(strTo - strFrom + 1); startLengthyOperation(); for (currRow = strFrom; currRow <= strTo; currRow++) { progressUpdate(); sleep(2000); } endLengthyOperation(); } С этим кодом теперь хотя бы показывает корректно полоску прогресс бара: Т.е. 1 - 25%, 2 - 50%, 3 - 75%. 4 шаг не показывает. Похоже тут ничего поделать нельзя. Последний раз редактировалось oleggy; 03.10.2020 в 09:21. |
|
03.10.2020, 11:55 | #15 |
Участник
|
Цитата:
Если не получается написать метод который вам посоветовал mazzy в пункте 5, то вам проще что-нить убрать - или setText или полоску движка. Я, в случае если хочу в прогрессе уведомить о начале этапа многоэтапной обработки(ну предположим обработка по месяцам) - не стесняюсь, пишу update(true). Если у вас такой же случай, то тоже пишите. А если итераций сотни+, то никто не заметить в движке возможную мелкую несогласованность) |
|
03.10.2020, 13:56 | #16 |
Участник
|
Цитата:
Сообщение от mazzy
добавьте
X++: //mazzy 13.12.2019: по образцу getTotal() public int64 getCount(int _idx = 1) { if (oprProgress) return oprProgress.getCount_RU(_idx); else if (oprProgressEmbedded ) return oprProgressEmbedded.getCount_RU(_idx); else if ( oprProgressServer ) return oprProgressServer.getCount(_idx); else return 0; } Он тоже самописный. Мне интересно. |
|
04.10.2020, 09:27 | #17 |
Участник
|
Цитата:
(и вообще считаю, что префиксы-суффиксы - зло. раз, два) код метода SysOperationProgressServer.getCount X++: public int64 getCount(int _idx = 1) { if ( Bypass ) return 0; select ProgressTotal from progress where progress.RecId == progressRecIds[_idx]; return progress.ProgressCount; } в серверном прогресс-баре счетчик записывается в таблицу, которая является общей для всех процессов. и обновление SysProgress параллельными процессами в легкую может стать бутылочным горлышком на сервере. выше я говорил, что некоторые на проектах запрещают использовать ProgressBar вообще. конечно же не для того, чтобы усложить жизнь пользователей а именно из-за того, что натыкаются на это бутылочное горлышко. в основном проблема возникает, когда программист отлаживает RunBaseBatch на клиенте с прогрессбаром, а потом этот же класс безо всяких модификаций начинает выполняться в пакетнике. есть разные подходы для решения проблемы с прогресс-баром на сервере. что-то сделано и в Аксапте - обратите внимание, как забавно работает процент выполненных работ в пакетных заданиях Цитата:
просто окно прогресса закрывается раньше, чем пользователь успевает заметить. Хинт в том, что винда тоже отрисовывает окошки не сразу. Там тоже свой delay есть. Цитата:
Цитата:
Сообщение от Perc
Я, в случае если хочу в прогрессе уведомить о начале этапа многоэтапной обработки(ну предположим обработка по месяцам) - не стесняюсь, пишу update(true). Если у вас такой же случай, то тоже пишите. А если итераций сотни+, то никто не заметить в движке возможную мелкую несогласованность)
см. форму Tutorial_Progress Цитата:
чтобы сделать его самостоятельно, посмотрите на серверный setCount |
|
05.10.2020, 09:48 | #18 |
Участник
|
Цитата:
Сообщение от mazzy
Цитата:
Сообщение от oleggy
Изменил код с учетом добавленного метода getCount и стало по другому (!): ... 4 шаг не показывает. Похоже тут ничего поделать нельзя. просто окно прогресса закрывается раньше, чем пользователь успевает заметить. Цитата:
Если у вас не получается как в пункте 5 и другие варианты не устраивают, то сделайте как в пункте 5)) |
|
05.10.2020, 18:06 | #19 |
Участник
|
Цитата:
Но ваше восприятие тоже возможно. наверное, точно было выразиться так: или добавить метод, который не обращаясь к методам incCount, setCount, setText, обновляет и счетчик, и текст. после чего вызывает update один раз. |
|