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 strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Timer & Status Bar 2

Status
Not open for further replies.

LWB

Technical User
Feb 4, 2003
95
US
When I put the working directory files on the server, some things ran a lot slower. A couple of buttons on the main form run a bunch of update queries and then open the form. On a standalone computer this takes maybe a second. On the server it takes maybe 5 to 8 seconds. So I created a "Please Wait" popup form.

I thought it would be neat to put a status bar on it, and I did so. I'm using the timer event to advance the bar. The open for the timer is on the "Please Wait" form and the Killtimer is on the close event. It runs fine by itself. I open the "Please Wait" form at the beginning of the code (pushbutton on the main form) that runs the queries and close it at the end. However, I have to insert sleep commands between the queries for the bar to properly grow in size. Is there a better way? Right now I'm using sleep(100) and the timer is set to 75. I've just chosen a size increment for the bar that results in it approaching max size when the queries are finished.

I know this is rather crude, and I figure there must be a better way. Any advice?

Lynn
 
Lynn,

It depends on how you're running the queries. If they're being run automatically because they're part of the document's data model, there's little you can do.

On the other hand, if you're running the queries via ObjectPAL, then you have a lot of control over the process. simply advance the progress meter between queries.

The reason, by the way, your form runs more slowly from the network is probably sue to the fact that your queries are being run by the local workstation.

Again, depending on how you've set things up, this may mean that you're transferring the entire dataset to the client each time the form is opened. This is especially true if you're using QBE or SQL queries against Paradox tables stored on the server.

You can reduce this startup time by using different techniques to limit the records. For example, a TCursor/setRange can run far more quickly than a query.

To illustrate the possibilities, lets assume that you've written a task tracking system and that your form opens the tickets entered in the last 24 hours.

To do this, you might run a query like this from the form's data model:

Code:
   TICKETS.DB | DateEntered         |
        Check | >= ~( today() - 1 ) |

To speed this up, you could using something like this from a script:

Code:
var
   frm  Form
   foi  FormOpenInfo
   tc   TCursor
endVar

   tc.open( ":data:tickets" )
   tc.switchIndex( "DateEntered" )
   tc.setRange( [ date() - 1, date() ] )
   if tc.nRecords() = 0 then
      msgInfo( "No New Tickets", "No tickets were " + 
               "entered in the last 24 hours.  Go play." )
   else

      ; Warning: Tcursor points to ANSWER after this.  
      ; If you need to massage the original table 
      ; afterward, you need to open it again.

      tc.instantiateView( ":priv:answer.db" )
      sleep()
      foi.masterTable = ":priv:answer.db" )
      foi.Name = "tickets.fsl"
      frm.open( foi )
   endIf

   if tc.isAssigned() then
      tc.close()
   endIf

Now, this is off the top of my head, so may have some typos. But, it illustrates a different, faster way to create an Answer table containing the records of interest.

Now, this does restrict you to those queries that can be specified with a setRange. this may seem like a limitation, but many queries can be expressed as a series of setRange() calls. It's time-consuming, but the performance benfits are amazing. In one case, I used this approach to reduce the startup time of a form from seven minutes to less than one second.

To work this into your other questions, you'd update the progress meter between lengthy operations, e.g. after the setRange calls().

Also, it's always a good idea to sleep() after a lengthy network operation. This lets Paradox "pause" until the process is completed.

Hope this helps...

-- Lance
 
Lance,

Yes the queries (QBE) are run by ObjectPal. And they are fairly complex with most having multiple tables in them. I don't really understand how to do them (or some of them anyway) via a T-Cursor (I have used T-Cursors for editing and lookup).

