Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations biv343 on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Progress Bar Animation - Separate Process? 1

Status
Not open for further replies.

craigsboyd

IS-IT--Management
Nov 9, 2002
2,839
US
I want to be able to have a progress bar for my application that is not tied to the thread currently executing in my application. The reason for this is so the progress bar can show progress as well as some sort of animation (similar to the documents flying from folder to folder that Windows uses). And, this animation will not stop just because VFP is busy crunching a single line of code. The problem as I see it is when a single line of code is executing the process never gets into a wait-state so that the animation can continue. So for a moment or two while that line executes the animation appears to hang, even when animation is provided via ActiveX control. I want the animation to continue somewhat smoothly so the user knows that something is still going on. I have worked with _vfp.autoyield but because the code being executed is a single line setting autoyield to .T. doesn't work. I have some ideas, but thought I would post here and see what everyone else thought might be the best way to go about this. Thanks.

Slighthaze = NULL

[ul][li]FAQ184-2483
An excellent guide to getting a fast and accurate response to your questions in this forum.[/li][/ul]
 
Slighthaze

Are you using AVI for the animation ?

-- AirCon --
 
Aircon,

What I was using was the MS Scriplet control with the URL set to an animated GIF. I am open to suggestions. Whatever the animation is I need it to keep going somewhat smoothly even if my application is seriously crunching some code.

Slighthaze = NULL

[ul][li]FAQ184-2483
An excellent guide to getting a fast and accurate response to your questions in this forum.[/li][/ul]
 
I never have the need to make such animation myself. So this is (purely) just a thought.

If you are using GIF animation maybe it will be the same with using AVI. Even heavier I think.
How about making the process into a VFP COM EXE and perhaps use timer and feed a DoEvents. Is it worth to try ?


-- AirCon --
 
I dunno if a VFP COM EXE will work or not...I know that DOEVENTS won't work though, because my application is running a single line of code there is no place to put the DOEVENTS...there is no wait-state which is why my animation stops to begin with (actually since I am using an ActiveX there is a couple of times that the animation kind of moves, but barely and that is only because i have _vfp.autoyield = .T. I'm thinking I have to create a separate process and feed the progress value over to it, the separate process will also need to check the Windows processes running list to make sure that my application hasn't been shutdown (such as end task) so it doesn't keep running when my application isn't (maybe I can use createprocess API so that I own that process and it will shutdown automatically or something). I agree with you that an AVI will be more overhead...I think the animated gif is ok, just need to find a way to make it continue the animation even when my application is really busy processing. I think with a separate process that I can get windows to take care of that for me. Still looking for ideas before i try to implement this though.

Slighthaze = NULL

[ul][li]FAQ184-2483
An excellent guide to getting a fast and accurate response to your questions in this forum.[/li][/ul]
 
Actually my idea was to create a timer inside the VFP COM and in the timer event feed a DoEvents. All the works is within the COM itself. Or you can also try CreateEvent & SetEvent, then wait for the signal. I'm not sure both ways will work or not.

Using CreateProcess also a good idea. But basically you also have to create a separate VFP exe in order to create another process. So this is almost the same idea with COM EXE, but the results might be different.

One more idea is to use CreateThread or even better CreateRemoteThread. But since VFP lacks of callback function this idea is difficult/impossible to implement from VFP.

Well..I'm run out of idea. I can only wish you good luck
[thumbsup2]

-- AirCon --
 
Slighthaze

The following may help

Create a top-level form, nominal 170 high x 450 wide.

Add the Microsoft Animation Control 6.0 at the top of the form, followed by a label, progressbar, 2 futher labels and a command button, captioned 'Cancel', centred at the bottom of the form.

In pseudo code, the sequence of events is as follows.

Create a cursor and populate it with the path\filenames.ext of the files you want to open/process.

Caption the labels explaining the first record is about to be processed, and indicate the total no of records to be processed.

SCAN

DOEVENTS()

WITH THIS
[tab].oleFileMove.Open([avi\filemove.avi])
[tab].oleFileMove.Play()
ENDW

Open file with ShellExecute() or CreateProcess() if you want the external process to retain control until a specific process is complete.

Update progressbar

Recaption labels showing progress

INKEY(0.01)

ENDS

Recaption labels showing completion

