Help with progress metre (1 Viewer)

torz

Registered User.
Local time
Tomorrow, 04:07
Joined
Jun 21, 2014
Messages
73
Hey guys,

Hoping someone could explain how the attached progress metre is supposed to work?
I was trying to use the one with the 2 bars on there...

Basically, I just copied the code from the button that ran the progress metre on their form into my from (which is behind a button as well). also copied the class files and forms across.
The issue is that the progress metre finishes WAAAAAAAAAAAAY before the tasks themsevelves...
Just wondering what I'm doing wrong?


Thanks
 

Attachments

  • MeterWithForms.mdb
    400 KB · Views: 115

torz

Registered User.
Local time
Tomorrow, 04:07
Joined
Jun 21, 2014
Messages
73
Here's another method at Datapig

Thanks :)
I think i remember seeing this one a while back but wouldn't really work in this situation...

The function that the bar is going to be used for the is retreaving a random amount of records from a website adding them to a table & then there is some joining and stuff going on. So the length will be different every time... This one sounded like it would check the number of tasks itself and work it all out automatically, obviously I could be wrong.... not to sure to be honest
 

stopher

AWF VIP
Local time
Today, 19:07
Joined
Feb 1, 2006
Messages
2,395
Thanks :)
I think i remember seeing this one a while back but wouldn't really work in this situation...

The function that the bar is going to be used for the is retreaving a random amount of records from a website adding them to a table & then there is some joining and stuff going on. So the length will be different every time... This one sounded like it would check the number of tasks itself and work it all out automatically, obviously I could be wrong.... not to sure to be honest
There is no logic for determining the length of time in either of the solutions provided by you or jdraw. In the method you have used, the time and steps are artificially generated by the variables PAUSE_MIN_LENGTH (default 0.1 sec), TaskCount and ActionCount. You have to define these according your project i.e. normally you would do the Meter.InitializeTask ActionCount, "Task " & x & " progress..." and Meter.updateTask according to the completion of some activity in your project (rather than artificially looping).

Personally I think the code you are using is rather overkill as much of it is about creating a form on the fly. You might be better off using the method provided by jdraw as it uses much the same principle but with easier to follow and therefore develop code.

hth
Chris
 

smig

Registered User.
Local time
Today, 21:07
Joined
Nov 25, 2009
Messages
2,209
are you sure you send the correct number of tasks (records in you case) to the meter ?
make sure you add a step for every record
 

Frothingslosh

Premier Pale Stale Ale
Local time
Today, 14:07
Joined
Oct 17, 2012
Messages
3,276
I'm surprised you didn't just PM me, since I wrote the bloody thing.

<Edit: WHOOPS, he just posted the class, not his project>

Personally I think the code you are using is rather overkill as much of it is about creating a form on the fly.

In my defense, I included that code just because I have an objection to distributing forms with what is supposed to be a stand-alone class. It's probably irrational, but sometimes I'm a purist. :D

The form creation code is only run if the form doesn't exist, and can be stripped out entirely (along with the existence check) if you want, as long as you have a copy of the form it creates and include that in the project. The rest of the time, it only uses the creation/destruction functions, Initialize, and Update.
 
Last edited:

Frothingslosh

Premier Pale Stale Ale
Local time
Today, 14:07
Joined
Oct 17, 2012
Messages
3,276
Oh, hell, all you posted was the class.





Basically, to make it work, you have to create a class object, then run the Initialize function for the object. This requires the following:
  • The number of actions being performed
    • For a recordset import, that will mean the number of records being imported.
  • The description of the task being performed.
    • "Importing records...." is perfectly fine.
  • Whether or not you want the system to pause between reaching 100% and it closing the form.
    • This is an optional parameter which defaults to TRUE if you skip it.
  • The length of time to pause if the above is true.
    • This is an optional parameter which defaults to 1/10 second if you skip it. This allows the user to just barely see the 100% before the meter form is closed.
