Logo

Hacker’s Guide to Visual FoxPro
An irreverent look at how Visual FoxPro really works. Tells you the inside scoop on every command, function, property, event and method of Visual FoxPro.

OpenTables, CloseTables

These methods of the Data environment open and close the tables listed there.

Usage

PROCEDURE oDEObject.OpenTables
PROCEDURE oDEObject.CloseTables

By default, OpenTables opens all the tables and views listed in the Data environment and establishes the specified relations among them, while CloseTables closes them. You can override this behavior with your own code. However, opening and closing tables and views is part of the default behavior for these methods—that means they’ll do it unless you put NODEFAULT in your version of the method.

OpenTables is sensitive to the value of OpenViews. That property determines whether OpenTables opens all views, no views, or just local or remote views.

If AutoOpenTables is .T., OpenTables is called implicitly at startup of the object (form, formset, report or label). Similarly, AutoCloseTables set to .T. means that CloseTables is called automatically.

You can also call OpenTables and CloseTables in code.

The firing order of OpenTables and BeforeOpenTables is seriously confusing. Any custom code in OpenTables fires first, then BeforeOpenTables fires, then the actual opening of tables that’s the default behavior of OpenTables occurs. We think BeforeOpenTables is misnamed and should actually be called BeforeAutoOpenTables, but we do see that 20 characters is just a little long for a method name.

What’s going on here is that OpenTables and CloseTables are really unique among all the events and methods of Visual FoxPro. Technically, they’re methods, but in some ways they behave more like events. Having AutoOpenTables set to .T. causes the OpenTable method to fire automatically like an event and unlike any other methods. OpenTables and CloseTables need to be in a special category all by themselves.

The biggest consequence of the relationship between OpenTables and BeforeOpenTables is that there’s not much reason ever to use BeforeOpenTables. You can put the same code in OpenTables and it’ll run before the tables open.

You might wonder when you’d want to override the default behavior of these methods. The most important case is to use a single form with different databases. The Database property of a cursor in the Data environment has a hard-coded path. You have to change it at runtime if you want to refer to a different database than the one you used when you created the DE. You can do that in code. But, if the choice of database is based on something else in the form, say a parameter, you can’t make the change until after the form is initialized. In that case, you can put code in OpenTables to change the database property of each cursor (either specifically or by looping to find them). In the Form’s Init method, you can explicitly call OpenTables. Your code to change the database reference executes first, then the default of opening the tables occurs, using the newly specified database. (Of course, you may prefer to put this code in Init rather than OpenTables, so you can do it once in a form class and be done with it.)

Example

* In a very simple version of the case described above,
* the form's Init method might be:
PARAMETER cWhichDBC

* WhichDBC is a custom property of the form
This.WhichDBC=cWhichDBC
ThisForm.DataEnvironment.OpenTables()

* If there are two tables in the DE,
* the OpenTables method might look like:
This.Cursor1.Database=ThisForm.WhichDBC
This.Cursor2.Database=ThisForm.WhichDBC

* Be sure to set AutoOpenTables to .F. in the Property Sheet

OpenTables doesn’t need to include the USE or SET RELATION commands because that happens automatically when the method is called. A form with this structure can even be called and told to use the OPEN DATABASE by passing DBC() for the parameter.

In real code, you’d want to use AMEMBERS() and a loop to change the cursor’s database properties, rather than hard-coding. Similarly, the Init would probably do some checking on the parameter to make sure it refers to a real DBC and perhaps even to ensure that the necessary tables exist in that DBC.

Another time to put code in OpenTables is to create indexes on the fly for views. You can set things up so that the tables and views open, and then you do some indexing. The code looks like this:

* First, make the tables and views open right away
NODEFAULT  && Prevent the table opening from running at the end of the method
DoDefault() && Make the table opening happen right now
SELECT SomeView
INDEX ON SomeField TAG SomeTag

You can use the same approach to do any other kind of thing that should happen as soon as the tables have opened.

See Also

AfterCloseTables, AutoCloseTables, AutoOpenTables, BeforeOpenTables, OpenViews