INKEY(1.0)

Release the form


The INKEY()s are there to pause execution to enable the labels to accept the new captions and effectively 'refresh' themselves, (and no, you cannot refresh a label as such!).

faq184-2366 How can I create a progressbar in a form?

will give you the code to build an in form progressbar.

I use variants of this form whenever external applications or files are being opened even if only one file is being opened. It reassures the user that something is happening and also allows them to cancel out if required.

FAQ184-2483 - the answer to getting answered.​
Chris [pc2]
 
Aircon - COM Server EXE was indeed the ticket to getting this

Chris - I did make the progress bar form a top level form always on top - problem wasn't being able to show progress indication, it was having animated GIF run smoothly and I needed the progress class in a separate process from my application to achieve that. DOEVENTS and _VFP.Autoyield = .T. would not work in this case.

Thank you to both for taking the time...


I think I've got it...I created the progress thermometer as an out-of-process Automation Server (.exe file). I just moved the class that I was already using over to a new vcx in a new project and defined the class as OLEPUBLIC. Since it is out-of-process the animated GIF keeps going smoothly even when my application is indexing a huge table (just an example) - because now my progress bar is running in a separate process from the application. From within my application to use this new progress bar I do something like:

MyBar = CREATEOBJECT("progress.clsprog")
MyBar.Visible = .t.
...start some heavy duty code - almost 100% CPU
MyBar.update(25,"Backing Up Data")
...some more heavy duty code
MyBar.update(50,"Backing Up Data")
...some more heavy duty code
MyBar.update(75,"Backing Up Data")
...finishing up heavy duty code
MyBar.complete()
Release MyBar

It works like a charm. I will provide an example of this soon if possible (maybe FAQ)...I think this is useful stuff. There is only one drawback, it takes a moment for the MyBar = CREATEOBJECT("progress.clsprog") line to execute since windows has to start a new process for it. But the delay is minimal and the effect is worth it in my opinion.

Slighthaze = NULL

[ul][li]FAQ184-2483
An excellent guide to getting a fast and accurate response to your questions in this forum.[/li][/ul]
 
slighthaze

'DOEVENTS and _VFP.Autoyield = .T. would not work in this case.'

If the form variant being used is to open applications/files, then I dispense with DOEVENTS and use the following code within the SCAN...ENDSCAN loop, initialising the form with the command button 'Cancel' disabled.

WITH .cmdCancel
[tab].Enabled = .T.
[tab].Refresh()
ENDW

lnSeconds = SECONDS()
DO WHILE .T.
[tab]inval1 = INKEY(0.06,[HM])
[tab]IF SECONDS() > lnSeconds + 2
[tab][tab]EXIT
[tab]ENDI
[tab]IF inval1 = 151
[tab][tab]llExit = .T.
[tab][tab]EXIT
[tab]ENDIF
ENDD

WITH .cmdCancel
[tab].Enabled = .F.
[tab].Refresh()
ENDW

IF llExit
[tab]llExit = .F.
[tab].cmdCancel.Click()
ENDI

This allows about a second in every iteration for the user to click on the form - it's not necessary to actually hit the command button.

The click event of the command button queries the user as whether or not he/she/it actually wants to cancel the processing and acts accordingly.

The user can see when a cancellation is possible, ie between processes, and it removes the frustration of endlessly clicking without anything happening!

FAQ184-2483 - the answer to getting answered.​
Chris [pc2]
 
Chris,

I agree with you that it is important to give the user an opportunity to cancel a progress such as the one you have laid out. But in my case I am looking for something that will keep the animation on the progress form running smoothly while my VFP Application executes individual lines of code...a single line may take several seconds to execute...creating an index on the table or a PACK statement. There is nowhere in a single statement that a wait-state occurs so that the progress bar can be advanced or the animation (documents flying across like in windows explorer progress indication). So the progress bar form in this instance must be created in a separate process. The problem is not advancing the actual progress bar or giving the user a way to cancel the operation, it is just being able to keep the animation running smoothly on the progress bar form. I should have my example done shortly and I will post it so you can see what I am talking about.

Slighthaze = NULL

[ul][li]FAQ184-2483
An excellent guide to getting a fast and accurate response to your questions in this forum.[/li][/ul]
 
