- What is a behavior class or object?
A behavior class is a utility class that implements
something that needs to be done in a reusable way.
For example FormResizeBehavior is a behavior class
that resizes all controls on a form when the form
itself is created. The core components like the
application, form and UI control classes rely on
behavior objects to do most of the work.
- How can I change between identical databases while an application is running?
To do this you need to cange the DataBase property of the cursors
inside the forms data environment before the data is opened. To do this you can do the following:
-
Create a property cActiveDatabase in the Application class and fill it with the required database
-
DEFINE CLASS DataSwitcher AS BaseDataBehavior
METHOD Init
*
* Switch between databases at form load time
*
* Parameters:
* toForm : The form
*
LPARAMETERS toForm
LOCAL ARRAY laCursors[1]
LOCAL loDE, loCursor, lnCount, lnI
*
* Get a handle on the forms DE
*
loDE = toForm.DataEnvironment
*
* Close open tables, better performance with AutoOopenTables = .F.
*
loDe.CloseTables()
*
* Get an array of the contained objects
*
lnCount = AMEMBERS(laCursors, loDe, 2)
FOR lnI = 1 TO lnCount
*
* Get the object
*
loCursor = EVALUATE('loDe.' + laCursors[lnI])
IF loCursor.BaseClass = 'Cursor'
*
* Change the database only for cursors
*
loCursor.Database = goApp.cActiveDatabase
ENDIF
ENDFOR
*
* Open the tables
*
loDe.OpenTables()
RETURN DoDefault(toForm)
ENDDEFINE
- What do you mean with "Running the application in developers mode"?
When the application is run from the VFP command line
with one parameter .T. the application is started in
a special way. What happens is that the application
object and the whole environment is created except
for the main menu which is not replaced and no READ
EVENTS is executed. The result is an application in
the background allowing the developer to modify and
test forms much faster. Instead of having to modify
a form, run the application, choose the form, test
the form and stop the application cycles the
developer can now run the form from the designer
and still have all the normal functionality like
toolbars, menus, security and more.
To start an application first build the application
with BUILD APP <app> FROM <app> and then
run it DO <app> WITH .T. or and this is even
faster you can do the following DO Main WITH .T.
after first making sure the path is set. Selecting
Setup.prg in the project manager and clicking on the
Run button does this.
- Can I add my own behavior classes to the application framework?
Yes. Just create a subclass of the type of behavior class you want to
create add your code. Save the class in one of your own class libraries
and not in one of the standard framework class libraries. The standard
application framework class libraries always start with an "s" to
indicate that they are standard classes.
- Do I need DoDefault in my behavior classes?
This depends. If you create the kind of behavior class that fully
implements something you don't use DoDefault() but if your behavior
class implements some addition to another behavior you need to call
DoDefault with the same parameters as your method received.
For example: The FormResizeBehavior doesn't have a DoDefault in the
FormResize method as it completely implements the forms resize
behavior. It would not make sense to have two separate objects do
some thing similar. On the other hand is the StartStopEdit behavior
class. This class switches the form from edit to view mode when the
data is saved. As it doesn't know how to save itself it does a
DoDefault to save the data and depending on the result switches the
form to view mode or lets it remain in edit mode.
- How do I create a modal dialogue?
Creating a modal dialogue is best achieved by creating a form based
on the ReturnForm class in sForms.vcx. The easiest way to use a modal
dialog that ask the user for some input is done by placing the following
code in the OK button: ThisForm.Hide() and in the Cancel button:
ThisForm.Release(). Using this the form will still exist when the user
chooses OK while it won't when the user chooses cancel. This makes it
very easy to retrieve the users data in the following way:
LOCAL loForm
loForm = CreateObject(<dialogue class>)
loForm.Show(1)
IF TYPE("loForm") = "O" AND !ISNULL(loForm)
* OK do whatever
loForm.Release()
ELSE
* Cancel
ENDIF
- I have my own UI controls, can I use them with the framework?
Sure. The framework comes with a complete set of UI controls called c… in
sBase.vcx that implement some basics like a self-check and a Release()
method. A more complex set of UI controls implementing the behavior mechanism
called b… can be found in sControl.vcx . However the framework's classes are
not dependent on these classes and there is no problem if you ignore them and
user your own classes.
- What sort of file naming conventions do you use?
To separate between the type of class library I use a different
start letter. Although you don't need to use the same conventions
I do advise you don't create or modify class libraries starting
with an "s" to avoid possible conflicts.
-
Class libraries starting with an "s" are the standard classes.
These are part of the framework core and should never be changes.
-
Class libraries starting with a "c" are customer specific classes.
These class libraries contain subclasses of the framework or other
more specialize classes that are used for a particular customer in
more than one application.
-
Class libraries starting with an "a" are application specific classes.
These classes, like Application, are used in only one project.
- Where do I requery a view with child records?
The BaseForm class contains a Requery() method that is called every
time the user navigates through the data. This is called after he
has skipped to a new record but before the controls are refreshed
so this is the place to requery child views.
- I am doing an SQL on al companies starting with a small letter "b" but the cursor also contains customers starting with a "B"?
The default setting for SET COLLATE in the framework is GENERAL.
This means that the test "a" = "A" returns. To prevent this from
happening in a SQL select use the SELECT * FROM Customer WHERE
Cust_Id LIKE "a%" syntax.
The reason for this setting is that it makes it easier for user
to search in data as they don't need to take care of the case and
you don't need to create index tags on UPPER().
- I am using SQL select but my query takes a long time?
Try using the SYS(3054) function to check is the SQL select is Rushmore
optimized. If it is not make sure you have an index tag on the expression
used and that the index tag is create while the collate sequence was
general. Rushmore only uses index tags that are create with the same
collate sequence. You can use DISPLAY STATUS to check the collate
sequence of an index tag.
- How does one Requery() method in the BaseForm class?
Every time you use a method like BaseForm.SkipNext() that causes
the form to refresh itself the method BaseForm.RefreshForm() is
called. This method locks the screen if not in debug mode, calls
BaseForm.Requery() and then BaseForm.Refresh(). The idea behind
this is that you can put code in the BaseForm.Requery() method
that needs to be executed every time the form is refreshed. Usually
this would be a call to the Requery(), hence the name, function to
requery a child in a parent child form. For example suppose the
orders form in the sample was done using views the BaseForm.Requery()
would contain the following code :
LOCAL vpOrderId
vpOrderId = Orders.Order_Id
Requery('lv_OrderItens')
- Does the form caption appear on the menu after putting "WindowsPad" in the form.cFormBehavior?
When the form is loaded you might want to show this in the windows
popup. Normally an item appears for every open form allowing you to
activate it. This is what the WindowsPad class does. It looks for a
submenu named Window and adds an item to it. If there is no popup
named Window is does nothing at all. To see what it does take a look
at the demo application. Build and run the application with DO Demo1
(do not add WITH .T.). Take a look at the Window menu, start the form
customer and when it is active take another look at the Window menu
there should be an extra pad "Customer - 1.". Now quit the application
and modify the Customer form to remove the WindowsPad behavior. If you
build and run the application and start the form this time there should
be no extra pad on the Windows menu.
- What were/are your goals in building Application Framework?
I wanted to design a framework that was easy to use and flexible and still
very powerfull. I had read a lot about how ET++ and MacApp worked and was
fascinated by the way it used an adaptation of the Smaltalk MVC model. I
tried to do the same, separate the Controller (behavior objects) from the
forms (View objects) to achieve the flexibility and power I wanted. I
decided to leave the data as it was as I am a fan of drag an drop during
development.
- What are ET++ and MacApp?
ET++ is an advanced Application framework developer in C++ for development
of Unix applications. Weinand and Gamma originally develop it at the university
of Zurich and it is a very good example of the power of object oriented
application frameworks. MacApp is a commercial object oriented application
framework for developing applications on the Apple Mackintosh. Both have
evolved to version three and provide a lot of useful information.
- Is there a simple way to change the parent class?
There are at least two ways to do this :
- Use the class browser
- By far the easiest and fastest but make a backup copy first
Open the class libraries with : USE j:\v5apps\common\libs\sreports.vcx and
replace the vcx name with REPLACE ALL ClassLoc WITH STRTRAN(ClassLoc,
"scontrols.vcx", "scontrol.vcx")
- I have created a customer form and do not see any edit/navigation tool bars when running the form?
That could be the result of no application object being active. First build
the app and run the app with a parameter .T. "DO Demo1 WITH .T." and then
run the form. Any toolbar defined for the form in the cTools property should
now become active.
- How do I call an Exit Application dialogue window when I select exit?
That is pretty easy actually.
Create a class based on BaseApplicationBehavior and put the following code in the
OnShutDown method. Add the class name to the Application.cBehavior property, build
and run and it should work.
LPARAMETERS toApp
LOCAL llReturn, lnButton
lnButton = MessageBox('Click OK to exit application', 1 + 32, _SCREEN.Caption)
IF lnButton = 1 && OK button
llReturn = DoDefault(toApp)
ELSE
llReturn = .F.
ENDIF
RETURN llReturn
- It is possible to use PagesFrames with multiple pages in forms of maintenance?
Yes, that is what I do a lot of the time
- Some gurus say that makes no sense to develop new systems in conventional tools. That the unique possible language for the future is Java.?
I don't think we will ever have a single unique language, Java will have its role
in the future but it will not eliminate the existing languages, it is just the
newest hype. At the moment the future seems to be more like developing and combining
ActiveX components and those can be developed in a whole range of languages like VC++,
VJ, VB, VFP, Delphi etc.
- Does the framework support a 3-tier model?
Yes. The data handling is all delegated from the form to behavior classes. So the
form is the UI layer, the behavior classes form the business layer and the database
forms the data layer. At this moment I don't have any classes that work like ADO
and let you create remote objects as data but these are planned for a new version.
They are actually quite easy to make as the demo shows, the printer form works with
an array as the data source instead of a cursor and it takes little work to expand
this to a remote object.
- Explain the error handling capabilities?
Error handling is basically split into two.
1. If the file DEBUG.TXT is present and the application is not started as an EXE the
developer uses the normal VFP error handler.
2. If the framework error behavior is used an error is logged and the user is informed
and the application terminates. In some cases like printer not ready or lock contentions
the user can retry the action. This is typically not used during development but during
testing and at runtime.
There is a little more to it though. VFP-Frame has a unique feature which lets the
developer run the application in development mode. This means that the application
object and all related services are available but the normal VFP menu is not replaced
and no READ EVENTS is executed. This is a major advantage to the developer as he can
develop a form, run it and still have all related toolbars, menus and other things
that are otherwise only present during a full run. The result is far faster development
cycles with little need to build and run the app all the time.
- How did I create this page?
This page is created using my HtmlMerge utility to merge a Visual FoxPro table holding the data with a template of the page. The page template contains the java script code to show and hide the elements of the faw sheet when users click on the header.
You can download a zip file form the downloads page containing the source.