PROGRESS 编程其实很简单(一)
PROGRESS 编程其实很简单(一)
PROGRESS 编程其实很简单(一)
一、变量定义。
变量必须在第一次被使用之前定义,可以定义在程序的任何地方!但是通常为了增加程序的可读性,变量定义都放在程序的开始处!以下是变量定义的几个实例:
define variable str01 as string label "DemoString" initial "hello".
def var str02 like str01.
def var dt01 as date extent 5.
def var inte01 as inte format ">>>9".
说明,第一行:
str01 是变量名, 变量名不要与系统关键字重复,字符或者下划线开头,比如 strModel,_Model ;
string 表示变量类型,本例指字符型变量,其它类似的比如 integer , date , logical 等 ;
label 就是后续程序中对变量的描述,比如需要用户输入这个变量值时,系统提示 “DemoString" ;
initial 变量的初始值
第二行:
def 和 var 都是简写, def 是 define 的简写, var 是 variable 的简写; PROGRESS 支持语法简写,但是初学者最好先写全,后面有经验了再简写。
like 和 as 的不同点是: as 后面直接说明变量类型,而 like 后面跟另外一个变量或者字段。
第三行:
extent 5 ,表示该变量是数组变量。
第四行:
format ">>>9" 变量格式
指定变量的格式一个最大的好处就是预留宽度,这个对变量的输入或者报表的输出都很有用的。
比如年份的宽度一定是 4 位的,那么你就可以指定格式 format "9999" 。
PROGRESS 程序每行结束必须有个 “.” 号!!!
二、注释。
注释就是用 /* ... */ ,可以嵌套,比如
/*--- 注释 1
/* 注释 2 */
---*/
三、记录的显示。
如果进入 PROGRESS 编程模式以后连接了数据库,那么直接显示记录的值即可,比如:
for each TABLE_NAME:
display TABLE_NAME.
end.
/* 显示 TABLE_NAME 所有字段所有记录 */
或者:
find first TABLE_NAME.
display TABLE_NAME.
/* 显示 TABLE_NAME 第一条记录所有字段的值 */
通常显示记录值都是采用这 2 种方式!当然,可以按要求显示特殊的字段,比如:
for each pt_mstr where pt_model begins "E" no-lock break by pt_price:
disp pt_model pt_price.
end.
这个程序看起来真的很容易明白,简单说明:
1 、 where 后面带条件,比如 = <> <= >= 等等,这种关系符,对数字、日期或者字符串,都适用;
关于条件的几种组合举例:
条件 1 and 条件 2
( 条件 1 or 条件 2 ) and ( 条件 3 or 条件 4)
not 条件 1
2 、 no-lock ,这是关键字,你只要记住:
如果接下来的程序要对记录进行修改,那么不能加 no-lock ,如果不要,请加上 no-lock ;
3 、 break by ,就是按某个字段排列,默认是按这个字段的升序,如果降序则后面加上 desc ,比如:
break by pt_price desc 。
如果需要多次排列,那么 by 几次就可以,比如:
break by pt_price by pt_date
另外一个常用的显示或者更新记录的语句是 find !比如:
find pt_mstr where pt_model = "mainboard" no-lock no-error.
find first pt_mstr where pt_price <= 10 no-error.
find last pt_mstr where pt_price <= 10 no-error.
说明:
1 、 where 后面的条件跟 for each 语句类似;
2 、 no-lock 的作用跟 for each 的 no-lock 也是一样的;
3 、 no-error ,通常是 find 就加上,否则如果找不到满足条件的记录,系统会出错误提示;而实际上,通常需要在程序自己判断结果;
4 、 find first 就是定位第一天满足条件的记录; find last 定位最后一条满足条件的记录;
4 、还有一种叫 find next ,就是定位当前记录的下一条;
5 、 find 和 find first / find last 不同的是, find 后面带的条件,通常是满足 TABLE 的某个唯一索引。
关于 for each 和 find ,这章你只要了解到这里就 OK 了!
四、判断。
判断最简单了,就是一个 if 条件 then ... else ... ,比如:
if str01 = "cpu" then disp "CPU"
else disp "Not CPU".
当然,这个 ” 条件 “ 可能有很复杂的组合。如果,涉及到的动作比较多,那么做法是用 do: ... end. ,比如
if str01 = "cpu" then do:
str01 = "my cpu".
disp "CPU".
end.
else do:
str01 = "my memory".
disp "Not CPU".
end.
if 支持嵌套,怎么嵌套?你自己会了!不是吗?
五、循环。
PROGRESS 的循环功能实在令人不敢恭维,没有 when 没有 while ,没有 loop 、 for 什么的,只有一个 repeat !
不过,用好了这个 repeat ,一样实现任何功能。
通常实现循环的模式:
repeat:
/* 处理事务 */
if 条件 then leave. /* 退出循环 */
end.
现在,你试试用 find 和 repeat 实现 for each 的功能!
六、赋值和计算。
+ - * / ,就是 加 减 乘 除了!比如:
ttl_amoount = ttl_ammount + dtl_amount.
x_a = x_b / x_c.
str_ttl = "I'm" + "sure!".
dt01 = today - 1.
dt01 = 3/22/2005. /* 日期 */
当然,日期和字符串不能做乘法或者除法!
七、其它零星的语法。
显示: display 简写 disp
退出编程模式: quit
执行 UNIX 命令: unix COMMAND
好了,这章你学会了,如果熟悉数据库表和字段的结构,你也大概能看任何东西了,甚至做一些常规的统计也肯定没问题!
Progress编辑其实很简单(二)
程序架构。
PROGRESS 启动应用程序,通常都是先启动一个主程序,比如 mf.p ,这个 mf.p 做一些全局变量设置,并初始化应用程序菜单。当用户执行菜单功能时,实际上是运行菜单所指定的程序!在这种模式下, PROGRESS 的程序一般都不大,结构明了可读性很强,每个程序目的非常明确,但是也要遵循一定的准则,方便以后的阅读和修改。
一、程序扩展名的设定。
.p 主程序(可直接运行,或者编译以后挂主菜单被调用)
.i 子程序(经常使用的执行某一特定功能,或者为了使主程序易于阅读脱离出来)
.v 验证程序
.w Windows 的程序( Windows 版的 Progress 支持可视化的组件编程,组件拉一拉放一放,就自动生成 .w 的文件了)
.r 编译后的程序(菜单调用时,实际上是执行 .r 的程序)
二、程序的命名规则。
主程序格式: aa + bb + cc + dd.p
其中:
aa --- 系统模块 ID
bb --- 系统功能
cc --- 程序类型( mt - 维护、 iq - 查询或者 rp - 报表等)
dd --- 序列号
子程序格式:通常是 主程序 a.i 主程序 b.i 这样子
// 关于程序的命名,个人觉得也没必要一定要遵循特定格式,一家公司有自己固定的命名方式,容易区分即可;如果是咨询公司或者系统集成公司,则要先了解客户的命名习惯和规则;同理,下面的 “ 程序头 ” 。
三、程序头。
以注释的形式,标明尽可能多的程序相关的信息,比如:程序名(路径,不过路径一般都是企业自己规定好了)、作者、菜单号、功能(菜单标题)、创建日期、修改日志等。至于格式,也就是 POSE ,爱怎么摆怎么摆,清楚明了即可。但是,在同一家公司,风格应该统一。另外,关于修改日志,个人觉得最好在程序头和程序体,都明显说明一下修改的日期和原因,要点。(注释不记入程序长度,所以不要担心程序太长, :p )
四、维护类程序模板。
注意:为方便说明,注释暂时用 “//” ,但是在 PORGRESS 程序里是错误的哈!
define variables.
{mfdtitle.i} // 程序头,全局变量定义等,是标准 QAD 的菜单程序就请加上这个,不要问为什么
form with frame a. // 定义格局(包含输入输出)
Mainloop:
repeat:
prompt-for … editing: // 通常这里输入主要字段(如果比如订单号,料件名称等)
{mfnp.i} // 前后记录显示功能,常用
end.
/* ADD/MODI/DELETE */
assign global…
find …
if not available … // 新记录
{mfmsg.i 1 1} // 类似 mfmsg 的子程序,都是信息提示类
create …
assign …
end.
Status = stline{2}.
update go-on (F5 or Ctrl-D) // 继续维护剩余字段
if F5 or CTRL-D then do: // 判断是否按了删除键,一般定义是 F5 或者 Ctrl + D
del-yn = yes.
{mfmsg01.i 11 1 del-yn}
end.
End.
Status input.
五、报表类程序的模板。
{mfdtitle.i}
form definition [selection criteria]
part colon 15 part1 colon 40 label {t001.i}
effdate colon 15 effdate1 colon 40 label {t001.i}
with frame a side-labels width 80.
// 以上 4 行定义用户输入 “ 限制报表输出 ” 的条件,比如生效日期啊什么的
repeat:
if part1 = hi_char then part1 = “”. // 如果用户不输任何东西,则默认最大字符或者最小字符,以下类似
if effdate = low_date then effdate = ?.
if effdate1 = hi_date then effdate1 = ?.
data statements [selection criteria]
bcdparm = "".
{mfquoter.i part } //BATCH 专用,至今没用过,体会不到好处,哪位帮忙解释一下?
{mfquoter.i part1 }
{mfquoter.i effdate}
{mfquoter.i effdate1 }
{mfselbpr.i “printer” 132} // 选择打印机的子程序
if part1 = “” then part1 = hi_char.
if effdate = ? Then effdate = low_date.
if effdate1 = ? Then effdate1 = hi_date.
{mfphead.i or mfphead2.i} // 报表头
for each…
display
{mfrpchk.i} or {mfrpexit..i} // 报表结束
end.
{mfrtrail.i} or {mftr0801.i} or {mfreset.i} // 报表结束、打印结束等
end.
六、查询类程序模板。
这个比报表来得要简单些了:
{mfdtitle.i}
form definition [selection criteria]
with frame a side-labels width 80.
repeat:
data statement [selection criteria] with frame a.
{mfselprt.i “terminal” 80 }
for each [selection criteria]
display …
{mfrpchk.i} (max page)
end.
{mfreset.i} (scroll output)
{mfmsg.i 8 1}
end.
通过这章的学习,你对 QAD 的 PROGRESS 程序已经有大致的了解。但是你可能还是感觉到,如果叫你做一些切实的东西,还摸不着门(什么?你摸得着了,那么恭喜你,你可以请我吃饭了),没关系,才 2 小时呢, 25 %的课程而已,不急不急!
•这章,重点解释 PROGRESS 报表的精髓 first-of() & last-of() 。
首先给出本章教程用到的示例信息 ---demo 表的结构和数据。
因为测试环境只连接了一个数据库,所以本文所有对字段的引用都直接写出来而没有特别指明表名,如果是多数据库环境,则需要带表名。
(比如数据库名是 dtbl ,表名是 demo ,那么对字段的引用应该是: dtbl.demo.mdlno )
【结构】
【数据】
1 、 first-of() & last-of() 的语法;
先看示例:
for each demo break by demo.vend:
if first-of(demo.vend) then disp demo.vend.
end.
/* 结果是显示 hp 和 ibm 两条记录 */
很明显可以看出来的就是,每个 first-of 或者 last-of 对应的字段,必须有 for each ... break by 来对应它,否则语法错误(即使 first-of 的字段是索引也会出错)。
比如以下语句会出错:
for each demo no-lock:
if first-of(demo.vend) then disp demo.vend.
end.
2 、函数的功能;
first-of() 函数的功能,就是通过 break by 对该字段进行排序,然后对该字段相同的记录进行 “ 预览 ” ,当第一次出现时发生!比如,示例中, break by 首先对 demo.vend 进行排序,这样会出现很多 vend 是 “hp” 和 “ibm” 的记录,当第一次出现 “hp” 记录和第一次出现 “ibm” 记录时,各显示一下该 vend 名称。
last-of() 一样,不同的是 “ 最后一次出现时发生 ” !
请看示例:
for each demo break by demo.mdlno:
if last-of(demo.mdlno) then disp demo.
end.
这段程序的结果如下:
通过收货日期和数量等,可以看到,每条记录,都是相同 “mdlno” 的最后一条
3 、应用;
通过以上分析,不知道大家有没有懂的真正的意思呢?
现在如果要实现这样的报表,那又该怎么写程序呢?
对每个 mdlno 收货进行合计,然后在 mdlno 的下一行显示合计数,类似这样的结果:
不看答案自己想想看。
参考答案(为方便阅读暂不用 accum() 函数):
DEF VAR ttl AS DECI.
OUTPUT TO c:\demoout.txt.
FOR EACH demo BREAK BY demo.mdlno:
ttl = ttl + demo.qty.
PUT demo.mdlno demo.rcvdt demo.qty SKIP .
IF LAST-OF(demo.mdlno) THEN do:
PUT " 合计 " ttl SKIP.
ttl = 0.
END.
END.
OUTPUT CLOSE.
说明: first-of 和 last-of 可以对应多个 break by 的字段,比如可以先按 mdlno 汇总,再按 vendor 汇总!
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ljah/archive/2007/10/22/1837494.aspx
浙公网安备 33010602011771号