Once you've done that, for every iteration of your task (one record loaded, in this case), run the UpdateTask function for the object. The only needed parameter is the ongoing count you're keeping of your task's progress. What I mean by this is that if you just imported your 317th record, then the parameter would be 317.

When you're done, just make sure to explicitly destroy the object.

*****

So for your record download, you would need the total number of records to be downloaded. Another option, if you can't get that but can pull the completion percentage, then just use said percentage.

If you can't get the record count until the load is complete, I'm afraid my meter class isn't the tool for you (nor is the built-in SysCmd meter, unfortunately).

If you have other quesitons (or suggestions), please let me know.

I strongly recommend looking at the test form I included in the download - you can see in it the code I used to control the meter bar.

Edit: It appears that I don't close the form automatically, so you want to either update the Update function so that it does upon reaching 100%, or else destroy the class object once the task is complete. The second is what I normally do, but the former is a change I should probably implement.
 
Last edited:

Frothingslosh

Premier Pale Stale Ale
Local time
Today, 14:07
Joined
Oct 17, 2012
Messages
3,276
*moved here from PM*

torz said:
Thanks heaps for the detailed reply! makes things so much easier for us noobs trying to learn :D

I still have no idea where to start, nor what the difference between putting code in a class, module or form itself is...

When you say I need to create a class object, I have no idea where to start. I have looked at the example like 100+ times but I'm way to new to understand where to start I think... after the reply I think I need to use the code you have in the frmtestmetre form and for the action & task values I need to use either sql or dcount to get the number of records it is going to download.
The download would become the task value & the action would be task x 2 (it will download them & update a different table)

Is that anywhere near close to what I need to do?

Thanks heaps!

Okay for starters, classes are modules that are used to create custom objects. Objects are just 'things' you interact with, such as forms, recordsets, tables, and the like. The clsMeter module is a class module that can be used to create a clsMeter object. Note that the graphic next to the name in your Modules tab is different than in a regular module! With that in your project, in your driver (the code that will be handling the import), you create the meter obejct with something like this:

Code:
Dim Meter as clsMeter

With that, you just created a clsMeter object called 'Meter'. It's just like when you create a recordset object or a form object to reference in your code, except rather than using a built-in object, you're using a custom one. If that's still Greek to you, try doing google searches on 'object-oriented programming' and 'class modules'.

Once you've created the object, you can use it to execute the built-in functions. So with an object you named Meter, you can use Meter.Initialize and Meter.Update. Once you're done, just do "Set Meter = Nothing", and that will close the form and clear the object reference.

Now, for the rest of what you are trying to do:

By downloading, do you mean your user is downloading a file to a local or network folder, or that they are actually importing the records directly into the database? How are you handling the actual import - TransferSpreadsheet? If so, my meter is of no use with that one - for that transfer progress, you're best off just turning on the hourglass and letting Access show its own meters. If you're doing a line-by-line import from a text file or Excel, that's a different matter.

Basically, the meter module simply tracks a single iterative task, and shows progress through the iterations. For example, if you're importing a spreadsheet one line at a time for some reason (say for data cleaning), you can use Excel methods to get the number of lines to be processed, and that gives you a count to work through. You can certainly use the meter to show progress through a series of linked automated tasks, but I didn't include functionality to change the displayed text. (I probably should, but it never occurred to me.)

So I guess the above is my long-winded way to ask this:

What PRECISELY are you doing? I know 'downloading and then updating records', but how are you going about it?
 

stopher

AWF VIP
Local time
Today, 19:07
Joined
Feb 1, 2006
Messages
2,395
I'm surprised you didn't just PM me, since I wrote the bloody thing.

<Edit: WHOOPS, he just posted the class, not his project>



In my defense, I included that code just because I have an objection to distributing forms with what is supposed to be a stand-alone class. It's probably irrational, but sometimes I'm a purist. :D

