vfp6.0产品id的名次命令是什么

第六章 VFP6.0程序设计基础
第六章 VFP6.0程序设计基础
第六章 Visual FoxPro6.0程序设计基础
章本章介绍FoxPro程序设计,这是本课程的重点内容。前面所学的选单方式和命令交互方式固然重要,但为了末端用户、为了简化和优化具体问题的操作,需要将选单方式或命令交互方式的步骤记录下来,成为方便使用的程序(软件)。本章分为:
工 具: ☆ ☆ ☆☆☆ ☆
6.1 程序文件
前几章介绍了FoxPro的命令、若干函数及FoxPro的交互执行方式,交互执行方式能灵活地解决即席提出的问题,为用户使用数据库提供了很大便利。但交互执行方式要求用户掌握较多的计算机知识:对非程序员用户、或称为未端用户而言,由于这些用户大多为组织中的各级管理人员,要求他们掌握较多的计算机知识是比较困难的。
  FoxPro还提供另一种执行方式,即程序方式。所谓程序方式是指计算机程序人员根据用户功能需求,将FoxPro的操作命令组织成程序,未端用户通过运行程序完成预定功能,同时程序方式还能解决一些复杂的问题,所以对于成功的数据库管理系统而言,交互方式和程序方式互为补充,缺一不可。
  在FoxPro的程序方式中,通过流程控制等语句,将前几章介绍的命令或函数组织成程序,程序方式中的命令也称为语句。程序组织在命令文件或过程文件中。命令文件和过程文件的区别在于,在命令文件中只包括一个可执行的程序,多个程序组织在一文件中构成过程文件。过程文件中的每个程序也称为一个过程。本书将命令文件和过程文件统称为程序文件,本章讨论程序的构造及运行。
  命令文件和过程文件都是文件扩展名为.PRG的文本文件,这两种文件统称为程序文件。程序文件可用任何一种编辑程序建立和修改,FoxPro系统本身也包含了编辑程序,使用该编辑程序可在FoxPro系统内编辑修改程序文件,和调用其它编辑程序相比,减少了在FoxPro系统和系统外编辑程序之间切换的开销。
6.1.1程序文件编辑命令
FoxPro编辑程序文件的命令是:
语法:MODIFY COMMAND[&文件&|?]|MODIFY FILE[&文件&|?]
「NOEDIT][NOWAIT]
[RANGE&数值表达式1&,&数值表达式2&]
[WINDOW &窗口名1&]
[IN[WINDOW]&窗口名2&|IN SCREEN]
[SAME][SAVE]
  如果未作特别设置,该编辑命令调用FoxPro的内部编辑程序,程序文件名以字母开始,由不超过8个的字母、数字及下划线构成。编辑好的文件存入磁盘后,自动将原来的文件改名为扩展名是.BAK的后备文件,如磁盘上存在一个该程序文件经编译的目标文件(扩展名为.FXP),则程序文件编辑后,系统在执行该程序时自动将其编译成目标形式以覆盖原目标文件,从而保证每次执行的总是该程序的最新版本。
  在MODIFY COMMAND命令中,如文件名不包括扩展名,则系统默认为是.PRG的程序文件,命令中如&文件名&包括MS-DOS的文件通配符“*”、“?” 则系统将文件名与其匹配的多个文件提交用户编辑。如果将命令写成MODIFY? 形式,则系统出现Open对话框,让用户选择扩展名为.PRG、.MPR、.SPR和.QPR的任一文件进行编辑。
  MODIFY FILE命令和MODIFY COMMAND命令相同,只是在(文件)名中必须说明扩展名。
  NOEDIT短语使得编辑的文件只能浏览而不能修改;NOWAIT短语中使得程序中的由本MODlFY COMMAND命令执行的编辑工作和程序的执行工作同时进行;RANGE子句说明文件编辑的范围,即由文件头开始计数,编辑从&数值表达式1&的值所指行到&数值表达式2&的值所指行的这一部分;WINDOW子句指定执行编辑的窗口名;SAME使文本编辑窗口不作为当前活动窗口;SAVE短语使得MODIFY COMMAND命令执行完成后,仍在屏幕上保持文本编辑窗口的图象。
  为提高程序的可读性,必须在程序文件中加以注释,这是软件工程化开发方法的基本要求,注释语句是NOTE。
语法:NOTE &说明&
   * &说明&
   && &说明&
注释语句以NOTE或*开始, FoxPro不将注释的(说明)作为程序语句执行。在程序文件中,注释可以单独成行,多行的(说明)在行未用“;”继行;注释也可放在可执行语句的后面,这时应用&&将注释与语句分开。
*例 Exa6_1.prg
NOTE 查找四川来的同学!
*统计四川同学的数量
DO WHILE .NOT. EOF()
IF "四川"$家庭住址
ENDDO &&处理结束
TEXT命令是文本命令,程序中用TEXT命令将&文本行&的内容在屏幕或打印机上输出。文本的内容不作为语句执行,放在程序末尾的文本可省略ENDTEXT短语,NOTE 命令和TEXT命令的区别在于是否将说明文本作为文本输出。
*例 Exa6_2.prg
Welcome You to FoxPro DB-World!
  这段文本包括在某个程序中,当程序执行到TEXT语句时,根据输出设备的设置,在屏幕或打印机上输出下列内容:
Welcome You TO FoxPro DB-World!
  前几章已经讨论了若干输入输出命令,这些命令中还没有对输入输出的位置及格式进行讨论,在程序执行方式中,需要构造一个输入格式让用户在确定的位置输入数据,需要控制打印输出的格式等等,这些都要求有控制输入输出位置及格式的语句,这些语句和流程控制等语句等等。在交互方式中也能作为命令使用,仅由于这些语句经常在程序方式中,故放在这里。
6.1.2 格式化显示语句
  首先讨论数据格式化显示语句。
语法:@&坐标& SAY &表达式1&[FUNCTION &功能码&][PICTURE &描述码&]
[SIZE&数值表达式1&,&数值表达式2&]
[FONT&表达式2&[,&数值表达式3&]][STYLE &表达式3&]
[COLOR SCREME &色彩模式&|COLOR &色彩对表&]
  &坐标&是以“,”分隔的一对&数值表达式& ,其值分别表示行、列的位置,对窗口而言,行坐标由上到下,列坐标由左到右,窗口左上角坐标为(0,0),右下角坐标视显示字体(foot) 及窗口而异,打印输出时,每页的行列坐标均由1开始,最大值取决于打印设备和打印纸。
  SAY语句的输出介质依赖于输出设备的设置,如果此语句前由SET DEVICE TO SCREEN设置输出设备为屏幕,则在屏幕上显示;如果由SET DEVICE TO PRINT设置输出设备为打印机,在打印机上打印输出。
*例 Exa6_3.prg
SET DEVICE TO SCREEN
@8,8 SAY"请输入用户名:"
@2,20 SAY" 系统功能"
* 分别由当前窗口第2行第20列开始显示系统功能,及由第8行第8列开始显示请输入用户名:
SET DEVICE TO PRINT
@8,8 SAY"建筑物造价"
@10,20 SAY" 今天的日期"+DTOC(DATE())
  由于打印机只能单向走纸,第一页由第8行第8列开始打印建筑物造 ,要到第2页第2行第20列才开始打印今天的日期。04/02/99。
  SAY语句中的&表达式&可以是一个常量,也可以是由常量、字段变量、内存变量及函数构成的表达式,在由多个简单表达式组成的一个复合表达式中,数值型量要用STR函数、日期型量要用DTOC函数转化为字符型量,再用字符串联接运算符“+”或“-”构成为一个字符串输出 。
