|
09.08.2007, 13:25 | #1 |
Moderator
|
Свой progressBar
Есть последовательность длительных невложенных операций, которые выполняются при запуске пользователем некой периодической операции. Стандартный прогресс бар мне не понравился и где-то за 20 минут было сделано примерно следующее:
Похоже на прогресс-бар установки 2005 SQL Server-а. Идея простая - форма с набором методов:
Из тонкостей, разве что вызов WinApi::updateWindow(element.hWnd()); в каждом методе. Какие я вижу преимущества по сравнению со стандартным прогрессбаром:
А теперь, когда я весь такой радостный и довольный собой, хотелось бы услышать вал критики подобного решения, дабы не было после мучительно больно за содеянное. |
|
|
За это сообщение автора поблагодарили: TasmanianDevil (2). |
09.08.2007, 13:39 | #2 |
Member
|
Можно вопрос?
Что плохого в стандартном многострочном прогресс-баре (кроме внешнего вида)? Данное решение адекватно работает в режиме удаленного клиента на тонком (имеется в виду пропускная способность) канале (насколько я понимаю, что в стандартном инфологе и прогресс-баре есть алгоритмы оптимизации под тонкий канал)? Т.е. в процессе длительной обработки на сервере будет что-то отрисовываться на клиенте? Или вы стандартный прогресс перерисовали просто? Любопытство, не более.
__________________
С уважением, glibs® |
|
09.08.2007, 13:45 | #3 |
Moderator
|
Цитата:
Что плохого в стандартном многострочном прогресс-баре (кроме внешнего вида)?
Цитата:
Данное решение адекватно работает в режиме удаленного клиента на тонком (имеется в виду пропускная способность) канале
Цитата:
асколько я понимаю, что в стандартном инфологе и прогресс-баре есть алгоритмы оптимизации под тонкий канал
Цитата:
Т.е. в процессе длительной обработки на сервере будет что-то отрисовываться на клиенте?
Цитата:
Или вы стандартный прогресс перерисовали просто?
|
|
09.08.2007, 14:09 | #4 |
Member
|
Цитата:
Сообщение от Андре
...
Ну разве что одна мелочь - ему не верят пользователи. Цитата: "А ты на эту фигню не смотри - он всегда врет, сколько ждать осталось." ... А за счет чего? У стандартной алгоритм очень простой. Общее количество шагов и количество выполненных шагов. А дальше врет оно или не врет во многом зависит от программиста, который эту штуку дергает (сама она к пользователю не ломится). А еще во многом от случая. Например, кто может спрогнозировать высокую загрузку сервера в какой-то момент выполнения длительной операции или блокировку в БД, например. У вашего решения искуственный интеллект или я что-то не понимаю?
__________________
С уважением, glibs® |
|
09.08.2007, 14:32 | #5 |
Мрачный тип
|
Да и пусть даже врет , на самом-то деле .
Расчет оставщегося времени - дело неблагодарное и на 100% не дающее точного результата ввиду теоретически возможной неоднородности временных затрат на каждую обрабатываемую итерацию. Ни стандартный прогресс, ни этот от подобного не застрахованы. По большому счету можно сказать что вредна эта фича, подсчет времени оставшегося, то бишь - лишний повод юзеру камень в огород системы бросить. Фича есть , но работает не всегда правильно - в печку ее Не знаю, как остальные, а я себе подобное реализую, попробовав дополнить столбцом затраченного времени на каждое действие |
|
09.08.2007, 13:50 | #6 |
Модератор
|
Цитата:
__________________
-ТСЯ или -ТЬСЯ ? |
|
09.08.2007, 13:51 | #7 |
Участник
|
Стандартный прогресс бар отрисовывает не кажджую операцию, а только если после последней отрисовки прошло некоторое время. На каждую операцию не гоняются данные между клиентом и сервером
|
|
09.08.2007, 13:52 | #8 |
Участник
|
А где проект?
Я так не играю. Хочется ж и у себя попробовать. Как же критиковать можно, видя лишь картинку?? Картинка, конечно, красивая, и тема виндовая, видимо, подобрана встать. Вопросы: 1. А показывается ли приблизительное общее время? (Как в стандартном прогресс баре, хоть он и врет?) 2. А есть ли updateInterval? или каждый раз при incCount() выполняется перерисовка формы? 3. Что будет если нажать на крестик? 4. Пробовали выполнять класс, использующий эту форму на сервере/клиенте? Как производительсноть? как обмен между клиентом и сервером? |
|
09.08.2007, 13:56 | #9 |
Мрачный тип
|
Мучительно больно быть не должно, ибо очень интересная и полезная вещь.
Но сразу вопросы : 1) поддерживается ли в столбце "прогресс" вывод абсолютных значений (и соответсвенно ручное выставление значения "готово" )? 2) возможна ли автоустановка ширины текстового столбца после передачи списка действий (пока будет работать, пользователь не сможет сам изменить ширину столбца ListView) 3) Насколько менее тормозит отрисовка по сравнению со стандартным прогресс-баром ? |
|
09.08.2007, 13:57 | #10 |
Moderator
|
Цитата:
belugin,Стандартный прогресс бар отрисовывает не кажджую операцию, а только если после последней отрисовки прошло некоторое время. На каждую операцию не гоняются данные между клиентом и сервером
1. В цикле (например while select) вызывается метод формы (doNextStep к примеру) 2. Форма помнит, когда этот метод дергали последний раз и если прошло больше 0.5 секунды, то она отображает изменившийся процент и мигает стрелочкой. То есть, реально метод дергается каждый раз когда выполнен элементарный квант действия, но прорисовка задается параметром (0.5 секунд) |
|
09.08.2007, 14:01 | #11 |
Moderator
|
kashperuk,
Цитата:
А показывается ли приблизительное общее время? (Как в стандартном прогресс баре, хоть он и врет?)
Цитата:
А есть ли updateInterval? или каждый раз при incCount() выполняется перерисовка формы?
Цитата:
Что будет если нажать на крестик?
Цитата:
Пробовали выполнять класс, использующий эту форму на сервере/клиенте? Как производительсноть? как обмен между клиентом и сервером?
|
|
09.08.2007, 14:03 | #12 |
Moderator
|
TasmanianDevil,
Цитата:
Насколько менее тормозит отрисовка по сравнению со стандартным прогресс-баром ?
Цитата:
1) поддерживается ли в столбце "прогресс" вывод абсолютных значений (и соответсвенно ручное выставление значения "готово" )?
2) возможна ли автоустановка ширины текстового столбца после передачи списка действий (пока будет работать, пользователь не сможет сам изменить ширину столбца ListView) Подгонки ширины пока нет. Есть идея и решение написанное за 20 минут. Сейчас по поводу проекта напишу |
|
09.08.2007, 14:14 | #13 |
Moderator
|
Проект не прицепил по 2-м причинам. Во первых, мне казалось все очевидно. Во вторых, проект сильно завязан на другой большой проект, частью которого он является.
Поэтому предложение - я сейчас распишу все куски кода, если что-то будет все-таки не понятно, подготовлю тестовый пример. Итак: 1. Создаем форму, размещаем на ней ListView (listCtrl) 2. На форме создаем методы: class declaration X++: boolean pulse; // для мигания стрелки int timer; // для тайминга прорисовки X++: public void init() { ; super(); listCtrl.addColumn(1, new FormListColumn("Операция", 1, 200)); listCtrl.addColumn(2, new FormListColumn("Прогресс", 2, 80)); imageList = gm_txRegMainClass::createImageList(['gm_archive', 'gm_next', 'gm_back', 'final']); listCtrl.setImagelist(imageList); timer = WinApi::getTickCount(); } Метод, который отображает перечень задач: X++: void setActionList(gm_containerCollection _actions) { gm_ContainerEnumerator enumerator = _actions.getEnumerator(); FormListItem item; int idx; ; while (enumerator.moveNext()) { item = new FormListItem(enumerator.current(), 0); idx = listCtrl.addItem(item); listCtrl.setText(idx, '0%', 1); } WinApi::updateWindow(element.hWnd()); } Метод отображающий прогресс операции: X++: void setPercent(int _idx, str _percent) { FormListItem item; ; item = listCtrl.getItem(_idx); if (WinApi::getTickCount() - timer > 500) { if (pulse) item.image(1); else item.image(2); pulse = !pulse; timer = WinApi::getTickCount(); listCtrl.setItem(item); listCtrl.setText(item.idx(), _percent, 1); WinApi::updateWindow(element.hWnd()); } } Для удобства метод завершения задачи: X++: void setFinalStatus(int _idx) { this.setPercent(_idx, 'Готово'); this.changeImage(_idx, 3); } X++: // Показ формы object initProgressBar(container _steps) { Args args = new Args(); Object formRunObject; FormRun formRun; ; args.name(formstr('gm_reportProgressForm')); formRun = ClassFactory.formRunClass(args); formRun.init(); formRun.run(); formRunObject = formRun; formRunObject.setActionList(new gm_ContainerCollection(_steps)); formRunObject.setCaption('Сбор значений'); return formRunObject; } void run() { progressBar = this.initProgressBar([' Сохранение документа',' Захват значений', ' Учет настроек HQ консолидации',' Составление списка ячеек', ' Удаление старых значений', ' Открытие файла']); this.openDocument(); progressBar.setFinalStatus(0); // мы сделали первую задачу delete_from values where values.ReportId == report.ReportId; progressBar.setFinalStatus(1); // мы сделали вторую задачу num = this.total(); cnt = 0; while select valuesSetup where valuesSetup.ReportType == report.ReportType { this.processCellSetup(valuesSetup.SheetName, valuesSetup.ExcelLabel); cnt++; progressBar.setPercent(2, strfmt('%1', cnt/num * 100) + '%'); // отображаем процесс длиетльной операции } progressBar.setFinalStatus(2); // мы сделали третью задачу // .... Последний раз редактировалось Андре; 09.08.2007 в 14:29. |
|
|
За это сообщение автора поблагодарили: kashperuk (4). |
09.08.2007, 14:20 | #14 |
Moderator
|
Цитата:
Так а эта не врет?
Цитата:
У стандартной алгоритм очень простой. Общее количество шагов и количество выполненных шагов.
Я, кстати, не планировал использовать это решение везде - а только для 1-2 задач, имеющих специфику описанную выше. Кроме того, врет/не врет - не основной (на мой взгляд) плюс решения. Внешний вид - в моем случае это важно. |
|
09.08.2007, 15:47 | #15 |
Member
|
Цитата:
Сообщение от Андре
...
Кроме того, врет/не врет - не основной (на мой взгляд) плюс решения. Внешний вид - в моем случае это важно. ... Насчет врет/не врет я вот чего вспомнил. Один программист (не Аксаптовский, по-моему Джавовский) мне рассказывал, что в документации по инструменту разработки (уж не помню как называется) написано, что прогресс-бар в плане времени врет, и не может не врать. И все программисты об этом знают. И никогда на его оценки не могут рассчитывать. Тем не менее в той книжке настоятельно рекомендовалось прогресс-бары рисовать по возможности всегда, когда это возможно, чтобы пользователь не начинал паниковать (ну типа думать, что что-то зависло, и программу закрывать). Исключительно для сохранения нервов пользователей. Я всегда пользуюсь этим правилом. Далеко не всегда в джобах ставлю .setTotal(). Но текст вывожу всегда. Чтобы знать, что происходит. А уж когда это может закончиться — я могу себе представить. И пользователь сможет, если некоторое время поработает с определенной задачей.
__________________
С уважением, glibs® |
|
09.08.2007, 14:51 | #16 |
Участник
|
А можно:
1. картинки, 2. код метода changeImage 3. GM_containerCollection, GM_ContainerEnumerator (я помню кто-то где-то выкладывал уже, но не нашел). И я бы сделал методы, которые бы пересекались с стандартными. и обертку. Может поиграюсь немного, как время будет. |
|
09.08.2007, 15:00 | #17 |
Участник
|
|
|
09.08.2007, 15:01 | #18 |
Moderator
|
Я приложил проект.
Цитата:
картинки,
Метод создающий imageList: X++: // создает ImageList на основе контейнера, переданных ресурсов static ImageList createImageList(container _con) { ImageList imageList = new ImageList( ImageList::smallIconWidth(),ImageList::smalliconHeight()); Image image = new Image(); ResourceNode resourceNode; int i; gm_reportFolders folders = gm_reportFolders::find(curUserId()); str file, aos_file; ; if ((folders.RecId != 0) && (folders.Icons == gm_reportIcons::None)) return imageList; if ((folders.RecId != 0) && (folders.Icons == gm_reportIcons::Directory)) { for (i=1; i<=conlen(_con); i++) { file = gm_reportSettingsTable::getTempFolder() + '\\' + conpeek(_con, i) + '.png'; aos_file = gm_reportIconDeployer::aos_directory() + conpeek(_con, i) + '.png'; if (!WinApi::fileExists(file)) gm_reportIconDeployer::saveFileOnClient(file, gm_reportIconDeployer::getFileFromServer(aos_file)); image.loadImage(file); imageList.add(image); } return imageList; } for (i=1; i<=conlen(_con); i++) { resourceNode = SysResource::getResourceNode(conpeek(_con, i)); resourceNode.AOTload(); image.setData(SysResource::getResourceNodeData(resourceNode)); imageList.add(image); } return imageList; } Цитата:
код метода changeImage
X++: void changeImage(int _idx, int _image) { FormListItem item; ; item = listCtrl.getItem(_idx); item.image(_image); listCtrl.setItem(item); WinApi::updateWindow(element.hWnd()); } Цитата:
3. GM_containerCollection, GM_ContainerEnumerator (я помню кто-то где-то выкладывал уже, но не нашел).
|
|
|
За это сообщение автора поблагодарили: mazzy (5). |
09.08.2007, 15:04 | #19 |
Moderator
|
Цитата:
mazzy, Работа с длительными операциями
2001-2002 год |
|
09.08.2007, 15:41 | #20 |
Участник
|
Цитата:
Достаточно вызвать SysOperationProgress.setInterval(1000000); Оставшееся время будет обновляться раз в миллион секунд. Если хочется управлять ожидаемым временем самостоятельно, то метод sendTime дает прекрасную возможность порулить этой строчкой вручную. Цитата:
Цитата:
Первый прогресс-бар обычно отображает число выполненных задач Второй и последующие показывают прогресс каждой задачи. Цитата:
ТО SetCount устанавливает проценты А вообще говоря советую посмотреть и тщательно проанализировать форму tutorial_progress. Особенно трехуровневые А также разобраться когда стандартный прогресс не отображает форму (COM, сервер, проверка производительности и т.п.) Но и свои наработки тоже вещь хорошая. |
|