Take the code below and cut-n-paste it into a prg file. Then add that prg file to a project and compile it to "MyApp.Exe" (or whatever). You will end up with a out-of-process Automation server and it will automatically be registered on your machine.

I know the browser control is lame for animation, but I wanted an example you could run right out of the box (you do need internet access since the animated GIF is on my server) If you wanna see what it is going to look like before you compile it into a COM Server EXE then uncomment the top 3 lines of code and run the prg from inside VFP.

*!* PUBLIC oForm
*!* oForm = CREATEOBJECT("progress")
*!* oForm.visible = .t.

DEFINE CLASS progress AS form OLEPUBLIC

Height = 87
Width = 450
ShowWindow = 2
ShowInTaskBar = .F.
DoCreate = .T.
AutoCenter = .T.
BorderStyle = 2
Caption = "Operation Progress"
ControlBox = .F.
Closable = .F.
MaxButton = .F.
MinButton = .F.
ClipControls = .T.
TitleBar = 1
AlwaysOnTop = .T.
SizeBox = .F.
ZoomBox = .F.
ColorSource = 0
Name = "progress"

*-- Specifies the current state of a control.
value = .F.
max = .F.
min = .F.

ADD OBJECT olecontrol1 AS olecontrol WITH ;
Top = -21, ;
Left = 0, ;
Height = 200, ;
Width = 75, ;
Name = "Olecontrol1", ;
OleClass = "Shell.Explorer.2"

ADD OBJECT olecontrol2 AS olecontrol WITH ;
Top = 33, ;
Left = 74, ;
Height = 27, ;
Width = 348, ;
Name = "Olecontrol2", ;
OleClass = "MSComctlLib.ProgCtrl.2"

ADD OBJECT label1 AS label WITH ;
AutoSize = .F., ;
Alignment = 2, ;
BackStyle = 0, ;
Caption = "0%", ;
Height = 17, ;
Left = 74, ;
Top = 60, ;
Width = 348, ;
Name = "Label1"

ADD OBJECT label2 AS label WITH ;
AutoSize = .F., ;
Alignment = 0, ;
BackStyle = 0, ;
Caption = "Current Task...", ;
Height = 17, ;
Left = 74, ;
Top = 12, ;
Width = 348, ;
Name = "Label2"


