Tommi Prami 130 Posted October 5, 2022 Yo, As windows does the similar thing when doing file operations in explorer, if it start to take time, then it bring s dialog up, and do not flash it if operation is fast (At least sometimes it seems this way). I've been pondering this kind of pattern for a long time. Never tried to code this, but as concept it might be nice, but I have feeling that this is easy to mess up, and for sure easy to kiss some corner cases to have super weird issues, I think. My idea would be something like LLazyProgress := LAzyProgressFactory(ParentFormEtc, lpMarquee, 300); try ... Work finally LLazyProgress.Free; end; If this would be network or file operation, sometimes it might be fast and sometimes very very slow,. And you kind of can't know for sure., My idea was that there would be some, like 300ms delay, if process takes more time than that, progress dialog would show, It could be marquee style, or if progress is more defined and known, could pass some callback for the actual progress and show it, Any thoughts/ideas on this. Mainly if problem with fluctuation of time process takes, sometimes there would be fast flash of dialog for user, and they never could see what was it. Completely different discussion should there be some kind of UI element to show user that progress has finished. -Tee- Share this post Link to post
Lars Fosdal 1792 Posted October 5, 2022 I like these messages that some use instead of a progress bar. A progress bar is linear - while the messages don't necessarily imply a linear time flow. Getting started Putting the ducks in a row Cleanup on isle four Seeing our target Just one more thing We have arrived Share this post Link to post
Tommi Prami 130 Posted October 5, 2022 32 minutes ago, Lars Fosdal said: I like these messages that some use instead of a progress bar. A progress bar is linear - while the messages don't necessarily imply a linear time flow. Getting started Putting the ducks in a row Cleanup on isle four Seeing our target Just one more thing We have arrived I most likely would have more than less both, but slightly off topic... Share this post Link to post
Lars Fosdal 1792 Posted October 5, 2022 Design wise, it depends a lot on whether your app can keep working while progress is ongoing or not. In some places - I just keep a panel hidden on top of the main window and expand it when I need to alert the user to why the app is blocking/busy. The content of that can be messages, a checklist, or a progress bar. Here a launch message "Forbereder oppstart av TineAdmin for Brummundal Test" (Preparing startup of Tine Admin for ...) after the user clicked the TineAdmin icon on the toolbar. This app is a little bit unusual as it doesn't have a main menu - but when it does - and I am blocking - I disable and update it. The benefit of using a panel is that it doesn't interfere with the window functionality when it the operation is non blocking. In other cases, I have a floating window on top with some messages. Here for login progress (Checking version) Share this post Link to post
PeterBelow 238 Posted October 5, 2022 6 hours ago, Tommi Prami said: Yo, As windows does the similar thing when doing file operations in explorer, if it start to take time, then it bring s dialog up, and do not flash it if operation is fast (At least sometimes it seems this way). I've been pondering this kind of pattern for a long time. Never tried to code this, but as concept it might be nice, but I have feeling that this is easy to mess up, and for sure easy to kiss some corner cases to have super weird issues, I think. My idea would be something like LLazyProgress := LAzyProgressFactory(ParentFormEtc, lpMarquee, 300); try ... Work finally LLazyProgress.Free; end; If this would be network or file operation, sometimes it might be fast and sometimes very very slow,. And you kind of can't know for sure., My idea was that there would be some, like 300ms delay, if process takes more time than that, progress dialog would show, It could be marquee style, or if progress is more defined and known, could pass some callback for the actual progress and show it, Any thoughts/ideas on this. Mainly if problem with fluctuation of time process takes, sometimes there would be fast flash of dialog for user, and they never could see what was it. Completely different discussion should there be some kind of UI element to show user that progress has finished. -Tee- Relocate the actual work to a secondary thread. At the start of the thread's Execute method use TThread.Queue to pass a method to the main thread that creates the progress dialog. The dialog is not shown immediately, though, it just starts a timer with the delay you want. If the timer fires before the thread has completed its work, show the dialog. The dialog can the either use a timer to check for the thread's progress at intervals to update its display, or the thread can inform the dialog through Synchronized method calls of its progress. When done it can then tell the dialog to close itself, also through a Synchronized method call. 1 Share this post Link to post
Tommi Prami 130 Posted October 6, 2022 17 hours ago, PeterBelow said: Relocate the actual work to a secondary thread. At the start of the thread's Execute method use TThread.Queue to pass a method to the main thread that creates the progress dialog. The dialog is not shown immediately, though, it just starts a timer with the delay you want. If the timer fires before the thread has completed its work, show the dialog. The dialog can the either use a timer to check for the thread's progress at intervals to update its display, or the thread can inform the dialog through Synchronized method calls of its progress. When done it can then tell the dialog to close itself, also through a Synchronized method call. Relocating actual work to thread, is what I would like to avoid, as it adds quite log extra complexity, like needs new connection to database etc. This why I asked because there might not be good solution without having actual work in a separate thread/task (= thread). For sure having the actual work in separate thread would have its own benefits, like they would crash if they mess around with GUI, but most likely work in legacy app has some GUI updates, that's why it would make it much easier to just keep the work in main thread. So far what I've been pondering that it would need thread, but been thinking that maybe the Lazy progress bar showing logic would be in thread. I thought something like this could work: 1. Have and initialize background thread which waits for progress bar dialog requests. 2. Also create initialize progress bar dialog 3. Request progress bar 3a If progress bar request is still alive and time period is over, show dialog 4. when work is done, ask thread to hide the dialog, if visible at all 5. free the request Needs some thread safety and TEvents or something for signaling and so on. Also Progress bar dialog would naturally be modal, and process messages in a way or other. Share this post Link to post
Anders Melander 1795 Posted October 6, 2022 https://bitbucket.org/anders_melander/better-translation-manager/src/master/Source/amProgress.API.pas and another, slightly older, version of the same: https://bitbucket.org/anders_melander/dwscriptstudio/src/master/Source/amProgress.pas and even a DWScript wrapper (the second & third screenshots are actually from a DWScript): https://bitbucket.org/anders_melander/dwscriptstudio/src/master/Source/ScriptRTL/amScriptModuleUserInterfaceProgress.pas Displays a non-modal form with a progress bar, a status message, and an optional cancel button. Defer the initial display of the progress form (what you call lazy loading). Default delay is 500 mS. Limit rate of progress update to minimize UI overhead. Default is max 1 update per 100 mS. Selectively pumps message queue to avoid application freeze and enable user to move/cancel progress dialog during use. Progressive or marquee mode. The current implementation uses DevExpress label and button controls but these can just be replaced with regular VCL controls without any loss of functionality. Usage: var Progress := ShowProgress('Hello world', False); Progress.EnableAbort := True; Progress.Progress(psBegin, 0, 100, 'Charging flux capacitor...'); for var i := 0 to 100 do begin Sleep(100); Progress.AdvanceProgress; end; and in Marquee mode: var Progress := ShowProgress('Hello world', False); Progress.EnableAbort := True; Progress.Marquee := True; Progress.UpdateMessage('Charging flux capacitor...'); while (not Progress.Aborted) do begin Sleep(100); Progress.AdvanceProgress; end; 5 Share this post Link to post