Thư viện tri thức trực tuyến
Kho tài liệu với 50,000+ tài liệu học thuật
© 2023 Siêu thị PDF - Kho tài liệu học thuật hàng đầu Việt Nam

1001 Things You Wanted To Know About Visual FoxPro phần 8 potx
Nội dung xem thử
Mô tả chi tiết
Chapter 10: Non-Visual Classes 321
Reading the data from the specified source into the form's cursor is handled by the custom
ReadFile() method as follows:
LOCAL ARRAY laTfer[1,2]
LOCAL lcSceFile, lcOldFile
WITH ThisForm
*** Check the source file, clear cursor if a new file is being created
IF .chkSource() > 0
IF EMPTY( ALLTRIM( .txtFName.Value ) )
*** Creating a new file - just return
ZAP IN curIniFile
.RefreshForm()
RETURN
ENDIF
ELSE
*** Source file check failed!
RETURN
ENDIF
*** Specified source is OK, so gather full path and file name
lcSceFile = ALLTRIM( ADDBS( .txtDir.Value )) + ALLTRIM( .txtFName.Value )
IF JUSTEXT( lcSceFile ) = "DBF"
*** It's a table, so just read it into an array
SELECT heading, item FROM (lcSceFile) ORDER BY sortorder INTO ARRAY laTfer
ELSE
*** It's an INI File (maybe). So read it
goIniMgr.ReadIniFile( @laTfer, lcSceFile )
ENDIF
*** Clear Cursor and Copy results in
ZAP IN curIniFile
INSERT INTO curIniFile FROM ARRAY laTfer
*** Strip off heading "[]" - they will be re-written anyway
REPLACE ALL heading WITH CHRTRAN( heading, '[]','') IN curIniFile
.RefreshForm()
ENDWITH
Writing the data out from the cursor is handled in the custom WriteFile() method as
follows:
LOCAL ARRAY laTfer[1,2]
LOCAL lcOldFile, lcDestFile
WITH ThisForm
*** Must have a destination
IF EMPTY( .txtDestFName.Value )
MESSAGEBOX( 'An output file must be specified!', 16, 'Unable to Continue')
.txtDestFName.SetFocus()
RETURN
ENDIF
*** We have a destination
lcDestFile = ALLTRIM(ADDBS(.txtDestDir.Value)) + ALLTRIM(.txtDestFName.Value)
*** Delete the File if it already exists
IF ! FILE( lcDestFile )
DELETE FILE (lcDestFile)
ENDIF
*** Now create a new, empty file ready for writing to
*** We need to do this to ensure that deletions get made properly
lnHnd = FCREATE( lcDestFile )
322 1001 Things You Always Wanted to Know About Visual FoxPro
IF lnHnd < 0
MESSAGEBOX( 'Unable to create new file ' + CHR(13) ;
+ lcDestFile, 16, 'Cannot Contuinue')
RETURN
ELSE
FCLOSE(lnHnd)
ENDIF
*** Now write the new file - ignore empty "heading" fields
SELECT * FROM curinifile WHERE ! EMPTY(heading) INTO ARRAY laTfer
WITH goIniMgr
*** Write file contents
.WriteIniFile( @laTfer, lcDestFile )
ENDWITH
*** Clear Cursor
ZAP IN curIniFile
.RefreshForm()
ENDWITH
How to select a different work area, OOP style! (Example:
ChgArea.prg)
One of the most frequently written snippets of code, in almost any application, looks
something like this:
*** Save Current work area
lnSelect = SELECT()
*** Select Required Area
IF ! USED( <Alias> )
USE <table> IN 0 AGAIN ALIAS <Alias>
ENDIF
SELECT <New Work Area>
*** Do Something There
…
<commands>
…
*** Return to original work area
SELECT (lnSelect)
Now, admittedly, this is not really very difficult, but it or some variant is repeated many
times in an application. We really should be able to do better than this now that we have all the
power of Object Orientation behind us and indeed we can.
Overview
The SelAlias class is designed to accept the alias name of a table as a parameter and switch to
that table's work area. If the table is not open it will open the table for us. More importantly it
will 'remember' that it opened the table and will, by default, close it when it is destroyed. The
class provides support for an additional parameter which can be used to specify an alias name
when it is necessary to open a table with an alias other than the real name of the table.
Chapter 10: Non-Visual Classes 323
The class has no exposed properties or methods and does all of its work in its Init and
Destroy methods. By creating an object based on this class, and scoping it as LOCAL, we need
never write code like that shown above again.
A word on creating the selector object
A selector object may be created in the usual way by first loading the procedure file into
memory and then using the CreateObject() function whenever an instance is needed. However,
Version 6.0 of Visual FoxPro introduced an alternative method, using the NewObject()
function, which allows you to specify the class library from which a class should be
instantiated as a parameter. While it is marginally slower, it does mean that you do not need to
load and retain procedure files in memory and is useful when you need to create an object 'on
the fly', like this one. The syntax for both methods is given below. (Note that with
NewObject(), if the class is not a visual class library, Visual FoxPro expects both a 'module or
program' name as the second parameter and either an application name or an empty string or a
NULL value as the third.)
*** Using CreateObject()
SET PROCEDURE TO selalias ADDITIVE
loSel = CREATEOBJECT( 'xSelAlias', <Alias>, [|<Table Name>])
*** Using NewObject()
loSel = NEWOBJECT( 'xSelAlias', 'selalias.prg', NULL, <Alias>, [|<Table Name>])
One word of caution – if you use multiple instances of this class in the same procedure or
method to open tables, either ensure that all objects are created from the same work area or that
they are released in the reverse order to that in which they were instantiated. If you do not do
this you could end up in a work area that was selected as a result of opening a table but which
is now empty.
How the selector class is constructed
As mentioned in the overview this class has no exposed properties or methods and does all of
its work in its Init or Destroy methods. Internally it uses three protected properties to record:
• the work area in which it was instantiated
• the alias of the table it is managing
• whether the table was already open on instantiation
The selector class Init method
The Init method does four things. First it checks the parameters. An alias name is the
minimum that must be passed, and in the absence of the optional second parameter – the table
name, it assumes that the table is named the same as the alias. If passed, the table name may
include an extension and may also include a path. (Notice the use of ASSERT in this part of the
method. The objective here is to warn developers of errors that may arise in the calling syntax
without impacting the run time code.)
324 1001 Things You Always Wanted to Know About Visual FoxPro
PROCEDURE INIT( tcAlias, tcTable )
LOCAL llRetVal
*** No Alias Passed - Bail Out
IF ! VARTYPE( tcAlias ) = "C"
ASSERT .F. MESSAGE "Must Pass an Alias Name to Work Area Selector"
RETURN .F.
ENDIF
tcAlias = UPPER( ALLTRIM( tcAlias ))
IF VARTYPE( tcTable ) # "C" OR EMPTY( tcTable )
tcTable = tcAlias
ELSE
tcTable = UPPER( ALLTRIM( tcTable ))
ENDIF
Next, it checks the currently selected alias. If this is already the required alias, it simply
returns a value of .F. and the object is not instantiated. The reason is simply that if the table is
already open and selected, there is nothing for the object to do anyway:
*** If already in correct work area - do nothing
IF UPPER(ALLTRIM( ALIAS() )) == tcAlias
RETURN .F.
ENDIF
Then it determines whether the required alias is already in use and, if not, tries to open the
table under the specified alias. If it succeeds it sets its 'lWasOpen' property to .F. This allows
the same table to be opened more than once under different aliases. If the table cannot be
opened, a value of .F. will be returned and the object will not be instantiated. (NOTE: A
"production" version of this class should also check that the file exists, and that it is a valid
Visual FoxPro table, before attempting to open it with a USE command. Such code has already
been covered elsewhere and has been deliberately omitted from this class to keep it as simple
as possible. See the ISDBF() function in Chapter 7, "How to compare the structures of two
tables" for one solution.)
*** If Specified Alias not open - Open it
IF ! USED( tcAlias )
USE (tcTable) AGAIN IN 0 ALIAS (tcAlias) SHARED
*** And Check!
llRetVal = USED( tcAlias )
*** If Forced Open, Note the fact
IF llRetVal
This.lWasOpen = .F.
ENDIF
ELSE
llRetVal = .T.
ENDIF
Finally it stores the currently selected work area number and the alias name to its
'nOldarea' and 'cAlias' properties and switches to the required work area. The object is,
therefore, only instantiated when everything has worked as expected:
*** IF OK, save current work area and
*** Now Move to the specified Work Area