Actually 7 separate Queries are run (producing new tables that are used in the datamodel of the form that opens at the end (which contains 4 tabs showing different data).

I stuck a sleep(100) after each query to allow the update to the progress bar. I just thought there might be a better way. The timer is set to 75 ms, and the sleep to 100ms. Can I reduce the time?

Yes the code is being executed on the local workstation. I'm sure that it is transferring the entire dataset to the client each time the form is opened.

Since the users have access to this database for informational purposes only (not to edit or add data) the speed is not really critical, I just wanted them to be aware that something is happening after they click on the button.

Still, improving speed would be nice.

Lynn
 
Lynn,

Hm. You may not need a timer. It sort of depends on how you're using the status form.

Forgive me if this seems too basic, but have you considered creating a custom method on your status form, one that updates the meter when called?

I'm assuming you've got something like this:

Code:
var
   fmStatus  Form
   q         Query
   tc        TCursor
endVar

   fmStatus.open( "status.fsl" );
   q = DefineQuery1()
   q.executeQBE()
   q = DefineQuery2()
   q.executeQBE()
   ; etc...

If this is sort of like what you're doing,

Here's one way you might add a custom method:

1. Open the progress form in a Design window.

2. Press Ctrl+Space to open the Object Explorer and make sure you can see tabs running along the right side of the window. (If not, then choose View | Both from the Object Explorer's menu.)

3. Click the Methods tab and then double-click <New Method>. This prompts you for a name; type UpdateMeter and then press Enter.

4. You'll get an editor Window containing the standard lines for methods. Assuming you have a text string (e.g. &quot;Please wait&quot;) and a progress bar, you'll want two parameters for your custom method. with this in mind, consider the following code:

Code:
method updateMeter( strCaption String; siPos SmallInt );

   txtCaption.Text = strCaption
   prgMeter.Pos = siPos
   sleep()

endMethod

This defines a custom method that updates the text of a text object on the form as well as the Pos property of a ProgressMeter OLE control.

5. Save your changes.


Once you do this, you can update the meter using something like this:

Code:
var
   fmStatus  Form
   q         Query
   tc        TCursor
endVar

   fmStatus.open( &quot;status.fsl&quot; );
   fmStatus.updateMeter( &quot;Running Query 1&quot;, 5 )
   q = DefineQuery1()
   q.executeQBE()
   fmStatus.updateMeter( &quot;Running Query 2&quot;, 15 )
   q = DefineQuery2()
   q.executeQBE()
   fmStatus.updateMeter( &quot;Running Query 3&quot;, 25 )
   ; etc...

This should let you ditch the timer completely.

The values you pass as the meter position are arbitrary. Pass whatever seems to make sense in practise.

Hope this helps...

-- Lance

P.S. Custom methods are great ways to extend the capabilities of your forms and provide new features that can be called from other forms, scripts, libraries, etc.
 
Lance,

Wow! That seems like a much better approach.

I am doing something like the define query, execute query steps you show. And I have written a couple of custom methods in the past.

But you are bringing out my ignorance in certain areas. I never heard of the Pos property. I looked that up and discovered there are &quot;trackbars&quot;, which I had never heard of before. I'm at a loss on how to create one however. My progress bar was just a colored box that I was changing the size. This was all based on some code found in Paradox's Help.

But when you refer to the &quot;Pos property of a ProgressMeter OLE control&quot; I'm lost. I think I can use your suggestions to work with my colored box progress bar, but I should learn what this is all about! I really don't have a clue what an OLE control is. Can you elaborate?

Lynn
 
Lance,

I figured out how to get the built in progress bar on my form - I'd swear that Paradox 7 never had these!

But I'm confused about the custom method. I created one attached to the form with the progress bar on it. But it is being called from the main form with the button that runs the queries. That form can't see the custom method since it is on a different form. How do I fix that? And I haven't yet figured out the Pos values and what they need to be to control the progress bar.

Lynn
 
Lynn,

Whoops; I forgot to add something very important (which is what I get for not actually walking through the process as I write these replies.) Sorry.

When calling custom methods from other forms or libraries, you need to tell Paradox to read those external files so it can learn what methods you'll be calling and verify your syntax.

You do this with a USES block. For example, here's some code from a test form I just cobbled together:

Code:
uses ObjectPAL
   &quot;:WORK:PROGRESS.FSL&quot;
endUses

method pushButton(var eventInfo Event)
var
   frm  Form
   str  String
   si   SmallInt
endVar

   if not frm.attach( &quot;Processing...&quot; ) then
      frm.open( &quot;:WORK:PROGRESS&quot; )
   endIf

   if fldCaption.isBlank() then
      str = &quot;&quot;
   else
      str = fldCaption.Value
   endIf

   if fldPos.isBlank() then
      si = -1
   else
      si = smallInt( fldPos.Value )
   endIf

   frm.updateMeter( str, si )

endMethod

In this code, the USES block tells Paradox to open the PROGRESS.FSL form in the current directory. Unlike most other uses of filenames, you need to incluse the file extension, e.g. PROGFORM.FSL.

Now, you can declare USES blocks in a number of places. Each form has a Uses method, as does each object. And, as you see from the above code, you can declare a USES block just above the method that calls the code.

The place you declare the USES controls its visibility (the range of objects, events, and methods that can &quot;see&quot; that declaration). You can do some pretty tricky things by managing the visibility. However, in most cases, declaring the USES in a form's USES block is sufficient.

You do need to declare your USES in each form you use it. Thus, if you create lots of little &quot;helper&quot; forms, it may be necessary to use a library to consolidate the declarations.

Personally, I try to declare my USES blocks as closely to the code that uses them as possible. This makes it easier to use the Clipboard to reuse code written for other forms/applications.

Now, as far as the progress bar goes, they were introduced with Paradox 7.32, though they were called OCX controls in that version. There was a little button on the Object toolbar that switch between the built-in design objects and the OCX objects. In later versions, the objects appear on the ActiveX controls toolbar. Since this isn't normally displayed by default, many people don't even realize they're available.

If you distribute your applications, you may want to avoid using the ActiveX controls, as the controls do need to be registered with Windows.

In your example, controlling teh size of the colored box may actually be a better approach, as that doesn't require any additional control registration on other machines.

I didn't refer to that initially because it's harder to implement up front. Since you've already done that though...

Hope this helps...

-- Lance
 

Lance

Thank you! It works great!

I never used the USES block before.

At the moment I have a &quot;Please Wait&quot; form with two progress bars on it. One my old colored bar and one the Active X progressbar. And I included the text line from your suggestion. It is working fine.

Thanks again. I'd never figure out half of this stuff without you, Mac, and Perrin.

Lynn
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top