The form creation code is only run if the form doesn't exist, and can be stripped out entirely (along with the existence check) if you want, as long as you have a copy of the form it creates and include that in the project. The rest of the time, it only uses the creation/destruction functions, Initialize, and Update.
Apologies. What I was trying to say was that the other example might be easier to follow. I actually think the method you've used is cool.

Could you consider adding something to this thread as it's another example of use of classes in Access.

Chris
 

jdraw

Super Moderator
Staff member
Local time
Today, 14:07
Joined
Jan 23, 2006
Messages
15,379
I agree with Chris and was about to suggest the class was relevant to the other thread.
As Chris hinted and frothingslosh augmented, you need to determine, in some manner, the number of "things" you plan to execute/do, and then divide that number by some value to determine how many calls you make to the class, or how many "text boxes" you will use to show progress in your meter.
 

Jibbadiah

James
Local time
Tomorrow, 04:07
Joined
May 19, 2005
Messages
282
I use a lot of progress bars in my forms because I regularly loop through many records (multiple emails, reports, files, etc).
It is good to have the bar to tell the user how things are progressing and it is far better to have a % complete meter than those bullsh*t "night-riderish" moving lights!!
One simple way of doing it is to use the code below (apologies, but don't know who I got this from initially). Rather than having a pop-up form you could also just pop this on your main form and only make both objects visible when a command button is pressed, etc.

On your form put the following:

1. a rectangle called recStatus
Back colour - Green (#00C161)
Border Style - Solid

2. a label called lblStatus
Back Style - Transparent

lblStatus goes over the top of the rectangle.
Both are visible on the form.


'I use the following to calculate 100 points in whatever loop I happen to have based on recordcount.
Code:
lngModulus = Round(lngRecordCount / 100)

'Which is then used by the following if statement to output a message (to a log file) or update the progress bar (or both)

Code:
If ((lngCurrentRow - 1) Mod (lngModulus) = 0) Then

            '-------------------------------PROGRESS BAR FORM-------------------------------

                intPercent = (lngCurrentRow / lngRecordCount * 100 / 1)
                Forms!frmProgress.recStatus.Width = (Forms!frmProgress.lblStatus.Width / lngRecordCount) * lngCurrentRow
                Forms!frmProgress.lblStatus.Caption = Format$(intPercent, "##") & "% complete"
                Forms!frmProgress.lblProgress.Caption = " Creating Application " & lngCurrentRow & " of " & lngRecordCount
                Forms!frmProgress.Repaint
                
            '-------------------------------PROGRESS BAR FORM-------------------------------

	'AddToLog Message
	'You could add DoEvents here

End If

'Sometimes when you do this you may need to consider using doevents to ensure that it updates correctly on the form (instead of the dreaded "Access is not responding"... especially with a heavy duty recordset (updating 1000's of files, etc).
'Beware that doevents will kill your cpu, so use it sparingly - If you just use it in the if statement above it will only get called 100 times.'

Regards,

James
 

Frothingslosh

Premier Pale Stale Ale
Local time
Today, 14:07
Joined
Oct 17, 2012
Messages
3,276
The one big issue is that this code forces changes to the display on every iteration, which by itself can cause severe system lag when you have thousands of iterations to run. You should do something like I put into the class in the OP, so that the screen is only updated when the actual percentage complete changes; updates of less than 1% aren't particularly useful or noticeable.
 

Jibbadiah

James
Local time
Tomorrow, 04:07
Joined
May 19, 2005
Messages
282
See point about modulus... Only updates if condition is true... I.e in example 100 times no matter how big tyhe recordset
 

torz

Registered User.
Local time
Tomorrow, 04:07
Joined
Jun 21, 2014
Messages
73
So I guess the above is my long-winded way to ask this:

What PRECISELY are you doing? I know 'downloading and then updating records', but how are you going about it?

Firstly thanks to you all, it got real interesting really quick :D and I think I have hours of fun ahead of me with all the links now as well!

Okay, so what is happening (I'm sure ther e is a better way like XHTML but haven't worked out exactly how to do it that way yet.)

So people submit a webform with a reference number which is stored along with a bunch of other stuff. Once or twice a day I'd like to click a button and it goes and checks status's and gives updates... Steps it is going through now:

Now go easy on me, I'm really really new :) I KNOW there is a whole bunch of ways that would be much more efficent than this, but I had trouble trying to work it out and just needed something that worked and will come back to speeding it up @ a later date.

1. Sets a recordset that it needs to check
2. Checks each reference number in the rs using ie.navigate "http://blah.blahblah.com/incidentviewer.aspx?incidentnumber=" & rs("iTamNumb")
3. Grabs 6 sections from the page for each rs using lblLastResolvedDate = ie.Document.getElementById("lblLastResolvedDate").innerHTML
4. Puts it into a tempory table
Code:
    CurrentDB.Execute ("INSERT INTO [tempITAM]([iTamNumber], [lblLastResolvedDate], [lblClosedDate], [txtDescription], [txtDetailedDescription], [txtWorkLog], [txtResolution]) " & _
                "VALUES ('" & rs("iTamNumb") & "', #" & lblLastResolvedDate & "#, #" & lblClosedDate & "#, '" & _
                    Replace([txtDescription], "'", "''") & "', '" & Replace([txtDetailedDescription], "'", "''") & "', '" & Replace([txtWorkLog], "'", "''") & "', '" & _
                    Replace([txtResolution], "'", "''") & "' );")
5. Then it will grab sections of each of the mentioned fields in step 4 and depending what the status's are it will shoot an email off to somoene, add it to a seperate table (work queue) and a couple of other things.


The reason I liked the look of the duel metre was because I thought I could break this up into 2 - 3 tasks with a whole bunch of actions (first task downloading, 2nd appending to table & 3rd notifying users) and allow it to show how long each specific task was taking.

I realise I'm probably (am) going the most retarded way about this, being that I'll have to redo a good chunk of it all when I get to work on speeding it up. Just didnt have the time to work it out at the moment :mad:
 

smig

Registered User.
Local time
Today, 21:07
Joined
Nov 25, 2009
Messages
2,209
I really liked this Class method too :)
An addition for an option to change the Text too will be cool.
 