PROCEDURE Init
this.olecontrol1.navigate(&quot;about:<html><body scroll='no'><img src=' ENDPROC

PROCEDURE update
lparameters nValue, cTask

this.value = nValue

IF PCOUNT() > 1
THIS.Label2.Caption = cTask
endif
ENDPROC


PROCEDURE value_assign
LPARAMETERS vNewVal
this.label1.Caption = ALLTRIM(STR(INT((m.vNewVal/this.max)*100))) + &quot;%&quot;
this.olecontrol2.value = m.vNewVal
ENDPROC


PROCEDURE max_access
RETURN this.olecontrol2.max
ENDPROC


PROCEDURE max_assign
LPARAMETERS vNewVal
this.olecontrol2.max = m.vNewVal
ENDPROC


PROCEDURE min_access
RETURN this.olecontrol2.min
ENDPROC


PROCEDURE min_assign
LPARAMETERS vNewVal
this.olecontrol2.max = m.vNewVal
ENDPROC


PROCEDURE value_access
RETURN this.olecontrol2.value
ENDPROC


ENDDEFINE

Example for using it once you have compiled it, in the command window execute the following lines

oProgress = CREATEOBJECT(&quot;MyApp.Progress&quot;)
oProgress.Visible = .t.
oProgress.update(25,&quot;Packing Data...&quot;)
oProgress.update(47,&quot;Indexing Data...&quot;)
oProgress.update(83,&quot;Backing Up Data...&quot;)
oProgress.update(100,&quot;Complete...&quot;)
Release oProgress


Slighthaze = NULL

[ul][li]FAQ184-2483
An excellent guide to getting a fast and accurate response to your questions in this forum.[/li][/ul]
 
slighthaze

Interesting stuff, but I don't follow what problem you have with starting and stopping the avi file and 'being able to keep the animation running smoothly on the progress bar form'?

WITH THIS
.oleFileMove.Open([avi\filemove.avi])
.oleFileMove.Play()
ENDW

will start the animation

Process code goes here

Progressbar shows 100%

THIS.oleFileMove.Stop()

will stop the animation.

Release the form

FAQ184-2483 - the answer to getting answered.​
Chris [pc2]
 
Chris,

Say you have an application and in that application you have created a progress indication class. This class is a modeless form with a progress bar and animation. Now in your application you are running a your Packing procedure. First you call your progress bar class so it will show the user the percentage complete on packing all tables and then you begin to pack the tables. Now everytime you issue PACK on your larger tables (let's say 32mb and above) you will see that the animation on the progressbar bar slows to a crawl or stops because the process is unable to do both the PACK and the animation at the same time smoothly. At least that has been my experience. Maybe on a new PC this wouldn't happen, but alot of my users will be running PC's with about 128mb ram and 300 mhz CPU and the graphics card is nothing special. Maybe I am the one that is missing something.

Slighthaze = NULL

[ul][li]FAQ184-2483
An excellent guide to getting a fast and accurate response to your questions in this forum.[/li][/ul]
 
slighthaze

I use the following code within the SCAN... ENDSCAN loop.

WITH THIS
.oleFileMove.Open([avi\filemove.avi])
.oleFileMove.Play()
ENDW

Technically wrong, but when combined with INKEY(n) to force the pseudo refreshes of labels etc, seems to prevent the behaviour you describe.

FAQ184-2483 - the answer to getting answered.​
Chris [pc2]
 
Hi,

I realize this is an old thread but I followed SlightHaze's instructions and created an EXE to generate my progress bar. It works perfectly on my machine where I compiled the exe.

HOWEVER, it won't work on another workstation where I am logged on with Admin Rights but VFP8 is not installed. I receive an error message OLE ERROR CODE 0x80040111 CLASS FACTORY CAN'T SUPPLY REQUESTED CLASS

I have done the following with no success:
1. Added it to the INNO setup as an exe and it registers without incident.
2. Regsvr32 with the file as an exe but of course it won't register.
3. Recompiled the Project as a single thread dll (and tried as a multi thread dll) and registered the dll on the workstation successfully.

Any ideas would be greatly appreciated,

Michael
 
i am unfamiliar with the INNO setup, so bear with me here...when you say it is registered on the other machine do you mean that the equivalent of:

MyProg.exe /regserver

...has been run on that machine?


Also, are you certain that all the needed VFP8 runtimes are installed on the other machine? Reason I ask this question is you said the workstation does not have VFP8 installed and it works on the one that does.



Slighthaze = NULL
craig1442@mchsi.com
&quot;Whom computers would destroy, they must first drive mad.&quot; - Anon​
 
Thanks for the quick reply,

It did install the Run Time Files in the correct places (I verified with the reference list in Wiki) but it appears that it did not register the ProgressBar.

After I registered it using the method you suggested it was fine. I feel incredibly stupid but I had never known how to register an exe manually.

Is there a command I can do to programmatically run the ProgBar.exe /regserver when I start up my application?

Will it hurt to run that each time the app is started?

Thank you for your help again,

Michael
 
Hmmmmm...I don't see why you couldn't do this through code. No it wouldn't necessarily hurt anything, but there has to be a better way. You need to basically check if it is registered and then if it is not register it. This process could in my mind take as much time and resources as just going ahead and registering it every time. I though you might include a .BAT file that would do it and then when it has run delete the file so you only have to check if the file is there or not when you run your app, but the problem with that is that you cannot be completely sure that the BAT ran successfully, so you may still end up with a problem...though the likelihood of this happening is slight if it is done right. I am a little shocked that this INNO setup whatever it is doesn't know how to register COM Servers. My answer for right now is that I don't know what is the best solution to your problem...i suspect there is a better way than what has been proposed so far.

As for feeling stupid, you should have seen me the first time I tried to make a COM Server. I was floundering and looking dumb with the best of them.

Slighthaze = NULL
craig1442@mchsi.com
&quot;Whom computers would destroy, they must first drive mad.&quot; - Anon​
 
Hi,

I'm sure it is something stupid I was doing. I was able to add a cmd file as a postprocessor file that will register the exe.

I have just been lazy and not learned how to do so much stuff I should know how to do. Anyway, crisis averted. Onward and Upwards.

BTW, I do like the Progress Bar very much.

Michael
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top