FUNCTION子句和PICTURE子句说明显示或打印的格式。
FUNCTION子句中功能码含义为:
B 数值数据在显示区域中左对齐
C 在正的数值数据后面标以CR表示贷方
D 根据SET DATE中的日期格式将字符型数据和数值型数据编辑为日期型
E 以英国格式“日/月/年”编辑日期型数据
I 字符型数据去除前后空格
X 在负的数值型数据后面标以DB表示借方
Z 当数值型数据的值为0时,显示空格而不显示0
( 当数值型数据为负时,以"()"括起来
! 对字符型数据将小写字母转换为大写
^ 用科学汁数法表示数值型数据
$ 以当前的钱币符号表示数值型数据(例$50.06)
PICTURE子句中描述码含义为:
X 允许任何字符
Y 只允许逻辑型数据Y、y及N、n,且将其转化为大写(y转化为Y,n转化为N);
! 小写字母转化为大写字母
$ 根据SET CURRENCY、SET SEPARATOR及SET POINT的设置将数值型以钱币形式显示
* 在数值型数据前显示“*”号
. 说明小数点位置
, 以“,”分隔数值型数据的整数部分
  PICTURE子句的&描述码&中可包括任何字符,除上面列出的功能码外,其它字符以原样显示。PICTURE子句的&描述码&中也可包括功能码,不过必须在功能码前冠以“@”符号。
SIZE子句通过两个数值表达式说明显示区域的行数和每行长度;FONT子句、STYLE子句和COLOR子句分别说明显示的字体、字形和色彩。
6.1.3 格式化GET语句和READ语句
  GET子句用以显示和编辑已存在的字段变量、内存变量及数组元素的内容。
语法:@&坐际& GET &内存变量&|&字段&
[FUNCTION &功能码&][PICTURE &描述码&]
[FONT&字符表达式&[,&数值表达式1&]][STYLE &字符表达式1&]
[DEFAULT&表达式1&]
[ENABLE|DISABLE]
[MESSAGE &字符表达式2&]
[[OPEN] WINDOW &窗口名&]
[RANGE&表达式2&[,&表达式3&]]
[SIZE &数值表达式2&,&数值表达式3&]
[VALID&逻辑表达式1&|&数值表达式4&[ERROR &字符表达式3&]]
[WHEN &逻辑表达式2&]
[COLOR SCHEME&色彩模式&|COLOR &色彩对表&]
  GET语句可和SAY语句联合在一起说明&坐标&位置,这时由&坐标&位置开始显示SAY&表达式&的值,空一格显示GET&变量&,否则由&坐标&说明GET&变量&的位置。输出设备一定要由SET DEVICE TO SCREEN设置为屏幕。
  &内存变量&|&字段& 说明GET语句的编辑对象,其类型可以是数值型、字符型,日期型和逻辑型.
FUNCTION编辑功能码:
A 只允许字母字符A~Z a~z
B 数字左对齐,只允许用于数值型数据
C 在正数之后添加一个CR,仅用于数值数据,而且仅用于SAY子句
D 根据当前SET DATE设置的日期格式,将字符型数据和数值型数据编辑为日期型
I 编辑字段中的文本中心对齐
J 编辑字段中的文本右对齐
K 光标移到一个字段时,以整个字段作为编辑对象
L 数值型字段中显示前导零(而不是空格)
M&表列& 在字符型数据的输入中,通过&表列&给出多个可能的值(字符串),各可选字符串之间以分号分隔,从而建立弹出式的选择输人方式。
R 在编辑区显示格式化标记,但不存在变量中
S&N& 恨据n值控制输入区域宽度,以控制键控制字符串在该宽度中左右移动
T 压缩前部和后部空格
X 在负数之后添加一个DB, 只用于数值数据,而且仅用于SAY子句
Z 如果数值是零,则显示空字符串,只能用于数值型数据将字符型数据中的小写字母转化成大写以科学汁数法显示数值型数据
PICTURE 描述码:
  PICTURE 短语中的&描述码&可包括任何字符,除下面列出的描述码外,其它字符以原样输出,原样输出的字符可用作输入的提示,输入时光标将跳过这些字符。
A 只允许字母字符
L 只允许逻辑值
N 只允许字母和数字
X 允许任意字符
Y 只允许逻辑值Y、y、N、n,且一律转化为大写
9 对字符型数据只允许数字字符,对数值型数据允许数字及正负号
# 允许数字、空格、正负号和小数点
! 小写字母转化为大写字母
$ 数值前加钱币符号
* 数值前加“*”号和“$”符号用以检产数值
. 指定小数点的位置
, 小数点左边整数数位用逗号分隔
* 例 Exa6_4.prg
****** picture function *****
SET TALK OFF
Appe blank
@1,5 SAY "学 号:" get 学号 PICTURE""
@2,5 SAY "姓 名:" get 姓名 MESSAGE"Please input your name"
@3,5 SAY "入学成绩:" get 入学成绩 PICTURE"#####.##"
num1=-99.55
num2= 2.00
@8,5 GET num1 PICTURE "999.99"
@10,5 GET num2 PICTURE"@Z" DISABLE
@12,5 GET num3 PICTURE "##,###.##" FUNCTION "Z"
SET TALK ON
  一般而言,作为GET语句编辑对象的内存变量必须事先定义,只有用DEFAULT短语说明的变量在编辑前才不必事先定义,这些变虽以&表达式1&的值作为其编辑的初始值。
  缺省说明ENABLE|DISABLE短语时,每个编辑对象都是可编辑的,DISABLE使编辑对象只供显示不可编辑。
  MESSAGE子句在一个对象被编辑时将&字符表达式2&的字符串作为提示信息显示在系统状态条上。
  数据输入中的数据完整(正确性&由RANGE子句、VALID子句和WHEN子句检查,下面分别说明这三种验证方法。
  RANGE子句用于字符型、日期型和数值型变量的验证,以说明编辑中输入数据的允许范围,范围用&表达式2&和&表达式3&分别表示数据的下界和上界,如只说明上界或下界,则只检查相应的上界或下界,如果输入数据不在该范围内,则系统提示正确的取值范围,击入空格键后重新输入。
* 例 Exa6_5.prg
@8,5 SAY"Please Modify Your Enroll Score:"
@8,5 GET 入学成绩 RANGE 400,700
  VALID子句用&逻辑表达式1&验证编辑输入数据的正确性。验证在READ语句执行后进行,&逻辑表达式&验证为真后才能退出该变量的编辑, VALID子句也可通过&数值表达式&进行验证,在VALID子句验证不能通过时,由ERROR子句显示由&字符表达式3& 给出的出错信息。
* 例 Exa6_6.prg
APPEND BLANK
@1,5 SAY"是否属于会计981班(Y/N)?" GET sy PICTURE"Y"
@3,5 SAY "学 号:" get 学号 PICTURE""
@4,5 SAY "姓 名:" get 姓名 MESSAGE"Please input your name"
@5,5 SAY "入学成绩:" get 入学成绩 PICTURE"#####.##"
@8,2 SAY"Sorry!"
  READ语句执行以后,不能再编辑该语句以前的GET&变量&,若要使这些变量仍能被以后的READ语句所编辑,必须用READ SAVE语句。
* 例 Exa6_7.prg
*********** SAVE的作用 **********
APPEND BLANK
@2,5 SAY"请输入您的姓名:" GET 姓名
@4,5 SAY"是否男生(Y/N)?" GET ns PICTURE"Y"
@6,5 SAY"请输入您的入学成绩:" GET 入学成绩 PICTURE"###.#"
  在屏幕格式文件(扩展名为.FMT)中,用格式化输入输出命令构造屏幕格式,编辑修改变虽内容。
6.1.4 TRANSFORM函数
语法:TRANSFORM(&表达式&,&字符表达式&)
  TRANSFORM函数用格式描述将字符或数值表达式格式化,返回一个经格式化的字符串。函数第一个自变量&表达式&是待格式化的字符型或数值型变量,第二个自变量&字符表达式& 是关于该变量输出格式的描述,&字符表达式&由一个或多个PICTURE描述码及FUNCTION功能码组成,格式化规则请参阅@...命令关于PICTURE及FUNCTION格式的说明。
* 例 Exa6_8.prg
STORE 15.89 to price
?TRANSFORM(price, "$$$$$.99")
6.1.5 读错事件处理陷井
  数据正确性的保证可通过ON READERROR读错事件处理陷井。
语法:ON READFRROR[&命令&]
  通过READ语句执行@ …GET语句编辑时如发生RANGE范围或VALID验证失败,或输入无效日期时,触发读错陷井READERROR中的处理&命令&。如果不使用该语句作陷阱处理,则系统将出现提示。
6.1.6 窗口(或屏幕) 的清除及填色命令
  清除整个窗口(或屏幕) 用命令CLEAR。
语法:CLEAR
  CLEAR命令清除当前窗口(或屏幕),并释放所有尚未进入READ编辑的@ …GET变量。
  清除局部窗口(或屏幕)用下列命令:
语法:@&坐标1&[CLEAR|CLEAR TO &坐标2&[DOUBLEE]]
  由&坐标1& 作为左上角坐标, &坐标2& 作为右下角坐标,清除当前窗口(或Windows主窗口、或整个屏幕)中的这个矩形区域,如缺省CLEAR或CLEAR TO,则由&坐标1& 开始到清除当前行;如仅缺省&坐标2&,则由&坐标1&作为左上角坐标,清除窗口(或屏幕)的右下角。
@2,5 CLEAR TO 6,74
局部填色用FILL命令。
语法:@&坐标1& FILL TO &坐标2&
[COLOR SCREME &数值表达式&|COLOR &色彩对表&]
  FILL语句改变当前窗口(或Windows主窗口、或整个屏幕)的某块文本的显示色彩,&坐标1&和&坐标2&分别说明该文本区域的左上角和右下角坐标。色彩属性由COLOR子句给出。
@4,1 FILL TO 10,8 COLOR R+/B
6.1.7 画矩形框命令
注:经测试,在DOS状态下可以实现,但在Windows95下边界(框)花样无法实现。
简单画矩形框的命令是:
语法:@&坐标1&,&坐标2& BOX [&字符表达式&]
  在FoxPro主窗口(或用户定义窗口)中作出一个以&坐标1&为左上角坐标,&坐标2&为右下角坐标的矩形框,如不说明&字符表达式& ,矩形框为单线边框;&字符表达式& 最多由9个字符组成,从左上角开始,每个字符分别作为矩形框的角及边,第9个字符作为矩形域内的填充字符,如&字符表达式&中只有1个字符,则构造以该字符为边的矩形框。
@4,5,14,60 BOX REPLICATE(CHR(177),9) &&画出有阴影的矩形
画矩形框(包括圆角形矩形框)更进一步的命令是:
语法:@&坐标1& TO &坐标2&
[DOUBLE |PANEL|&字符表达式&][PATTERN &数值表达式1&]
[PEN&数值表达式2&[,&数值表达式3&] [STYLE &字符表达式2&]
[COLOR SCREME &数值表达式4&|COLOR &色彩对表&]
该命令最简单形式是:
@&坐标l& TO &坐标2& DOUBLE|PANEL|&边界串&
  其作用相当于上述的作矩形框的命令@&坐标1& TO &坐标2& BOX &字符表达式&。其中DOUBLE短语说明边界为双线框,PANEL短语说明边界为条形框。
  在FoxPro for Windows中用该命令描述对象的输出边界,其中PATTERN子句说明对象的充填特征。&数值表达式1&的含义为:
  PEN子句说明对象的轮廓线,&值表达式2& 和&数值表达式3& 的含义为:
数值表达式2为线宽度。
数值表达式3为线型:
2 长划虚线
4 双点划线
  SAVE说明对象的边框形状,&字符表达式2& 的值(0到99)说明矩形框圆角的曲率。0值指定没有转角,99时为最大转角,从而构造成一个圆(或椭圆)。
  COLOR 子句说明对象的色彩属性。
6.1.8 换页、换页事件及打印机初始化
  注:由于未连接打印机,仅供今后编程参考。
打印换页命令EJECT
语法:EJECT
  EJECT 命令使打印纸换页,如果系统内存变量_PADVANCE置为FORMFEED,将换页符送往打印机;如置为LINEFEEDS,则根据页面的大小送若干个换行符给打印机(关于下列系统内存变量的介绍请见第10章)。该命令重置PCOL函数和PROW函数的值,但不影响系统内存变量_PAGENO或_PLINENO的值。
* 例 Exa6_9.prg
********* 打印换页 ********
SET DEVICE TO PRINTER
set printer to test.txt &&由于无打印机,以文件代替打印机。
DO WHILE pagenum&=3
@1,1 SAY "PAGE"+ STR(pagenum,3)
pagenum=pagenum+1
SET PRINT OFF
SET DEVICE TO SCREEN
语法:ON PAGE [AT LINE&数值表达式&&命令&]
  ON PAGE AT激发一个换页事件,该命令监测系统内存变的PLINENO的值,当该值大于&数值表达式&的值时.执行&命令&中规定的动作。
打印换页命令EJECT PAGE
语法:EJECT PAGE
  EJECT PAGE命令根据系统内存变量_PADVANCE的值及ON PAGE事件状态决定打印的走纸方式。
如_PADVANCE的值为FORMFEED,未设置ON PAGE的事件陷井,则本命令完成下列动作:
·在打印机联机时将换页符送打印机
·根据内存变量_PILFNGTH和_PLINENO的值,将换行符送屏幕及替换文件
·_PAGENO的值置为1
·_PLINENO的值置为0
  如_PADVNCE的值为LINEFEED,且设置了ON PAGE陷井,但_PINENO的值小于ON PAGE命令中的数值表达式时,送入若干个换行符,以强迫换页。
其它情况下,执行下列动作:
  根据系统内存变量_PLENGTH和_PLINENO的值,送若干个换行符给打印机(或送往FoxPro主窗口,或替换文件)
·_PAGENO的值加1
·_PLINENO的值置为0.
打印初始化语句
语法:PRINTJOB
&语句序列&
ENDPRINTJOB
PRINTJOB对打印机从其有关的系统内存变量初始化,影响的内存变量包括:
·向_PSCODE中置入打印机起动控制码;
·在_PEJECT设置为BEFORE或BOTH时.进行打印机换页 ;
·将_PCOLNO置0.
  ENDPRINTJOB结束打印作业,其完成的工作包括:
·向 _PSCODE中置入打印机结束控制码;
·在_PEJECT设置为AFTER或BOTH时,进行打印机换页;。
  根据_PCOPIES系统内存变量中设置的打印份数值,自动进行(语句序列)的循环,以完成多份打印输出。PRINTJOB…ENDPRINTJOB只能在程序方式中使用;使用中不能构成嵌套。
6.2 程序的控制结构
● 在交互执行方式中,命令根据输入的先后次序顺序执行,在程序执行方式中,程序文件中的语句也是顺序执行的,只有采用流程控制语句后,才能改变语句的执行顺序。
  Foxpro的流程控制语句包括条件语句,由多条件语句演化出的分情况语句,以及循环语句,这些语句只能用在FoxPro的程序中,而不能作为命令用于交互执行方式。
6.2.1 条件语句
IF&逻辑表达式&
&语句序列1&
&语句序列2&]
  IF语句称为条件语句,根据&逻辑表达式&的值控制执行的命令序列,如果&逻辑表达式& 的值为逻辑真值.T.,则执行&语句序列1&中语句,否则执行&语句序列2&中的语句。&语句序列1)或&语句序列2& 执行完毕后,IF语句结束,程序执行IF语句的下一条语句。逻辑框图见图4-1。
* 例 Exa6_10.prg
*如果kj981.dbf文件的当前记录不是四川学生,则显示其各项情况,否则将统计来自四川的学生数的内存变量加1。
IF.NOT."四川"$家庭住址
IF语句中可省略ELSE子句,这时如果&逻辑表达式&的值为逻辑真.T.,则执行&语句序列1&,否则不做任何动作,逻辑框图见图4-2.
* 例 Exa6_11.prg
*如果kj981.dbf文件的当前记录不是四川学生,则显示其各项情况,否则不做任何事情。
IF.NOT."四川"$家庭住址
  &逻辑表达式& 可以构造成由逻辑运算符.NOT. 、.AND.、.OR.联结起来的复合条件。
* 例 Exa6_12.prg
*****************************************
IF .NOT."四川"$家庭住址 .AND. 入学成绩&400 .OR. .NOT."重庆"$家庭住址
******************************************
  IF语句可以嵌套,即IF语句中的&语句序列1&或&语句序列2&中还可包含IF语句,例如,程序中构造了一个用户使用菜单:
1.数据输入
2.数据查询
3.数据修改
  菜单屏幕由一系列的@…SAY语句构成,用户对菜单功能的选择通过lNPUT语句输入到一个命名为act的内存变量中。
* 例 Exa6_13.prg
********************************************************
1.数据输入
2.数据查询
3.数据修改
@5,10 GET act RANGE 1,4
*DO datainput &&执行数据输入程序
* DO datasearch &&执行数据查询程序
Brow NOMODIFY
IF act = 3
* DO dataupdate &&执行数据修改程序
  IF语句中的IF必须和ENDIF配对,程序中使用了缩排的书写方式,以便于程序阅读,但FoxPro系统在执行IF语句时,不是根据缩排的格式来决定IF和ENDIF的配对关系,而是由IF语句的最内层开始,逐层将IF和ENDIF配对,所以在多层嵌套时尤应注意配对关系,以免配对错误引起程序逻辑的错误。在某些情况下IF…ENDIF语句也可由IIF函数代替,从而简化条件描述的结构,提高程序的执行速度。
语怯:IIF(&逻辑表达式&,&表达式1&,&表达式2&)
  IIF函数测试&逻辑表达式&的值,如该值为真,则返回&表达式1&的值;为假则返回&表达式2&的值。
* 例 Exa6_14.prg
c=IIF(a&=b,a-b,b-a)
  IIF函数也可嵌套使用。
* 例 Exa6_15.prg
c=IIF(a=b,a*b,IIF(a&b,a-b,b-a))
6.2.2 分情况语句
CASE&逻辑表达式1&
&语句序列1&
CASE&逻辑表达式2&
&语句序列2&
… …
CASE&逻辑表达式n&
&语句序列n&
[OTHERWISE
&语句序列n+1&]
  DO CASE语句称为分情况语句,进入分情况语句后,系统首先判断&逻辑表达式I& ,如其值为逻辑真值.T.,则执行&语句序列1&,否则判断&逻辑表达式2&,如其值为逻辑值真.T.,则执行&语句序列2&;依此类推。无论执行了哪个语句序列,系统不再顾及其后面各CASE的&逻辑表达式&,而直接执行ENDCASE后面的下一条语句,换言之,系统只会执行分情况悟句中的一个&语句序列&。如果各个&逻辑表达式&均为逻辑假.T.,且如有OTHERWISE子句,则执行&语句序列n+1&, 然后结束分情况语句,否则直接结束分情况语句,而未做任何动作,其逻辑框图见图4-3。
  由IF语句中最后一个例子可以看出,当某个变量有多个可能取值,程序要根据值的不同作不同处理时,用IF语句既繁琐又易出错,这时用分情况语句可以简化程序结构。例Exa4-13用分情况语句可构造如下:
* 例 Exa6_16.prg
1.数据输入
2.数据查询
3.数据修改
@5,10 GET act RANGE 1,4
CASE act=1
*DO datainput &&执行数据输入程序
CASE act=2
* DO datasearch &&执行数据查询程序
Brow NOMODIFY
CASE act = 3
* DO dataupdate &&执行数据修改程序
6.2.3 循环语句
  循环语句实现有规律性的重复操作,重复操作的语句组构成的&语句序列&称为循环体。FoxPro 2.5具有一般程序设计语言都具有的WHILEE条件循环和FOR跳步循环,同时还有专用于数据文件处理的SCAN扫描循环。循环的次数一般是由循环条件决定,但在循环体的&语句序列&中可用跳出语句(EXIT)结束循环,也可用(LOOP)语句继续循环。
(1) WHILE条件循环
DO WIIILE&逻辑表达式&
&语句序列&
DO WHILE语句为条件循环语句,其中&辑表达式&的值构成循环条件,&语句序列&中的语句构成循环体,进入循环语句后首先判断&逻辑表达式& 的值是否为逻辑真值.T.,为真则执行&语句序列&.然后重新判断&逻辑表达式&的值,如此循环,直至&逻辑表达式&的值是逻辑假值.F.为止,其逻辑框图可表示为图4-4。
  在程序中经常需要重复一系列的操作,例如检索造价在30万美元以上的建筑物,由于Foxpro的文件操作是记录级的操作,每次处理的对象都是数据文件的一个记录,所以每次要检索文件当前记录是否造价在30万美元以上,要检索文件中造价在30万美元以上的所有建筑,必须从文件的第一个记录开始,逐个检查文件的每个记录,直至文件结束为上,这时的&逻辑表达式&具体化为判断是否到文件尾,即使用EOF()函数进行判断。
* 例 Exa6_17.prg
DO WHILE .NOT.EOF()
IF 入学成绩&400
Big400=Big400+1
?"分数高于400的学生有",big400,"名"
  作为循环条件的&逻辑表达式&可以是用.NOT.、.AND. 、.OR. 联结成的复合条件。FoxPro对文件操作的循环条件经常是用对文件的记录指针进行判断的EOF()、 BOF()函数,FoxPro程序中另一种常用循环条件是&逻辑表达式& 为永真的条件,即循环条件为逻辑真值.T. ,在循环中满足适当条件时用EXIT语句跳出循环,具体例子见EXIT语句。
(2) FOR跳步循环
FOR &循环变量&=&数值表达式1&TO&数值表达式2&[STEP &数值表达式3&]
&语句序列&
ENDFOR|NEXT
  在FOR循环中,循环体&语句序列& 的执行次数是根据(循环变量)的值来决定的,进入FOR循环语句后,&循环变量&取&数值表达式1&的值作为初值,&数值表达式2& 的值作为终值,&数值表达式3&的值称为步长,&语句序列& 构成循环体,&循环变量& 可以是一个内存变量,也可以是一个数组元素,该变量不必预先定义。
  如果&数值表达式3& 的值为正数,则当循环变量的值小于或等于终值时,执行循环体一次;如果步长值为负,则循环变量值大于或等于终值时执行循环体,循环体每次执行结束后,将循环变量的值与步长相加,重新进行比较,步长的缺省值为1。
* 例 Exa6_18.prg
* 如果要处理数据文件中记录号为偶数的记录
J=RECCOUNT()
FOR mcount=I TO J STEP K
@2,2 SAY "姓名:" +姓名
@3,2 SAY"您的入学成绩: ←请修改 (输入小于0的数则结束)"
temp=入学成绩
@3,16 GET 入学成绩 PICTURE"999.9"
*(对偶数记录进行修改)
IF 入学成绩&0
REPL 入学成绩 WITH temp
(3) SCAN扫描循环
SCAN [NOOPTIMIZE][&范围&][FOR&逻辑表达式1&][WHILE&逻辑表达式2&]
[&语句序列&]
  SCAN循环针对某个数据文件进行,这个数据文件中由&范围&子句说明的处理范围,&范围& 缺省值为ALL,该范围中逐个扫描满足FOR条件或WHILE条件的记, 即自动进行记录指针的移动。对每个满足条件的记录,完成由&语句序列& 组成的循环体的动作。
* 例 Exa6_19.prg
SCAN FOR RECNO()%2=0
@2,2 SAY "姓名:" +姓名
@3,2 SAY"您的入学成绩:   ←请修改 (输入小于0的数则结束)"
temp=入学成绩
@3,16 GET 入学成绩 PICTURE"999.9"
*(对偶数记录进行修改)
IF 入学成绩&0
REPL 入学成绩 WITH temp
  循环语句也可嵌套,即在循环语句的循环体中还包含循环语句,这时特别要注意DO WHILE …ENDDO、FOR…ENDFOR和SCAN…ENDSCAN的配对。具体例子见EXIT语句。
(4) EXIT语句
语法:EXIT
  EXIT语句用于退出循环,在DO WHILE语句、FOR语句及SCAN语句的循环体中,若执行到EXIT语句,则无条件地退出包含该EXIT语句的这层循环,程序执行该层循环语句外的下一条语句。
* 例 Exa6_20.prg
* 输入一个整数,判断该数是否是质数。
DECLARE xx[100]
INPUT"请输入一个大于1的整数:" to testnum
k=INT(SQRT(testnum))
FOR I=2 TO k
IF MOD(testnum,I)=0
?testnum,"是质数"
?testnum,"不是质数"
(5)LOOP语句
语法:LOOP
  LOOP语句用在循环语句的循环体中,如循环体的执行中遇到LOOP语句,则不再执行LOOP语句与该循环体结束语句之间的所有语句(结束语句在WHILE循环中是ENDDO,在FOR循环中是ENDFOR或NEXT,在SCAN循环中是ENDSCAN),而返回到包含该LOOP语句的这一层循环的开始处,即返回到DO WHILE或FOR或SCAN,在FOR循环中返回后修改循环变量的值,在SCAN循环中返回后移动记录指针。然后重新判断循环条件。
* 例 Exa6_21.prg
*统计kj981.dbf文件中四川学生的数量,逐个显示他们的的学号、姓名、家庭住址、入学成绩情况;对不是四川的学生只显示其姓名和家庭住址。
DO WHILE .NOT. EOF()
IF "四川"$家庭住址
? 学号,姓名,"家住",家庭住址,入学成绩
WAIT"按任意键继续..." WINDOW
?姓名+"不是四川的学生"
WAIT"按任意键继续..." WINDOW
?"共有",ALLTRIM(STR(sc)),"个家庭住址是四川的学生"
  LOOP语句造成程序执行顺序的跳跃,使程序可读性降低。通常可以通过修改程序结构而取消LOOP语句,例如上例程序可改写成:
* 例 Exa6_22.prg
*统计kj981.dbf文件中四川学生的数量,逐个显示他们的的学号、姓名、家庭住址、入学成绩情况;对不是四川的学生只显示其姓名和家庭住址。
DO WHILE .NOT. EOF()
IF "四川"$家庭住址
? 学号,姓名,"家住",家庭住址
WAIT"按任意键继续..." WINDOW
?姓名+"不是四川的学生"
WAIT"按任意键继续..." WINDOW
?"共有",ALLTRIM(STR(sc)),"个家庭住址是四川的学生"
该程序还可以简化:
* 例 Exa6_22p.prg
*统计kj981.dbf文件中四川学生的数量,逐个显示他们的的学号、姓名、家庭住址、入学成绩情况;对不是四川的学生只显示其姓名和家庭住址。
SET TALK OFF
DO WHILE .NOT. EOF()
IF "四川"$家庭住址
?学号,姓名,"家住",家庭住址
?姓名+"不是四川的学生"
WAIT"按任意键继续..." WINDOW
?"共有",ALLTRIM(STR(sc)),"个家庭住址是四川的学生"
6.3 模块化程序设计
& 在设计数据库应用系统时,首先应通过系统分析,确定应用系统的总体目标,即首先决定应用系统要“干什么”。对一个复杂的应用系统,根据其逻辑结构可将系统总目标分解为几个子目标,对各个子目标有可能再分解力更低一级的子目标。系统分析完成以后才能进入系统设计和程序设计,程序设计中每个子目标构成一个模块,一般最低一级子目标的规模控制在50条 语句左右,这样,应用系统由若干大模块构成,大模块分解为小模块,模块间存在调用关系,通过这种结构化的系统分析和系统设计,使得最后的应用系统可读性强、易于维护和管理,结构化的方法是一种良好的程序设计方法;例如要构造一个98级学生成绩管理系统,则以xs98.dbf文件为主建立一个数据库应用系统;对xs98.dbf文件的操作可分解为数据输入,数据查询和数据修改等几个独立部分,在数据查询部分还可分为根据学号查询、根据姓名查询等等,构造一个层次化的树型结构(图6_5)。 在构造FoxPro程序时,上层的模块完成用户菜单构造或通过(ASF语句(或IF语句)对下层进行调用控制,底层的模块则是一些以基本语句(例如APPFND、LOCATE…) 构造的基本功能程序,每个模块可以作为FoxPro的一个独立命令文件,也可以将若干个模块集中为一个过程文件,命令文件或过程文件中过程问的调用一般由DO语句实现。
6.3.1 DO语句
语法:DO &文件&[WITH&参数表&][IN&文件&]
  DO命令执行FoxPro的一个程序,程序中同样可以包含DO命令,DO的做套层次最多不超过32层。 DO命令所执行的&文件&可以是程序文件,也可以是扩展名为.MPR、.SPR或.QPR的菜单程序、屏幕程序或SQL查询程序,当文件中没有说明扩展名时,系统按.EXE、.APP、.FXP、.PRG的优先次序查找待执行的文件,通过IN子句可执行另一个文件中的过程, 命令文件是扩展名为.PRG的文件,每个命令文件完成一个相对独立的功能。
例如学生成绩管理系统可以设计成以下框架:
************************************
*            学生成绩管理系统主模块              *
************************************
SET TALK OFF
1.数据输入
2.数据查询
3.数据修改
@5,10 GET act RANGE 1,4
CASE act=1
* DO datainput &&执行数据输入程序
CASE act=2
DO dataquery &&执行数据查询程序
CASE act = 3
* DO dataupdate &&执行数据修改程序
… … …
数据查询模块有可分为两个模块,例如:
************************************
*   成绩查询模块dataquery.prg    *
************************************
SET TALK OFF
1.按学号查询
2.按姓名查询
@5,10 GET cx RANGE 1,2
* DO by_num &&执行按学号查询程序
* DO by_name &&执行按姓名查询程序
… …
?"输入错误,返回!"
  数据库应用系统一般都是很复杂的软件系统,系统的功能由很多功能模块完成,如果将这些功能模块都构造成各个独立的命令文件,命令文件的数量将会相当之多,造成系统管理上的困难。同时,命令文件及该应用系统的数据文件、索引文件、内存变量文件等都必须组织在应用系统的一个目录结构中,造成目录结构的庞杂和臃肿,致使系统在目录搜索及命令文件打开/关闭切换操作中的开销增加,最终造成系统效率下降。
  FoxPro系统允许将多个过程构造成一个过程文件,一个过程文件被编译后不能超过64K大小,过程文件中的每个过程以PROCEDURE语句开始,以区分不同过程的起始位置。
语法: PROCEDURE &过程名&
  &过程名&由不超过10个的字符组成,一个过程的开始意味着上一个过程的结束,例如可以将对xs98.dbf文件的各种处理过程集中成一个过程文件:
PROCEDURE datainput
… …
RROCEDURE datasearch
… …
PROCEDURE dataupdate
… …
PROCEDUBE by_num
… …
PROCEDURE by_name
  在过程文件中除包括过程外,还可包括用户自定义函数,用户自定义函数以FUNCTION语句开始。
语法:FUNCTIOON &函数名&
  同一过程文件中的各个过程(及用户自定义函数)在形式上是同等的,在执行逻辑上可能存在相互调用关系。
  一个应用系统可能由若干个命令文件和若干个过程文件组成,命令文件和过程文件可以并存,但在任一时刻只能打开一个过程文件,打开过程文件的语句是:
语法SET PROCEDURE TO[&过程文件&]
  一个过程文件打开后,原打开的过程文件自动关闭,不带过程名的SET PROCEDURE TO或CLOSE PROCEDURE也能关闭过程文件,退出FoxPro系统后,自动关闭打开的过程文件。
* 例 将本章第二节所有例子的程序文件合成一个过程文件为(ch6sec2.prg):
************************************************************
* EXA6_17 *
************************************************************
PROCEDURE EXA6_17
* 例Exa6_17.prg
DO WHILE .NOT.EOF()
IF 入学成绩&400
Big400=Big400+1
?"分数高于400的学生有",big400,"名"
************************************************************
* EXA6_10 *
************************************************************
PROCEDURE EXA6_10
* 例 Exa6_10.prg
*如果kj981.dbf文件的当前记录不是四川学生,则显示其各项情况,否则将统计来自四川的学生数的内存变量加1。
IF.NOT."四川"$家庭住址
************************************************************
* EXA6_11 *
************************************************************
PROCEDURE EXA6_11
* 例 Exa6_11.prg
*如果kj981.dbf文件的当前记录不是四川学生,则显示其各项情况,否则不做任何事情。
IF.NOT."四川"$家庭住址
************************************************************
* EXA6_12 *
************************************************************
PROCEDURE EXA6_12
* 例 Exa6_12
*****************************************
IF .NOT."四川"$家庭住址 .AND. 入学成绩&400 .OR. .NOT."重庆"$家庭住址
******************************************
************************************************************
* EXA6_13 *
************************************************************
PROCEDURE EXA6_13
* 例 Exa6_13.prg
********************************************************
1.数据输入
2.数据查询
3.数据修改
@5,10 GET act RANGE 1,4
*DO datainput &&执行数据输入程序
* DO datasearch &&执行数据查询程序
Brow NOMODIFY
IF act = 3
* DO dataupdate &&执行数据修改程序
************************************************************
* EXA6_14 *
************************************************************
PROCEDURE EXA6_14
* 例Exa6_14.prg
c=IIF(a&=b,a-b,b-a)
************************************************************
* EXA6_15 *
************************************************************
PROCEDURE EXA6_15
* 例 Exa6_15.prg
c=IIF(a=b,a*b,IIF(a&b,a-b,b-a))
************************************************************
* EXA6_16 *
************************************************************
PROCEDURE EXA6_16
* 例Exa6_16.prg
1.数据输入
2.数据查询
3.数据修改
@5,10 GET act RANGE 1,4
CASE act=1
*DO datainput &&执行数据输入程序
CASE act=2
* DO datasearch &&执行数据查询程序
Brow NOMODIFY
CASE act = 3
* DO dataupdate &&执行数据修改程序
************************************************************
* EXA6_18 *
************************************************************
PROCEDURE EXA6_18
* 例 Exa6_18.prg
* 如果要处理数据文件中记录号为偶数的记录
J=RECCOUNT()
FOR mcount=I TO J STEP K
@2,2 SAY "姓名:" +姓名
@3,2 SAY"您的入学成绩: ←请修改 (输入小于0的数则结束)"
temp=入学成绩
@3,16 GET 入学成绩 PICTURE"999.9"
*(对偶数记录进行修改)
IF 入学成绩&0
REPL 入学成绩 WITH temp
************************************************************
* EXA6_19 *
************************************************************
PROCEDURE EXA6_19
* 例 Exa6_19.prg
SCAN FOR RECNO()%2=0
@2,2 SAY "姓名:" +姓名
@3,2 SAY"您的入学成绩: ←请修改 (输入小于0的数则结束)"
temp=入学成绩
@3,16 GET 入学成绩 PICTURE"999.9"
*(对偶数记录进行修改)
IF 入学成绩&0
REPL 入学成绩 WITH temp
************************************************************
* EXA6_20 *
************************************************************
PROCEDURE EXA6_20
* 例 Exa6_20.prg
* 输入一个整数,判断该数是否是质数。
INPUT"请输入一个大于1的整数: " to testnum
k=INT(SQRT(testnum))
FOR I=2 TO k
IF MOD(testnum,I)=0
?testnum,"是质数"
?testnum,"不是质数"
************************************************************
* EXA6_21 *
************************************************************
PROCEDURE EXA6_21
* 例 Exa6_21.prg
*统计kj981.dbf文件中四川学生的数量,逐个显示他们的的学号、姓名、家庭住址、入学成绩情况;对不是四川的学生只显示其姓名和家庭住址。
DO WHILE .NOT. EOF()
IF "四川"$家庭住址
? 学号,姓名,"家住",家庭住址
WAIT"按任意键继续..." WINDOW
?姓名+"不是四川的学生"
WAIT"按任意键继续..." WINDOW
?"共有",ALLTRIM(STR(sc)),"个家庭住址是四川的学生"
************************************************************
* EXA6_22 *
************************************************************
PROCEDURE EXA6_22
* 例 Exa6_22.prg
*统计kj981.dbf文件中四川学生的数量,逐个显示他们的的学号、姓名、家庭住址、入学成绩情况;对不是四川的学生只显示其姓名和家庭住址。
DO WHILE .NOT. EOF()
IF "四川"$家庭住址
? 学号,姓名,"家住",家庭住址
WAIT"按任意键继续..." WINDOW
?姓名+"不是四川的学生"
WAIT"按任意键继续..." WINDOW
?"共有",ALLTRIM(STR(sc)),"个家庭住址是四川的学生"
************************************************************
* EXA6_22P *
************************************************************
PROCEDURE EXA6_22P
* 例 Exa6_22p.prg
*统计kj981.dbf文件中四川学生的数量,逐个显示他们的的学号、姓名、家庭住址、入学成绩情况;对不是四川的学生只显示其姓名和家庭住址。
SET TALK OFF
DO WHILE .NOT. EOF()
IF "四川"$家庭住址
?学号,姓名,"家住",家庭住址
?姓名+"不是四川的学生"
WAIT"按任意键继续..." WINDOW
?"共有",ALLTRIM(STR(sc)),"个家庭住址是四川的学生"
*****************************************
  有了这个总文件,其它分个文件就不需要了。只要在使用SET PROCEDURE TO ch4sec2命令,该过程中的所有命令文件都可以使用。
*例 exa6_23.prg 建立总控命令文件,使用过程文件ch4sec2.prg中的任意命令文件。
SET PROCEDURE TO ch4sec2
DO exa6_13
DO exa6_22
  当通过DO语句执行一个程序时,FoxPro搜索该程序的次序是:
·首先在包含该DO语句的程序文件中搜索;
·其次在用SET PROCEDURE语句打开的过程中搜索;
·再其次在执行程序构成的链中进行查找, FoxPro将执行过的程序信息保存在一个链中,链的查找按人后向前次序进行;
·最后查找独立的命令文件。
  DO命令可以嵌套,即DO命令所调用的命令文件或过程文件的过程中也包括DO命令。但是嵌套深度不能超过32层。DO命令可以递归即在一个命令文件(或过程文件的过程)中可以包括调用其自身的DO 语句。当然在递归调用时,必须安排好递归的出口,以免出现无穷递归的错误。
* 例 Exa6_24.prg
* 递归方法实现阶乘mu1=1X2X…X10
DO exa6_24
* 注:使用方法如下:
* 在命令窗口中执行下列命令
*DO exa6_24
3628800。 && 最后得出1* 2*3……*10的阶乘结果
这里顺便讲以下累乘(卷积)的计算,对于上例阶乘可以用以下简单程序计算:
* 例 Exa6_25.prg
@2,4 SAY"请输入阶乘的最高值:" get n RANGE 1,15
for I=2 to n
@4,2 SAY "The Result Is: "+STR(mul)
4.3.2 返回语句
  返回语句控制命令文件或过程文件中过程执行的终上,返回语句有三种格式:
RETURN[&表达式&|To MASTER |TO&程序名&]
  RETURN语句终止当前的命令文件或过程,当RETURN下带任何选择项时,控制返回到调用程序,RETURN TO MASTER返回最上层调用程序,如选用TO&程序名& ,则返回到由&程序名&说明的程序。在程序结束位置,RETURN语句实际上是一个可选也可不选的语句。因程序文件最后一条语句执行结束后,自动完成RETURN语句的功能。执行RETURN语句后,释放所有的局部内存变量。
  CANCEL语句终止命令文件或过程文件的执行,控制返回到命令窗口(或Windows主窗口〕。在程序文件中,也可直接用QUIT语句,退出FoxPro。系统而返回Windows主窗口。在FoxPro执行结束时,最后必须执行QUIT命令,否则会造成文件破坏及数据丢失。
* 例 Exa6_26.prg
* 调用阶乘和求和两个程序
SET TALK OFF
DO WHILE .T.
@2,2 SAY "请选择:1.做阶乘 2.求和" GET xz PICTURE'9'
DO Exa6_25
@16,2 SAY"还继续做吗?" GET jx PICTURE"Y"
* 例 Exa6_27.prg
* 对n个连续自然数求和
@2,2 SAY"请输入求和的自然数起始数:" GET n1 PICTURE"99"
@4,2 SAY"请输入求和的自然数终止数:" GET n2 PICTURE"999"
FOR I=n1 TO n2
@6,2 SAY"这"+ALLTRIM(STR(n2-n1+1))+"个自然数的和是:"+ALLTRIM(STR(sum))
  在口令检查中,如系统设定某过程的执行口令为“axl3z”,应用人员如口令应答不对则返回到命令窗口。
* 例:Exa6_28.prg
* 设立口令
password=0
SET DEVICE TO SCREEN
@2,2 SAY "请输入您的口令(六位数字)"
SET CONSOLE OFF
INPUT TO password
SET CONSOLE ON
IF password&&888888
WAIT"Sorry! You havn't the right to operate this system." WINDOW
DO EXA6_26
  在FoxPro用户自定义函数中,也可以用CANCEL及QUIT语句终止程序的执行。前已叙及,用户自定义函数通过RETURN&表达式&中的&表达式&值将函数结果值返回给函数引用语句,函数命令文件(或过程)也能作为一般的命令文件(或过程〕由DO语句执行,但函数由DO调用并经RETURN语句返回时,将忽略RETURN后面的返回值。
4.4.3 参数
  多个命令文件或过程文件中的多个过程可能需要相同的子功能,但执行这些子功能要求不同的自变量值,为说明简单起见,设想多个过程都要求计算长方形面积,但各个过程要求计算的长方形边长各不相同。这种情况当然可将完成该功能的程序段编写进各个过程中,但这种功能相同仅参数下同的程序段在多个过程中重复出现,程序就比较冗长而且出错机会增加,为此可将这个公用的子功能编写成一个能供各个程序调用的公共程序,通过参数传递的方式完成调用程序与被调用程序之间的数据传送。程序调用由DO语句完成,调用参数在DO语句的&参数表&中给出。&参数表&中的参数可以是任何有效的表达式,包括常量、内存变量、字段名或用户自定义函数,参数个数限制在24个以内,如果内存变量名和数据文件的字段名相同,则要在字段名前标以数据文件的别名,否则字段名优先。
  被调用程序的参数由程序中PARAMETERS语句说明。
语法:PARAMETERS 〈参数表&
  PARRAMETERS悟句必须是被调用程序的第一条语句,被调用程序的PARAMETFRS语句与调用程序DO语句的WITH相呼应,完成与调用程序之间的参数传递。在&参数表&中,各个参数以逗号分隔。调用程序中的参数和被调用程序中的参数之间按排列位置对应,对应位置上两个参数必须数据类型相同。和用户自定义函数,一样,传送到调用程序中的参量个数可以少于在PARAMETERS参数表中的参量个数,在这种情况下,余下的参量系统自动赋以逻辑假值.T.,参量的个数可通过PARAMETERS()函数测定。
DO语句中的参数可以是一个常量,调用时该常量值赋给破调用的命令文件(或过程)的参数表中对应的变量。调用参数可以是一个表达式,调用时计算出此表达式的值赋给被调用的命令文件(或过程)中对应的变量。调用参数可以是一个变量或数组,这个变垦必须预先定义,在缺省状态下,过程调用的参数传递是以传递地址方式完成,即如果该变量的值在被调用命令文件(或过程〕中发生变化,调用完成后将这个新的值返回给调用命令文件(或过程〕的相应参数,如果希望以值传递的方式进行叁数传递,即希望参数在过程中变化后的新值不返回到调用程序中.则需在将该变量括上括号,请注意,用户自定义函数调用时参数是以值传递的方式进行,如果希望将用户自定义函数的参数传递方式改为传递地址,需用SET UDFPARMS REFERENCE进行设置。
* 例 Exa6_29.prg
* 计算矩形面积的命令文件
PARAMETER length,width,area
area=length*width
?"The area is ",area
用DO Exa6_29 with 2,3命令执行上述程序,结果为:
The area is 6
4.4.4 局部变量和全局变量
  在Foxpro命令窗口中定义的内存变量是全局变量,可由所有程序使用,在命令文件或过程中定义的变量是局部变量,调用程序所定义的内存变量相对于被调用程序而言具有全局意义,即下层可以使用和改变上层所定义的内存变量。但是,某些下层模块可能要求自己使用的变量与上层无关,而且在多次重复被调用中,需保留上次最后被调用的结果值,如果该变量与上层某变量重名,则由于上层对该变量的使用,可能改变该变量的值,为此,需要将这种变量局部化,局部变量可通过PRIVATE语句说明,反之,如果下层建立的内存变量希望作为全局变量供所有程序使用,必须将这种变量用PUBLlC语句说明成全局变量。
  局部变量和全局变量的定义各有2种方式,语法为:
PRlVATE&内存变量表&
PRIVATE ALL [LIKE|EXCEPT&模板&]
PUBLIC &内存变量表&
PUBLIC [ARRAY] &数组& (&数值表达式&[,&数值表达式&])
[,&数组&(&数值表达式&[,&数值表达式&]),…]
  在被调用程序中用PRIVATE语句建立局部变量,局部变量若和上层的变量重名,系统将这两个变量作为不同变量看待,一个是相对于下层具有全局意义的变量,称为当前隐藏的变量,列变量表时标以另一个是当前的局部变量,局部变量赋值下影响上层同名变量,当下层执行完返回上层时,下层局部变量不能由上层程序所检索与修改,上层变量恢复其隐藏的值。
  局部变量说明中由ALL说明当前所用的变量全部是局部变量,用LIKE短语说明当前所用的变量中变量名与&模板& 相匹配的变量都是局部变量,用EXCEPT短语说明除了与&模板&匹配的变量外都是局部变量。
  在被调用程序中用PUBLIC语句建立全局变量,这些在下层建立的全局变量可由任何上层检索及修改,全局变量必须先定义然后才能引用,全局变量定义后,系统首先为其赋以逻辑假值.F.。第二种全局变量定义格式可定义一维及二维全局内存变量数组。
* 例 Exa6_30.prg
********* 上层程序*********
DO Exa6_31
LIST MEMORY LIKE"?"
* 例 Exa6_31.prg
********* 下层程序*********
LIST MEMORY LIKE"?"
  命令文件Exa6_30中定义了三个变量x 、y、z。命令文件Exa6_31中定义了全局变量w,并将x说明为局部变量,还另外定义和使用了变量v。在执行Exa6_30时,Exa6_30调用Exa6_31,所以相对Exa6_31而言,Exa6_30中三个变量x、y、z具有全局意义。
  执行DO Exa6_30, 各变量值为:
N pub N 10
W pub N 22
X Priv (hid)N l Exa6_30
Y Priv N 6 Exa6_30
Z Priv N 3 Exa6_30
X priv N 10 Exa6_31
V Priv N 30 Exa6_31
N pub N 10
W Pub N 22
X Priv N 1 Exa6_30
Y Priv N 6 Exa6_30
Z Priv N 3 Exa6_30
  前6个是Exa6_31列出的内存变量,其中第一个x标以hid,即是一个在Exa6_31中隐藏起来的内存变量,第二个x 是Exa6_31局部变量,取值为10。
  后4个是Exa6_30列出的内存变量,第一个x恢复了调用Exa6_31前的值,第二个x 消失了。Exa6_31中定义的W保存了下来。
  如果由Exa6_30退回到命令窗口,其它变量均消失了,只有变量W保存下来,读者可在命令窗口用LIST MEMORY命令证实这一点。
4.4.5 光带式选单
  光带式选单是一种非常有用、非常灵活的选单,用户可以通过光标的移动对选单的功能进行选择,被选中的功能以增强方式即亮底暗字的形式显示,非常醒目。其命令格式如下:
@&坐标&PROMPT&字符表达式1&[MESSAGE&字符表达式2&]
功能:&字符表达式1&用于定义光带选单中的一个功能项,该项在屏幕上的显示位置又&坐标&指定。MESSAGE为可选项,用于在消息栏显示&字符表达式2&所表示的信息,详见课本。
该命令以组合形式出现,即同时用相同语法定义几个光带项。
光带式选单定义后需用与之配套的MENU TO命令激活才能使用,语法为:
MENU TO&内存变量名&
其功能为激活光带选单,使用户能用光标移动键与回车键在选单上进行功能选择。该内存变量的取值范围应在1至功能项的总数之间。初始赋值为几,选单激活时光带就停在第几项功能上。若未赋初值,则激活时停在第一项功能上。选中几就把几存入内存变量中,并进行相应操作序列。
* 例 Exa6_32.prg 最简单的光带式选单
SET TALK OFF
SET STATUS BAR ON
* SET STATUS ON
Ms1='用于修改指定的字段'
Ms2='按记录的关键字删除'
Ms3='向数据库添加记录'
Ms4='按记录的关键字值查询'
Ms5='结束运行'
@3,10 PROMPT"\&1.修改" MESSAGR ms1
@3,30 PROMPT"\&2.删除" MESSAGR ms1
@4,10 PROMPT"\&3.添加" MESSAGR ms1
@4,30 PROMPT"\&4.查询" MESSAGR ms1
@5,20 PROMPT"\&5.返回" MESSAGR ms1
SET MESSAGE TO 16
*例 Exa6_33.prg 下拉菜单横条
DO WHILE .T.
SET COLOR TO n/n
SET COLOR TO 5/2
@1,35 SAY'信息管理系统'
@3,14 PROMPT'数据管理'
SET COLOR TO 7+/1
@3,26 PROMPT'数据查询'
@3,38 PROMPT'数据输出'
@3,50 PROMPT'数据维护'
@3,60 PROMPT'推出系统'
MENU TO CH
CH=STR(CH,1)
DO PROC&CH
* 例proc1.prg 上例第一项功能
set colo to 4/3
DO WHILE .T.
@5,14 PROMPT'增加数据'
@6,14 PROMPT'修改数据'
@7,14 PROMPT'删除数据'
@8,14 PROMPT' 返 回 '
MENU TO cout
Cout=STR(cout,1)
DO PROC1&cout
6.4 事件处理
Microsoft windows是个事件驱动的操作系统。所谓事件可定义为一种情况或一种活动的发生,或一种指定状态的变化。在Windows系统的管理下,FoxPro的程序按用户描述的流程执行,但是,程序执行过程中可能会发生各种“事件”,其中有由于程序中预期不到的错误造成的“出错事件”,有当用户非预期地激发某一个键时的“按键事件”、还有FoxPro可识别的其它“事件”,包括打印过程中的“换页事件”、菜单系统中的各种“选择事件”及退出系统时的“关闭事件”等,事件处理是指这样两方面的能力:一是能识别事件的发生,二是能根据特定的事件采取相应的处理方法。 本节主要讨论“出错事件”、“按键事件”和“关闭事件”,其它事件将在有关章节中讨论。
  在交互方式中,也能通过事件处理语句处理出错事件等。
4.4.1 出错事件及相关函数
语法:ON ERROR[&命令&]
  程序执行中由于各种不可预期的原因可能会造成程序执行出错,例如当外存不够时,大文件的排序操作不能完成,在多用户状态下,多个用户打开外数据文件会引起冲突,如果在程序中已经预置了ON ERROR &命令&,则当任…出错事件发生时,会引发ON ERROR中&命令&语句的执行,一般而言,该&命令&一般是DO&文件& 这种语句,即当错误事件发生后,转入执行DO语句所调用的出错处理过程。出错处理过程有时也称出错陷井。 FoxPro还提供了ERROR()函数、MESSAGE()函数、PROGRAM()函数及LINENO()函数,分别返回错误类型、出错原因、出错的程序名及出错的程序行号。
例:某程序中间可以加入如下语句:
… …
ON ERROR DO errhand with ERROR(), MESSAGE(),PROGRAM(), LINENO()
… …
… …
* 例: 出错处理子程序errhand.prg
**** 出错陷井 ****
PARAMETERS merror, mess,mprog, mlineno
?"您的程序出错! "
?"错误类型号:"+LTRIM(STR(merror))
?"出错原因:"+mess
?"出错程序名:"+mprog
?"出错程序行号:"+LTRIM(STR(mlineno))
  现提供一个比较好的出错处理程序(err.prg),供大家使用。
  出错处理完成后,程序一般跳过出错行继续执行。只有当出错陷井的程序出口语句是RETRY语句这时返回执行激活陷井的同一个程序出错行。
  不带&命令&的ON ERROR命令关闭出错陷井。
语法:ERROR()
  ERROR函数返回最近程序出错的错误类型号。ERROR函数只有当ON ERROR设置的出错陷井处于激活状态时才起作用,否则总是返回一个0值。
  RETURN语句和RETRY语句重新将ERROR函数的返回值置为零。
MESSAGE函数
语法:MESSAGE([1])
  MESSAGE 函数在不带选择项1时返问错误原因信息,带选择项1 返回程序出错行。和ERROR函数不同,RETURN语句和RETRY语句下重置MESSAGE函数的返回值。
PROGRAM函数
语法:PROGRRAM([&数值表达式&])
  PROGRAM函数返回当前正在执行程序的程序名或返回程序出错时导致出错的程序名。程序可以通过DO语句嵌套,&数值表达式&缺省时返回当前执行程序的程序名,为0或1。返回最上层的主程序名,否则返回&数值表达式&的值指定的嵌套的那一层的程序名。
LINENO函数
语法;LINENO([1])
  LINENO函数返问出错行的行号,行号由程序的开始计数,注释行、接续行和空行都作为单独的一行计入行号中。在缺省任选项1时,行计数由主程序开始,否则,当前程序第一行的行号为1。
4.4.2 ESCAPE 按键事件
语法:ON ESCAPE[&命令&]
  和ON ERROR一样,该语句可通过&命令&设置ESCAPE按键陷井。程序中设置了ESCAPE按键陷井后,往一时刻按ESCAPE键均进入该陷井进行处理。
* 例 Exa6_34.prg
*************** 主程序 ****************
SET ESCAPE ON
ON ESCAPE DO stopit
WAIT WINDOWS"按ESC键结束循环" NOWAIT
Moreloop=.T.
DO WHILE moreloop
PROC stopit.prg
***** 按键陷井stopit.prg *******
moreloop=.F.
  注意上述程序中WAIT WINDOW行中的NOWAIT,由于该短语的存在, moreIoop的逻辑值最后赋了一个假值,从而导致不能进入DO循环而退出程序的执行,ESCAPE只有SET ESCAPE ON设置时才有效。
4.4.3 任一按键事件
ON KEY[&命令&]
ON KEY LABEL[&键标&][&命令&]
ON KEY=[&数值表达式&][&命令&]
  ON KEY&命令&设置按任意键均进行的按键事件处理。
  ON KEY=命令只是为了保留和Fox的过去版本兼容而被保留在FoxPro2.5中,尽管该命令对某一个键值可以定义一个按键事件,但其致命的弱点是任一时刻只能有一个按键事件,或者说当前ON KEY=命令自动取消了上一个ON KEY=命令所定义的按键事件。
  ON KEY LABEL可以定义多个按键事件,这些键在用ON KEY LABEL取消前一直有效。在READ、BROWSE、EDIT,CHANGE和用户定义的菜单中(或弹出式菜单)中按了任意一个所定义的键,或按了鼠标钮,均进入相应的按键事件处理程序。ON KEY LABEL语句中通过&键标& 名来定义用户按键(包括组合键),通过(命令)对键标(即用户按键事件)进行指派,即设置相应击键陷井。
  用&数值表达式&的值代表字符的ASCII码,可将可打印字符定义成“热键”,对功能键和控制键以ON KEY LABEL键标的值作为&数值表达式&的值。
ON KEY LABEL键标定义表见教材附录三。
  如果同时有多个ON的引发情况存在,则首先是ERROR事件,然后是ESCAPE事件,最后是KEY LABEL、KEY或KEY=&数值表达式&事件。
  在定义同一键的下一个同类型的ON语句执行前,前一个ON语句一直有效,下一同类型ON语句中的&命令&将取代前一个ON语句中的&命令&。或者说一个新的陷井取代了一个同类的老陷井,如果缺省下一个ON语句中的&命令&,则撤消前一个同类ON语句中的&命令&,或者说撤消了这个陷井。
  用户程序可能希望在不同时刻激活各不相同的序列。例如在多个窗口之间切换时,不同窗口可能激活不同的“热键”序列,为此可用PUSH KEY命令将当前生效的热键事件序列存放入内存的一个“热键栈”当中,在需要时再通过POP KEY重新弹出。
语法:PUSH KEY[CLEAR]
  “热键栈”中存放的按键事件序列按先进后出的原则放行,该语句中包含CLEAR子句后,在栈中保存键标的指派后,清除当前键标指派。
语法:POP KEY [ALL]
  当PUSH KEY语句执行后,用户可用ON KEY LABEL语句修改或重定义热键,在回到原执行状态时,可通过POP KEY语句后将“热键栈”中定义的热键指派重新激活。包含ALL子句后,清除当前所有用ON KEY LABEL定义的热键指派,同时清除内存“热键栈”。
4.4.4 关闭事件
  FoxPro可以识别和处理“关闭事件”,当退出FoxPro for Windows或直接退出Windows时通过用户事先定义的“关闭事件”的处理过程进行处理。
语法:ON SHUTDOWN[&命令&]
  用户在FoxPro莱单框的File项选择Exit,或执行QUIT命令均激发“关闭事件”;在Foxpro for Windows处于打开状态时,由Windows的程序管理器直接退出Windows也激发“关闭事件”。这两类“关闭事件”通过ON SHUTDOWN定义的“关闭事件陷井”(关闭事件发生时执行的&命令&)进行处理,通常该&命令&是由DO语句启动的一个过程,在过程中通过对话框由用户对退出进行确认。用户确认后,由程序关闭所有打开的文件,清理FoxPro的各种环境变量,最后执行QUIT命令;如用户不准备退出,则将控制返回给应用程序。
缺省&命令&的ON SHUTDOUN取消上述对于“关闭事件”的处理定义。
4.4.5 ON()函数
语法: ON(&字符表达式1&[,&字符表达式2&])
  对上述ON ERROR、ON ESCAPE、ON KEY、ON KEYLABEL、ON SHUTDOWN,及下义将要描述的ON PAGE和ON READERROR等事件处理而言,每当设置的事件发生时,控制将转向相应的处理程序, ON函数以字符串方式返回相应命令或处理程序名。
第一个参数&字符表达式1&用以说明事件:
字符表达式1
ON KEYLABEL
ON READERROR
  对于ON KEY等还需要由&字符表达式2&说明具体的键或组合键的键标,键及组合键的键际见附录三。
* 例 Exa6_35.prg
ON KEY LABEL CTRL+F1 WAIT'请试按组合键CTRL+ F1或其他键!' WINDOW
ON ERROR DO ERR WITH PROGRAM(), LINENO(),ERROR(), MESSAGE(1), MESSAGE()
@1,1 SAY'如按CTRL+F1键,则···'
@2,1 SAY ON('KEY','CTRL+F1')
@3,1 SAY'如果发生错误,则···'
@4,1 SAY ON('ERROR')
6.5 常见计算和字符图形编程实例
* 例 Exa6_34 求Fabonacci数列中的前20个数 */set talk offcleara=0b=1?a,b &&输出头两个Fabonacci数for i=3 to 20 &&从第三项起循环& c=a+b && 前两项之和& ??c&if mod(i,5)=0 &&每行输出5个值&&& ?& endif& a=b& b=cendfor
* 例 Exa6_35 求100以内的素数i=0for m=2 to 100& prime=1 && 设一个标志,先假定是素数& for n=2 to m-1&&& if mod(m,n)=0&&&&& prime=0 && 表明m不是素数&&& endif& endfor& if prime=1 && 假定值没有改变*/&&& ??m&&& i=i+1&&& if mod(i,5)=0 && 每行输出5个值 *&&&&& ?&&& endif& endifendfor
* 例 Exa6_36 求调和级数中第多少项的值大于10limit=10sum=0.0n=1do while .t.& sum=sum+1.0/n& if sum&LIMIT&&& exit& endif& n=n+1&enddo?"n="+ltrim(str(n))return* 例 Exa6_37 打印九九乘法表
* 九九乘法表PARAMETER typeCLEARIF TYPE=1& ?" 九九乘法表(TYPE 1)"& ?" "& FOR I= 1 TO 9&& ??" ("+ALLTRIM(STR(I))+")"& ENDFOR& FOR I=1 TO 9&&& ?"("+ALLTRIM(STR(I))+")"&&& FOR J=1 TO I&&&&& ?? I*J PICTURE"999999"&&& ENDFOR& ENDFORELSE& * 另一种方法& ?""& ?" 九九乘法表(TYPE 2)"& ?" "& FOR I= 1 TO 9&&& ??" ("+ALLTRIM(STR(I))+")"& ENDFOR& FOR I=1 TO 9&&& ?"("&&& ?? I PICT"9"&&& ??")"&&& FOR J=1 TO I&&&&& ?? J PICT"999"&&&&& ??"*"&&&&& ?? I PICT"9"&&&&& ??"="&&&&& ?? I*J PICT"99"&&& ENDFOR& ENDFORENDIF
* 例 Exa6_38 打印实心菱形set talk offset color to 2/7+clearn=0@1,1 say"请输入菱形的边长:n=" get nread?for i= 1 to n& for j=n-i to 1 step -1&&& ??" "& endfor& for j=1 to 2*i-1&&& ??"*"& endfor& ?endforfor i= 2 to n& for j=i-1 to 1 step -1&&& ??" "& endfor& for j=2*(n-i)+1 to 1 step -1&&& ??"*"& endfor& ?endfor
* 例 Exa6_39 打印空心菱形set talk offclearset color to 7+/1n=0@1,1 say"请输入菱形的边长:n=" get nread?for i= 1 to n& for j=n-i to 1 step -1&&& ??" "& endfor& ??"*"& if i&&1&&& for j=1to 2*i-3&&&&& ??" "&&& endfor&&& ??"*"& endif& ?endforfor i= 2 to n& for j=i-1 to 1 step -1&&& ??" "& endfor& ??"*"& if i&&n&&& for j=2*(n-i)-1 to 1 step -1&&&&& ??" "&&& endfor&&& ??"*"& endif& ?endfor
发表评论:
TA的最新馆藏[转]&}

我要回帖

更多关于 vfp6.0产品id 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信