Frothingslosh

Premier Pale Stale Ale
Local time
Today, 14:07
Joined
Oct 17, 2012
Messages
3,276
@torz - Yeah, I've never done what you're attempting, so I'm not really the one to come up with a better way, I'm afraid. Hopefully stopher or jdraw will jump back in if there's a better way.

You could definitely use DualMeter to handle a project like this, just be aware that some things like your Document.get are going to be binary - they're going to have to jump from 0% to 100%. Also, make sure to read the documentation in the code repository for DualMeter, as it is rather more complicated than the Meter class. Also, DualMeter DOES support changing project descriptions on the fly. (That class uses 'projects' and 'tasks' - best way I could describe the two levels.)

@smig - I'll go ahead and post an updated version with Meter.ChangeDesc once I get the time to actually write it. :D The class is posted over in the CodeRepository, along with a how-to and a second class that provides for a dual-meter-bar setup.

Edit: LINKY
 
Last edited:

torz

Registered User.
Local time
Tomorrow, 04:07
Joined
Jun 21, 2014
Messages
73
Thanks to everyone! you all have been great :)

Managed to get it working pretty easy with the single metre, but trying to get the duel to work just didn't seem to make sense to me because of the way I have it working at the moment.
It's basically grabbing the rs count that it needs to check and then grabs the documents for the first record and adds that to the table and moves to the next so its all working in what I'd say is one task at the moment...

I'll look into changing things up at a later date, thanks again to everyone for all the help and links! lots of good reading!
 

Users who are viewing this thread

Top Bottom