Tasmanian Traders 示例是一个集成的 Visual FoxPro 应用程序,该应用程序是为假设的一家进出口公司开发的订单输入系统,该公司在世界各地专门销售食品。
Tasmanian Traders 提供了订单输入功能,允许用户:
该应用程序还描述了用户级保密,要求用户在查看或者编辑数据之前,首先要进行登录。
Tasmanian Traders 应用程序开发的每一步过程可以分别在下面的文档中找到:
创建表结构和关系
安全性
数据集成
数据库维护
创建数据库的有关说明
应用程序级功能
表单级功能
控件级功能
类的有关说明
表单
报表
菜单和工具栏
错误处理
调试
主程序
代码的有关说明
代码的有关说明
DO (HOME(2) + 'tastrade\tastrade')
-或者-
若要打开 Tasmanian Traders 应用程序的项目
MODIFY PROJECT (HOME(2) + 'tastrade\tastrade')
在编写 Tasmanian Traders 的代码之前,需要仔细地编写一个规范,来详细说明系统需求、功能和界面。该规范大约有 30 多页的篇幅,包含下面所需要的内容。
具有的功能
应用程序提供订单输入功能,该功能应允许用户创建新订单,直接向订单中添加项目,或从以前的订单中选择项目,计算包括折扣和运费在内的项目运算结果;计算定单中每种货物地货款、所有货物货款地小计和订单总计。用户在查看或编辑数据之前,需要进行登录,由此保证系统地安全性。
不包含的功能
应用程序不管理帐目票据款项:应收票据和库存票据。
界面需求
界面必须满足 Windows 标准,并且尽可能做到外观漂亮、直观。这些主观的界面要求在细节上很难描述,所以在整个开发周期中,界面做了很大的改动。
国际化的需求
因为本示例程序需要进行多种语言的本地化,在编写代码时,必须符合内部本地化工具的标准要求。
Visual FoxPro 特征
作为一个示例,该应用程序能够描述 Visual FoxPro 的许多新特点,并演示如何将菜单和工具栏配合使用,同时提供了示例报表。
系统需求
该应用程序必须能够在 Visual FoxPro 要求的最小内存和处理器下运行,并能够在 640 x 480 像素的显示方式下显示。
在仔细推敲这些规范时,可快速生成该应用程序中的主要表单原型,而无须编写函数代码。这些原型可以演示一些对客户有用的功能,客户可以对界面和功能进行反馈,然后将这些补充添加到规范中。
在开发程序的过程中,客户的反馈无须添加到规范文档中,而是直接集成在应用程序中。所以 Tasmanian Traders 应用程序的最终版本明显和原始规范中描述的应用程序有所区别。
设计数据库的关键任务是:
在 Tastrade 中,创建表的结构和关系的过程主要在 Visual FoxPro 《程序员指南》的第五章“设计数据库”中讨论。如果要查看 Tastrade 数据库中的表和关系,请打开“数据库设计器”。
在本应用程序中,关键的实体是一个订单,在大多数的关系中,都涉及表“Orders”,而其他实体都直接或间接支持一个订单。
尽管“Suppliers”和“Category”表不直接支持一个订单信息,但它们支持“Products”表。“Suppliers”表说明产品的来源,而“Category”表提供一些管理这些产品的信息。在 Tasmanian Traders 中,这些实体意义不大。但是,在其他的应用程序(例如一个库存管理程序)中,它们就非常地重要。
在创建数据库时,除了数据库的逻辑设计之外,安全性和数据完整性也是十分重要的。
数据库的安全性对数据访问提供了限制。没有授权的用户对所有的数据都无权访问,而有些用户则对某些数据不能全权访问。例如,您可能不想让订单输入人员改变雇员信息或用户赊购的限制。
要想实现安全性,需要向“Employee”表中添加两个字段:Group_ID 和 Password。要能够访问数据库中的某些信息,用户必须经过一个登录表单,在该表单中输入正确的密码。用户注册后,Tasmanian Traders 可以从 Group_ID 字段值上判断出用户的访问级别。
因为登录表单在许多应用程序中都是一个普遍适用的单元,所以为登录表单创建了一个类:Login.vcx 中的 Login。该表单类包含文本框,可让用户输入一个 ID 号和密码;用来判定密码的表和字段的名称保存在类的属性中;在“OK”命令按钮的 Click 事件中,调用了通用代码验证用户输入的密码。当用户输入了正确的密码时,表单的一个属性(uRetVal)设置为 ON。
针对本应用程序,我们为 Login 类创建了一个子类 LoginPicture。LoginPicture 不仅具有 Login 类的所有功能,还提供了一个用户的图片和文本描述,并对密码进行提示。在 Tasmanian Traders 以外的登录表单中,所有这些对象都不是必须的。
在单独的应用程序中,登录表单可提供一定程度的安全性。但由于任何使用 Visual FoxPro 的用户都能够在该应用程序外部打开数据库,并对其中的数据进行查看或修改,所以数据实际上并不安全。在实际应用中,网络权限和数据加密可以提高安全性。但是,对本示例应用程序来说,所有的 Visual FoxPro 用户都应该能够从程序外部或内部访问数据。因此,对于任何进入本应用程序的用户,用户登录名称和密码都应该是可见的,同时没有对数据进行加密。
保护数据一致性意味着即使合法用户也不能任意添加、修改或删除数据。随意地操作有可能导致数据库的某部分无效或不准确。
在数据库级上,数据一致性的管理对下面两种情况都有效:通过应用程序的表单修改数据,或直接在浏览窗口修改数据。因此,数据一致性(参照完整性和强制性商务规则)可以在数据库中实现。
参照完整性在数据库级上是通过“参照完整性生成器”实现的。通过参照完整性,您可以控制:对于数据库中的所有父表,当改变了一个关键字的值,那么子表上也相应发生改变(级联式更新);当删除父表的一个记录,子表上相关记录也被删除(级联式删除);如果子表中存在与父表的相关记录,则用户不能删除这些父表记录(限制式删除);用户不能向子表中插入与父表不匹配的记录(限制式插入)。
在 Tastrade 中,除了 Order_Line_Items 表外,每个表都包含一个主关键字段。因为 Visual FoxPro 要求主关键字段非空且不能为 NULL 值,并且在输入时自动检查输入的字段值是否重复,所以不需要您为防止主关键字重复编写任何代码。但是,为了方便用户,存储过程 NewID( ) 为大多数表的主关键字产生一个新值,每个表中下一次将要使用的主关键字的值都保存在 Setup 表中。NewID 每次返回该值,并计算下一个合适的主关键字的新值。NewID( ) 是 Orders.Order_id、Products.Product_id 和数据库中其他主关键字的默认值(在表设计器中设置)。
但是对于 Customer 表,不值得花费时间和精力来为用户生成一个新的 Customer_id 值。客户必须为 Customer 或 Add Customer 表单中的新记录提供一个主关键字,在 Customer 表中该关键字字段为 Customer_id。用户标识的命名规则是公司名字的缩写。例如,B's Beverages 公司的 Customer_id 是 BSBEV。
为了保证在每份订单中至少有一个订货记录项,Tastrade 数据库需要一个规则,而存储过程 ValOrder( ) 可以满足此要求。除此之外,ValOrder( ) 还可保证订单总计不能超过 Max_order_amt,且不能低于 Min_order_amt。在 Tasmanian Traders 中,如果一个订单总计超出客户的最大或最小订货数量,就会出现一个信息框让用户选择忽略此规则。在一个更为严格的数据方案中,您不可允许用户忽略此规则。
ValOrder( ) 调用 RemainingCredit( ) 和 CalcMinOrdAmount( ) 存储过程。因为数据库没有存储一些信息,来说明客户支付了哪些订单,所以不可能得到关于客户未结算帐目的信息。RemainingCredit( ) 过程假设所有的订单都是未结算的。
表单级数据有效性指的是,可以通过激活或废止某些控件,限制用户访问数据。对于所有的数据绑定型表单,在表单级上设置了开放式行缓冲。Order Entry 表单则为在表格中显示的表设置了开放式表缓冲。当用户决定不保存修改时,开放式行缓冲和表缓冲可以恢复记录。
为了使用户可对表重新索引,并检查数据库的有效性,应用程序中添加了 Rebuild 表单。Rebuild 表单使用了 REINDEX 和 VALIDATE DATABASE 命令。
代替 REINDEX 命令的另外一种方法是,您可以使用 TAG( ) 和 KEY( ) 函数提取索引表达式,再使用 DELETE TAG ALL 删除所有的标识,然后使用 INDEX ON 命令重新创建所有索引。此方法会使 .cdx 文件最小。
在开发过程中,为了描述 Visual FoxPro 具有长名称的能力,某些表和字段的名称被改变了。因此必须重新创建视图和索引,同时在表单和报表上的绑定型控件的 ControlSource 属性也必须手工修改。
最初,用户在登录后,必须面对一个空白屏幕,从菜单上选择一个操作。在后来的开发过程中,在 User_level 表中添加了一个 Startup_action 字段,该字段中的信息用来指定登录后运行哪部分应用程序。
在 Tastrade 项目中有两个自由表(不包含在数据库中的表):Behindsc 和 Repolist。Behindsc 表用来存储 Behind the Scenes 信息,其内容描述了应用程序中特定的功能是如何实现的,其中不包含在应用程序中使用的数据。Repolist 表列出了所有的报表,以及每个报表的一个叙述性的名字和类型。这两个表在应用程序内部使用,用户通常不使用它们。把这两个表都包含在数据库中也可以,但是由于它们工作时和 Tastrade 数据库中的数据无关,因此没有包含到数据库中。
我们为 Tasmanian Traders 创建了六个类库。它为几乎所有 Visual FoxPro 的基类创建了相应的子类,这样应用程序的基本外观很容易通过组件来维护。在类这一级上尽可能包含通用性的功能,使类很容易维护和重用。
在创建类时,不仅考虑当前的项目,还应更多地考虑了以后的项目和可维护性。其目标是尽可能多地将通用性的功能包含在类中。但这样,在底层的类中就会包含了许多紧密集成的内部功能,这给那些要想打开项目,查看组件并了解应用程序如何工作人增加了一些困难。Tasmanian Traders 的组件就十分紧凑地集成在一起,所以很难提取其中的一、两个组件,并将它们添加到其他不同结构的项目中。但您可以在相应类的基础上,创建子类从而快速而方便地扩展 Tasmanian Traders 或开发其他相同模式的应用程序。
开发人员可以将表单中对于表的操作诸如 AddNew、Save、Delete、Restore 以及在表中移动记录指针等作为表单类的方法程序。也可以创建一个自定义类来包含这些方法程序,并将一个基于该类的对象添加到表单类中(也可以直接添加到表单中);这样该功能可以添加到以后开发的任意的表单中(包括容器或控件类),而无须考虑表单的父类,所以极大地提供了灵活性。但另一方面,这样做带来一些麻烦:当在调用方法程序时,额外增加了引用层次,且如果该自定义类包含在不同的 .vcx 文件中,则当打开表单时,必须打开另一文件。在 Tasmanian Traders 中,由于在创建表单之前类结构已经清晰地定义,而且所有包含数据的表单都是从 tsBaseForm 派生而来,所以将所有操作表的方法程序包含在 tsBaseForm 中。
在 Tasmanian Traders 中,提供了一个工具栏,可使用户访问所有表单的通用功能。另一方法是创建一个命令按钮组的类提供这些功能,并将此类的对象添加到每个表单中。使用命令按钮组的优点是用户更容易将按钮和表单联系在一起,并能够用键盘方便地访问命令按钮。但工具栏优点更多:首先,Microsoft Office 采用了大量的工具栏,用户对此非常熟悉;更重要的,工具栏根本不占用表单上的空间,也不用向已经十分拥挤的表单上再添加其他控件;并且,在运行时,很容易基于用户的访问级别进行定制工具栏。
所有的环境设置保存在一个类中,这样通过一个简单的操作就可以进行设置和恢复。在一个类中保存环境设置,并用和 Destroy 事件相关的代码恢复它们,这样做的另外一个好处是当测试阶段出现崩溃时,很容易恢复系统。执行 RELEASE ALL 语句会激活对象的 Destroy 事件,并恢复原先的系统设置。
对于数据库的存储过程,类和表单的方法程序以及菜单和程序中的代码,在编写同时即可对它们进行测试。
针对如下领域,本主题讨论 Tastrade 应用程序的编写、测试和调试:
本主题还提供主程序初始化过程的概要说明。在本主题末尾的部分,附加“代码的有关说明”。
Tastrade 包含一些表单类(存储在 .vcx 文件中)和基于这些类的表单(存储在 .scx 文件中)。有关表单类的内容,请参阅“设计并创建 Tasmanian Trader 的类”一节。下面的列表包含所有的 Tasmanian Traders 表单(.scx 文件)[父类列在方括号中]。
表单名称 | 说明 |
BehindSc.scx [tsBaseForm] | Behind the Scenes 表单。 |
ViewCode [tsTextForm] | 从 Behind the Scenes 表单中显示代码。 |
Category [tsMaintForm] | 维护 Category.dbf 的表单。 |
ChngPswd [tsBaseForm] | 允许用户改变密码。 |
CustAdd [tsBaseForm] | 允许用户输入新客户的信息。 |
Customer [tsMaintForm] | 维护 Custsomer.dbf 的表单。 |
Employee [tsMaintForm] | 维护 Emplyee.dbf 的表单。 |
GetInv [form] | 允许用户在 Orders 报表中指定日期范围。 |
GetTitle [form] | 在 ListEmpl 报表中显示信息时,允许用户对雇员信息进行筛选。GetInv 和 GetTitle 基于 Visual FoxPro 表单基类,因此无须打开类库,就可以直接运行在项目管理器启动的报表中。 |
OrdEntry [OrderEntry] | Order Entry 表单。 |
OrdHist [OrderEntry] | Order History 表单。 |
Product [tsMaintForm] | 维护 Products.dbf 的表单。 |
Rebuild [tsBaseForm] | 允许管理员级的用户重新索引,并检查数据库的有效性。 |
Reports [tsBaseForm] | 允许用户指定运行一个报表。 |
Shipper [tsMaintForm] | 维护 Shipper.dbf 的表单。 |
Supplier [tsMaintForm] | 维护 Supplier.dbf 的表单。 |
如果表单上的控件没有和数据绑定,则大多数这样的表单(例如 IntroForm 和 About)作为类保存在 .vcx 文件中,并用 CREATEOBJECT( ) 函数来创建。有时,和数据绑定的表单也直接作为类进行调用。例如,Login 类提供属性为其控件设置数据,这些属性的默认值为 Tasmanian Traders 的表和字段。而其子类 LoginPicture 在应用程序中直接使用,这个表单没有 .scx 文件。
直接运行一个 Form 类的优点是,您可以将表单的创建和显示分为两个单独的操作:
这样做,在创建对象后而在显示它之前,您可以调整属性设置。
在“表单设计器”中创建表单的优点是,可以访问一个数据环境以及和该数据环境对象相关联的属性、事件和方法程序。由于在“表单设计器”中或“项目管理器”中可以直接运行它们,所以设计和测试这些表单十分的方便。
在应用程序中,大多数数据绑定的表单都将表包含在它们的数据环境中。如果要在程序包含了一个表单,此表单允许用户同时更新多个表,那么就需要为此目的创建一个视图。
在数据库设计之后,在任何时候都可开发报表。因为 Tasmanian Traders 不是主要针对报表来开发的应用程序,所以在开发过程的较晚时候才开始创建报表。每个报表在其数据环境中包含了一个本地视图,其中有两个报表允许为报表指定参数:
在这些报表的数据环境中,视图中包含有参数。当报表数据环境打开这些视图时,默认情况下,Visual FoxPro 为用户提供了一个通用对话框进行参数输入。为了使用 Tasmanian Traders 中自定义的参数输入表单,将这些报表数据环境的 AutoOpenTables 属性设置为“假”(.F.),然后在数据环境的 Init 中运行自定义表单来获取参数变量,最后调用数据环境中的 OpenTables 方法程序。
查询可作为这些报表的数据来源,但是使用它们就需要维护额外的文件 (.qpr 文件),所以没有使用。而且,视图是包含在数据库(.dbc)文件中的,并能够在数据库设计器中方便地进行显示和修改,同时也可直接添加到数据环境里。但是,在 RemainingCredit 存储过程,根据需要使用了 SQL SELECT 语句。
应用程序的主菜单在 Main.mnx 文件中定义,而程序中唯一所使用的工具栏是基于 Tsbase.vcx 文件中的 tsToolbar 类。
菜单的 CleanUp 代码检查登录到应用程序的用户级别,并释放用户不能访问的菜单及工具栏。对于“文件”菜单上的“返回到 Visual FoxPro”菜单项,其相关的过程代码调用应用程序对象的 Cleanup( ) 方法程序,该方法程序执行 CLEAR EVENTS 命令,并恢复 Visual FoxPro 菜单系统。
在工具栏上按钮的 Click 事件中调用当前活动表单的相应的方法程序。用这种方法,表单的相关功能都被封装在表单中。
在应用程序中,如果要协调菜单和工具栏的工作,可以在菜单项的代码中调用工具栏命令按钮的 Click 事件。Skip For 子句中的表达式可以根据工具栏上命令按钮的状态激活或者废止相应的菜单项。有关协调菜单和工具栏的详细内容,请参阅“帮助”中的“协调菜单和工具栏”主题。
错误处理的目标是预测和防止代码中可能出现的错误。例如,应用程序既可以通过运行 Tastrade.app 启动的,也可以直接运行 Main.prg(在 ...\Samples\Vfp98\Tastrade\Progs 下);这是因为在 Main.prg 中包含调整相对路径设置的代码。再例如,在使用代码设置或读取应用程序对象的属性之前,首先检查一下该应用程序对象是否存在。
IF TYPE('oApp') == 'O'
* do some code
ENDIF
在特殊的情况下,如果选择某个控件可能会导致错误,则可以事先把此控件设置为无效。
但是,并不是所有的错误都能够在代码中提前发现。必要时,需要在对象的 Error 事件中来处理不可预见的错误。
当方法程序发生错误时,Visual FoxPro 将检查此对象的 Error 事件的错误处理代码。如果 Error 事件中没有任何内容,则执行从父类中继承下来的 Error 事件,或者执行该类上面的其他层次的类的 Error 事件。
如果在类层次的任何地方都没有 Error 事件代码,Visual FoxPro 将查找一个 ON ERROR 例程。如果 ON ERROR 例程也不存在,Visual FoxPro 将显示默认的 Visual FoxPro 错误信息。若要查看默认的 Visual FoxPro 错误信息,请参阅“错误信息”。
Tasmanian Traders 将检查在数据库级别上可能发生的三种类型的错误:违反字段规则,违反主关键字规则和触发器无效。因为 Tasmanian Traders 中表单的 BufferMode 设置为 2—开放式,所以这些错误仅有可能发生在如下情况里:当用户将记录指针移动到不同的记录上(这时缓冲的内容会更新到磁盘),或用户保存当前记录的修改。这两种情况都由表单级的方法程序引起的(从 tsBaseForm 继承的方法程序),因此 Visual FoxPro 首先检查表单 Error 事件的错误处理代码。例如,下面的代码是关于 Customer 表单的 Error 事件:
DO CASE CASE nError = 1884 &&
违反主关键字THISFORM.pageframe1.page1.cntCustomerInfo.Error(nError, cMethod, nLine)
CASE nError = 1582 &&
违反字段规则THISFORM.pageframe1.page1.cntCustomerInfo.Error(nError, cMethod, nLine)
OTHERWISE
tsMaintForm::Error(nError, cMethod, nLine)
ENDCASE
如果违反了字段规则或者主关键字规则,错误信息传递到其相关的控件 cntCustomerInfo 上,这样,控件的错误代码可以提供一个比 Visual FoxPro 默认错误信息更为具体的内容,再将原有的值适当恢复,并将焦点设置到合适的控件上。
如果遇到了其他错误,Customer 表单会将此错误传递给父类 tsMaintForm,该类继承了 tsBaseForm 的错误处理代码。如果错误是由触发器失败引起,tsBaseForm 的 Error 事件代码将显示存储在 Customer 表单的 aErrorMsg[ ] 属性中的相应的错误信息:Insert trigger failed,Update trigger failed 或者 Delete trigger failed(如果要分别对每个表单创建一个单独的自定义错误信息,可以在该表单的 aErrorMsg[ ] 数组中初始化相应的元素)。显示出错信息的对话框中,为用户提供“无效”“重试”或者“忽略”选项。
在 Tasmanian Traders 中的 RestoreWindowPos( ) 方法程序里,有一个 ON ERROR 语句:
ON ERROR llError = .T.
设置窗口位置的代码在设置窗口位置时会检查 llError 的值:若 llError 为 .T.,表明从 .INI 文件中读取保存的窗口位置时发生了错误,这时就由表单默认的 Top 和 Left 属性来确定表单的位置。
开发过程中,每一步都需要经过测试和调试。在 Tasmanian Traders 中,只要某个组件大致成型,就需要对它进行测试。一旦遇到问题,即可使用 Visual FoxPro 的调试工具将它们检查出来,并进行适当修改。
在 Tasmanian Traders 开发过程中,Tastrade.h 文件里定义了一个应用程序级的常量,用于控制测试和调试:
#DEFINE DEBUGMODE .T.
如果 DEBUGMODE 为“真”(.T.) ,则条件代码自动将任意一个用户作为 Applications Developer (Leverling) 登录,这样开发人员在运行程序进行测试时,就不必每次重复登录过程。
当用户或者测试人员作为 Applications Developer 登录时,Tasmanian Traders 主菜单栏上的“Utilities”菜单成为活动的,此菜单可以访问跟踪窗口、查看窗口和调试窗口,还可以取消、重新执行和挂起系统中的进程。
Main.prg 应用程序的主程序。当运行应用程序时,首先执行 Main.prg。在 MAIN.PRG 中:
oApp = CREATEOBJECT('TasTrade')
创建对象时,发生如下操作:
THIS.AddObject("oEnvironment", "Environment")
THIS.oEnvironment.Set( )
oApp.Do( )
在 Do( ) 方法程序中,代码执行下面的操作:
THIS.DoMenu( )
lcAction = THIS.GetStartupAction( ) * GetStartupAction()
返回User
表中Action
字段的值
IF !EMPTY(lcAction)
&lcAction
ENDIF
考虑到本地化的需要,对于程序中所有要翻译为其他语言的字符串,必须用 #DEFINE 预处理伪指令来定义。所定义的常量以 _LOC 结尾,这样本地化工具可以在翻译时区分它们。这些都在包含文件 Strings.h 中定义。
应用程序中,多数的代码都在类或表单方法程序中书写,这样可以在相应的对象中封装它们。那些专门用于维护数据和保证数据一致性的代码则作为存储程序保存在数据库中。
UTILITY.prg,是应用程序的过程库,包含四个函数:
您可以创建一个类来包含这些函数,但是如果创建的对象只是为了使用这些过程,就凭空添加了一个没有意义抽象的类级别。
Tasmanian Traders 创建了六个类库。开发 Tasmanian Traders 时,考虑的关键问题是:功能合并时,合并的功能应该处于哪个级别:
在 Tsgen.vcx 类库中,创建了一个通用的应用程序类 Application,该类对大多数的应用程序都适用。Application 类提供了如下功能:
在 Main.vcx 中,Application 类的一个子类 Tastrade 专门为 Tasmanian Traders 提供了一些其他功能:
在 Tastrade 类的基础上,Main.prg 中创建了对象 oApp。
下面的章节列举并描述了 Application 类的功能。
应用程序运行时,Application 类保存 Visual FoxPro 的环境。Visual FoxPro 的环境包含诸如 PATH、TALK、CARRY 等等的 SET 命令设置。在 Application 类的 Init 事件中,向 Application 中添加了一个 oEnvironment 对象,这个对象基于 Tsgen.vcx 中的 Environment 类。在 Environment 类的 Init 事件中,使用代码将现有的 Visual FoxPro 环境设置存储在 Environment 类的属性中,以便以后恢复。
Application 类的 Init 事件中的代码也将 Visual FoxPro 主窗口的标题存储到 Application 类的 cOldWindCaption 属性中。当将基于 Application 类的对象释放时,可恢复这个设置。
在 Visual FoxPro 中,另外一个环境配置是当应用程序启动时活动的标准工具栏。Application 类的方法程序 ReleaseToolbars( ) 不仅存储系统工具栏的名称,还保存这些工具栏在应用程序运行时打开或关闭的信息。
Application 类的 Init 事件代码同时将当前系统菜单压入菜单堆栈中,以备以后恢复它。
Application 类的 Init 事件中,其他代码用来设置运行环境。这些代码:
退出应用程序时,Application 类的 Cleanup( ) 和 Cleanup2( ) 方法程序代码恢复原来的 Visual FoxPro 主窗口的标题,并关闭数据库,清除窗口,恢复初始的菜单,再调用 ShowToolbars( ) 方法程序重新打开 Visual FoxPro 系统工具栏,此工具栏即是在运行 Tastrade.app 之前显示的。
执行 CLEAR EVENTS 时,程序将执行 READ EVENTS 命令后面的语句,Main.prg 中的代码释放 oApp。当释放 Application 对象时,由于 oEnvironment 是 Application 类的一个成员,所以引发了 Environment 类的 Destroy 事件。
在 Environment 对象的 Destroy 事件中,调用 Environment 对象的 Reset( ) 方法程序,来恢复 Visual FoxPro 环境设置,这些设置在创建 Environment 对象时作为属性记录在对象中。
在 Application 对象中,其他代码运行应用程序的主菜单,并创建事件循环。在 Main.prg 中,创建了 Application 对象之后马上调用 Application 类的 Do( ) 方法程序。
Application 对象还管理应用程序的工具栏。在每个表单上都有一个属性标识与之相关的工具栏。因为本程序中只有一个工具栏,所以应用程序中的所有表单,该属性设置是相同的。
在表单的 Init 事件中,调用 Application 类的 ShowNavToolbar( ) 方法程序来显示工具栏。在该方法程序中判断 nFormInstanceCount 属性的值:若为 0,表明工具栏不存在,就显示它。最后将 nFormInstanceCount 属性的值加一。
在表单的 Destroy 事件中,调用了应用程序的 ReleaseNavToolbar( ) 方法程序减少 nFormInstanceCount 属性的值,若nFormInstanceCount 属性的值已减到 0,则移去工具栏。
多数应用程序在考虑安全性时,都要求用户在使用前登录。为了管理这一过程,Application 类在 Init 事件中调用 Login( ) 方法程序,Login( ) 又调用 DoFormRetVal( ),并将登录窗口类的名称作为参数。当用户登录后,用户级别被保存在 Application 类的属性 cUserLevel 中。
该属性在菜单的 Cleanup 代码中使用,用来根据用户级别决定显示哪些菜单。
除了那些在报表中为报表设置范围的表单以外,Tasmanian Traders 中的所有表单都是通过 Application 类的方法程序来显示的。DoForm( ) 方法程序接受一个表单的名字以及一个可选的参数,该参数将传递给表单。DoFormRetVal( ) 方法程序接受一个表单类的名称,并返回表单中指定的一个值。
Tastrade 是 Application 类的子类,它保存在在 Main.vcx 中。Tastrade 类的 Init 事件调用父类 Application 类中的 Init 事件,同时,如果在启动时要显示一个封面屏幕,则调用 DoFormRetVal("introform")。
Tastrade 是 Application 类的子类,它保存在在 Main.vcx 中。它为 Tasmanian Traders 提供一些特别的功能。Tastrade 中的 Do( ) 方法程序没有使用默认的 Application 类的 Do( )。它调用 Tastrade 中另一个方法程序 GetStartupAction( ),此方法程序查找用户登录后要自动运行的应用程序组件。如果找到,Do( ) 方法程序代码就启动它。
Tasmanian Traders 包含以下几种类型的表单:
下表列出 Tasmanian Traders 中的表单类和类层次。
表单类 | 类库 |
tsFormRetVal | Tsbase.vcx |
- IntroForm | Tsgen.vcx |
- Login | Login.vcx |
- LoginPicture | Login.vcx |
- FindCustomer | Tsgen.vcx |
- FindOrder | Tsgen.vcx |
tsBaseForm | Tsbase.vcx |
- tsMaintForm | Tsbase.vcx |
- tsTextForm | Tsbase.vcx |
- OrderEntry | Orders.vcx |
- About | About.vcx |
对于所有可返回值的表单来说,它们都是从 Tsbase.vcx 中的 tsFormRetVal
派生而来。全部的数据输入表单类都是基于 Tsbase.vcx 中的 tsBaseForm
。
当 tsFormRetVal
活动时,不能访问其他组件。
属性设置
AutoCenter = | .T. |
BackColor = | 浅灰色 |
BorderStyle = | 2-双线 |
FontSize = | 8 |
MaxButton = | .F. |
MinButton = | .F. |
WindowType = | 1-模式 |
自定义属性
uRetVal: | 保存表单的返回值。可为任意类型的数据:前缀“u”代表“未知的”。默认时,uRetVal 为“真”(.T.)。 |
调用 Application.DoFormRetVal
,可创建子类的一个实例。
数据输入表单基于 tsBaseForm 类,它和 tsToolbar 类联系紧密。在 Tasmanian Traders 应用程序中,tsBaseForm 是大多数表单的父类。tsBaseForm 类提供如下功能:
属性设置
BufferMode = | 2-开放式 |
自定义属性
aerrormsg[3] = | 错误信息数组,它允许在父类中编写通用的错误处理代码,而在每个子类中可分别自定义错误信息。在 tsBaseForm 类的 Init 事件中定义如下的默认值: |
aerrormsg[1] = | “Insert trigger failed!” |
aerrormsg[2] = | “Update trigger failed!” |
aerrormsg[3] = | “Delete trigger failed!” |
cToolBar: | 与表单相对映的工具栏的名字。 |
lAllowEdits: | 当前记录是否可以编辑。 |
lAllowDelete: | 当前记录是否可以删除。 |
lAllowNew: | 用户是否可以添加新的记录。 |
和事件相关的功能
Init: | 1. 恢复上次离开系统时表单的位置。 2. 向菜单中添加表单的标题。 3. 显示定位工具栏。 4. 初始化自定义的错误信息数组 aerrormsg[ ]。 |
Activate: | 1. 选择表单的数据环境中 InitialSelectedAlias 属性指定的别名(表)。 2. 刷新定位工具栏。 3. 刷新菜单。 4. 将状态栏的信息设置为表单的 Caption 属性。 |
Error: | 为所有表单设置通用的错误处理代码。 |
Destroy: | 1. 从菜单上移去表单的标题。 2. 将窗口位置保存在 Tastrade.ini 文件中。 |
QueryUnload: | 检查数据是否改变,并提示用户必要时保存所作的修改。 |
Unload: | 清除状态栏。 |
自定义方法程序
First: | 将记录指针指向第一个记录。 |
Next: | 将记录指针指向下一个记录。 |
Prior: | 将记录指针指向上一个记录。 |
Last: | 将记录指针指向最后一个记录。 |
这四个方法程序都可进行如下操作:
自定义方法程序
Save: | 保存当前记录。 |
Delete: | 删除当前记录。 |
AddNew: | 添加一个新记录。 |
Restore: | 恢复原始的字段值(取消所作的改动)。 |
AddToMenu: | 向 windows 菜单中添加表单的标题。 |
RemoveFromMenu: | 从 windows 菜单中移去表单的标题。 |
AskToSave: | 提示用户保存修改、放弃修改、或者取消上一次操作。 |
DataChanged: | 如果当前表单上的任何数据发生了改变,则返回“真”(.T.)。 |
WriteBuffer: | 将当前控件的值写到记录缓冲里。 |
RefreshForm: | 自定义刷新例程。 |
SaveWindowPos: | 将表单的 Top 和 Left 属性写到应用程序的 INI 文件中。 |
RestoreWindowPos: | 从应用程序的 INI 文件中读取表单的 Top 和 Left 属性,并设置它们。 |
WaitMode: | 将表单的所有控件上的鼠标形状改变为“沙漏”形。 |
FindCustomer 和 FindOrder 表单分别在一个表格里显示客户表和订单表,并允许用户改变索引标识。当用户关闭表单时,将选定行上的关键字值返回给调用的表单。
有两个通用目的表单:
AboutBox 表单
AboutBox 类保存在 About.vcx 中,它的 Init 事件需要两个参数:标题和登录位图。该类使用 API 函数在 Win.ini 文件(Windows 3.x)或其他系统的注册中进行查询,从而显示用户系统的有关信息。
IntroForm
IntroForm 保存在在 Tsgen.vcx 中, 是初始的封面屏幕。在该类中,chkShowAtStartUp 的 Click 事件代码向 Tastrade.ini 文件中写入一个值,指定在下次运行 Tasmanian Traders 时,是否显示此封面屏幕。
Tastrade 示例差不多为每个 Visual FoxPro 基本控件都派生了相应的子类,这样做是为了保持一致的外观或提供附加的默认功能。在 Tasmanian Traders 中,只要不只一处需要某一组控件,就为其创建一个类。
由于应用程序必须在 640 x 480 显示方式下运行,所以这些控件的默认字体被设置为 8 磅,而不是10 磅,以节省表单上的空间。
以下是按照类库列出控件:
TSBASE.VCX 类库
类 | 说明 |
ts3dShape | 形状控件类,可突出显示或封装一个表单的某部分。 |
TsComboBox | 该类为应用程序的所有组合框使用。 |
TsCommandButton | 该类为应用程序的所有命令按钮使用。 |
TsEditBox | 该类为应用程序的所有编辑框使用。 |
TsGrid | SumColumn 方法程序用于自动计算一个表格列的加总值。该类添加到 tsMaintForm 类中页框的 List 页面上。 |
TsLabel | 该类为应用程序的所有标签使用。 |
TsListBox | 该类为应用程序的所有列表框使用。 |
TsTextBox | 该类为应用程序的所有文本框使用。 |
OrdTextbox | TsTextbox 的一个子类,用在 Order Entry 和 Order History 表单中。 |
TsToolBarButton | 该类为应用程序的所有工具栏上的命令按钮使用。 |
Tsgen.vcx 类库
类 | 说明 |
CustomerInfo | 组织 customer 表中字段所对应的标签和文本框。 |
DateRange | 在 Visual FoxPro 控件基类的基础上创建的一个自定义控件。 |
Splitter | 在 Behind the Scenes 中使用,重新改变功能列表尺寸和说明编辑框的大小。 |
TsMaintForm | 该类供应用程序中所有的维护表单使用。 |
TsToolBar | 应用程序的工具栏使用的类。 |