Tim Posted January 14, 2015 Posted January 14, 2015 Hi, I am writing a wizard-style application which allows customers to create orders. When the user clicks on the Submit Order button on the last page of the wizard, a series of webservice calls are performed, which can take several seconds in total to complete. I would like to update the display after each webservice call. It seems however that the user interface is not updated until the button's OnClick event handler finishes executing. For example, the following code results in the strings 'one', 'two', 'three', 'four' being written to the memo control all at once after a four-second delay: procedure TMainForm.UniButton1Click(Sender: TObject); begin sleep(1000); UniMemo1.Lines.Add('one'); sleep(1000); UniMemo1.Lines.Add('two'); sleep(1000); UniMemo1.Lines.Add('three'); sleep(1000); end; Is there some way of updating the display in the middle of an event handler? I tried calling UniSession.AddJS('alert("one")') in place of UniMemo1.Lines.Add('one'), but this also doesn't seem to take effect until the event handler is finished. I also tried writing the progress messages to a form variable in TMainForm.UniButton1Click and then polling this variable with a Timer, but changes made to the variable's value don't seem to be visible in the OnTimer event until TMainForm.UniButton1Click is finished. Maybe I need to perform the webservice calls in a background thread, and/or write some javascript code that regularly polls for progress messages? I would be grateful for any insights. Thanks, Tim Quote
zilav Posted January 14, 2015 Posted January 14, 2015 Using UniTimer on client side, it will call your event peridocally and update UI. Quote
Tim Posted January 14, 2015 Author Posted January 14, 2015 Thanks Zilav for the reply. So you mean something like the following code? type TWorkerThread = class(TThread) procedure Execute(); override; end; var Gv_ProgressMessage : string; Gv_ProgressMessageCriticalSection : TRTLCriticalSection; procedure TWorkerThread.Execute(); procedure WriteProgressMessage(AMessage : string); begin EnterCriticalSection( Gv_ProgressMessageCriticalSection ); try Gv_ProgressMessage := AMessage; finally LeaveCriticalSection( Gv_ProgressMessageCriticalSection ); end; end; begin sleep(1000); WriteProgressMessage('one'); sleep(1000); WriteProgressMessage('two'); sleep(1000); WriteProgressMessage('three'); sleep(1000); end; procedure TMainForm.UniButton3Click(Sender: TObject); var WorkerThread : TWorkerThread; begin WorkerThread := TWorkerThread.Create(); end; procedure TMainForm.UniTimer1Timer(Sender: TObject); begin EnterCriticalSection( Gv_ProgressMessageCriticalSection ); try if Gv_ProgressMessage <> '' then begin UniMemo1.Lines.Add( Gv_ProgressMessage ); Gv_ProgressMessage := ''; end; finally LeaveCriticalSection( Gv_ProgressMessageCriticalSection ); end; end; function MainForm: TMainForm; begin Result := TMainForm(UniMainModule.GetFormInstance(TMainForm)); end; initialization Gv_ProgressMessage := ''; InitializeCriticalSection( Gv_ProgressMessageCriticalSection ); RegisterAppFormClass(TMainForm); finalization DeleteCriticalSection( Gv_ProgressMessageCriticalSection ); Or is there maybe a simpler way to do it? Quote
zilav Posted January 14, 2015 Posted January 14, 2015 Oops, forgot that UniTimer doesn't update GUI. Anyway, it is easy just using javascript timer. Made a quick simple demo for you. http://forums.unigui.com/index.php?/topic/4941-threaded-background-job-with-progress-updates-and-user-control/ Quote
Tim Posted January 15, 2015 Author Posted January 15, 2015 Thanks very much for the example! So it is necessary to perform time-consuming operations in a background thread if one wants to display the progress to the user. It was interesting how the updating of the progress bar is performed in the example using AddJS: UniSession.AddJS(Format('MainForm.pg.updateProgress(%d/%d, ''Running...'', true);', [job.Progress, 100])); Instead of setting the control's property directly: pg.Position := job.Progress; I tried using the second way, but then the progress bar advances jerkily. So I'm guessing this creates more HTTP traffic or something. By the way -- how did you know about the updateProgress function? Is there some documentation or special place in the sourcecode where one can look up the javascript functions available for each control? Thanks again, Tim Quote
zilav Posted January 15, 2015 Posted January 15, 2015 The only difference is that js method sets the last parameter to True which means "animate". Normally UniGUI exposes majority of properties in designer but "Animated" is not there yet. If you don't need animation, then just setting Position is easier. Traffic is the same. You can aways check Sencha ExtJS docs for javascript methods and properties on client side. For this particular function http://docs.sencha.com/extjs/4.2.3/#!/api/Ext.ProgressBar-method-updateProgress Quote
Administrators Farshad Mohajeri Posted January 15, 2015 Administrators Posted January 15, 2015 We have new demo ThreadTimer-3 which also demonstrates background thread handling. Quote
Tim Posted January 15, 2015 Author Posted January 15, 2015 Thanks for the information I will have a look at the ThreadTimer-3 demo and the ExtJS documentation. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.