hoyong

导航

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

posted on 2015-04-09 22:19  hoyong  阅读(1186)  评论(0)    收藏  举报