Progress学习.doc_第1页
Progress学习.doc_第2页
Progress学习.doc_第3页
Progress学习.doc_第4页
Progress学习.doc_第5页
免费预览已结束,剩余27页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

PROGRESS编程其实很简单(一) 一、变量定义。变量必须在第一次被使用之前定义,可以定义在程序的任何地方!但是通常为了增加程序的可读性,变量定义都放在程序的开始处!以下是变量定义的几个实例:define variable str01 as char 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 条件12、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-LOCK. i = i + 1. DISP pt_part pt_price WITH DOWN FRAME a. IF i 200 THEN LEAVE.END.六、赋值和计算。 * / ,就是 加 减 乘 除了!比如:ttl_amoount = ttl_ammount + dtl_amount.x_a = x_b / x_c.str_ttl = Im + sure!.dt01 = today - 1.dt01 = 3/22/2005. /* 日期 */当然,日期和字符串不能做乘法或者除法!七、其它零星的语法。显示:display 简写disp退出编程模式:quit执行UNIX命令: unix COMMAND好了,这章你学会了,如果熟悉数据库表和字段的结构,你也大概能看任何东西了,甚至做一些常规的统计也肯定没问题! PROGRESS编程其实很简单(二) PROGRESS程序架构。PROGRESS启动应用程序,通常都是先启动一个主程序,比如mf.p,这个mf.p做一些全局变量设置,并初始化应用程序菜单。当用户执行菜单功能时,实际上是运行菜单所指定的程序!在这种模式下,PROGRESS的程序一般都不大,结构明了可读性很强,每个程序目的非常明确,但是也要遵循一定的准则,方便以后的阅读和修改。一、程序扩展名的设定。.p 主程序(可直接运行,或者编译以后挂主菜单被调用).i 子程序(经常使用的执行某一特定功能,或者为了使主程序易于阅读脱离出来).v 验证程序.w Windows的程序(Windows版的Progress支持可视化的组件编程,组件拉一拉放一放,就自动生成.w的文件了).r 编译后的程序(菜单调用时,实际上是执行.r的程序)二、程序的命名规则。主程序格式: aa + bb + cc + dd.p其中:aa - 系统模块IDbb - 系统功能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 = stline2. 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.iform definition selection criteriapart colon 15 part1 colon 40 label t001.ieffdate colon 15 effdate1 colon 40 label t001.iwith 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.iform 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编程其实很简单(三) 这章,重点解释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汇总! progress中的数据库访问1 progress中的数据库是关系型的,具备关系型数据库的基本特征,当然没有像oracle那样复杂了,甚至说比sql server或者my sql都要简单。最简单的还是progress语言访问自己的数据库。这里假定你已经有了自己的数据库(关于数据库的创建和维护,以后再讲),这里主要说怎么开发。1.数据库的连接连接数据库,有两种方式,一个是动态连接,一种是静态连接。所谓的静态连接就是在程序启动的时候数据库作为一个参数直接连接,这个是由prowin32命令实现的,对应的在unix下是_progress命令。prowin32的使用格式如下:prowin32 -p main.p -param paramString -db dbname -T c: emp -H dbserver -S 5000 -pf c:myappdb.pf -ininame c:myappmyapp.ini-P参数,就是指定你的主程序,当然也可以是.w文件-param 就是你要输入的参数。 我们知道,一般的程序或者命令需要参数,这个就是。在c/c+或者java里访问参数是在main函数中,那么 progress怎么获取这个参数呢?这就要说到一个系统句柄session,它有一个parameter属性,可以用这个来访问它。 比如iparameter = session:parameter.整个参数是一个双引号引起来的字符串,如果你又多个参数需要输入,你可以把这下参数合并为一个以某字符分割的字符串列。-db 就是你要连接的数据库名字-T 表示你要使用的临时目录-H 是数据库所在的服务器名字或者IP-S 端口-pf 就是parameter file,也就是说你可以把一些参数写在一个文件里.比如我想连接两个数据库db1,db2;可以写两个文本文件,内容分别是:-db db1 -H dbserver -S 5000和-db db2 -H dbserver -S 5001然后分别存为db1.pf,db2.pf. 你就可以prowin32 -p main.p -df db1.pf -df db2.pf同时连接两个数据库了.设置你还可以在.pf文件里面再次使用-pf参数-ininame你要使用的ini文件,里面定义了你要使用的字体,颜色等等多对应的索引值. 那么动态连接,指的就是在程序文件里在进行连接,比如在main.p里边,可以使用connect语句:connect db-name|value(db-name).比如connect -db mydb1 -H dbserver -S 5000.或者connect value(-db mydb1 -H dbserver -S 5000). 后边的用法通常是可以把你的数据库连接参数化。 如有两个定义一样的数据库但是在不同的服务器上.或者在同一服务器上但是数据库名字不一样,你可以使用-ld选项,ld就是逻辑名.比如connect -db mydb1 -ld mydb2 -H dbserver -S 5001. 那么你就要使用mydb2前缀来引用mydb1数据库,相当于起了个别名。 注意一点的是,接下来访问数据库的语句不能和connect在同一个.p文件中,你必须把访问代码写在另外的.p文件中然后再调用之. 相应的connected(db-name)是一个用来判别数据库是否已经成功连接的函数. disconnect 则是用来断开数据库连接的,比如:disconnect db-name|value(db-name).2.访问数据库中的表和字段假设有这样的一个数据库,名字叫mydb,其中有一张表order:field-name field typeorder-num charcust-num chargoods charquantity decimalorder-related char 这里假定你的开发环境已经连接了数据库(在开发环境中连接数据库是一个简单的事情,你只要按照几个参数-db -H -S填充就行了),那么引用数据库是这样:var1 = mydb.order.order-num. 如果只有一个数据库的话,mydb.可以省略。 当你访问数据库的时候,需要用到以下语句:for each . 和 find.for each table-name where field1 = value1 and field1 = value2 . no-lock: your statement.end.for each 语句的常用方法很简单,就是一个循环。你的表名其实就是一个buffer-缓冲区。progress会把数据库中的纪录取回到当前的缓冲区中。 当你访问数据库的时候,有三种锁可以使用,no-lock,share-lock和exclusive-lock,并且缺省的选项是share-lock.它们三个的区别如下:no-lock:意味着其实progress没有对数据库施加任何限制,在你访问当前记录的时候,别人也可以访问并且修改。exclusive-lock:排他性锁,使用这个选项,则意味着任何别的人都不能访问当前纪录,当然更不能修改了。这个主要是修改时使用的。share-lock: 当你使用share-lock的时候,就意味着别人虽然也可以同时读取该记录的值,但是不能修改它。当你修改当前记录的时候,progress会自动施加exclusive-lock.在你的for循环中,如果下一条记录被人锁定了会怎样呢?它会一直阻塞,直到这个纪录被解锁为止。下面是一个例子:for each order where order.order-num = o00001 no-lock: display order.end.这里的display语句会显示该记录的所有字段。 如果想把显示的结果排序怎么办呢,可以使用by选项。其用法是by field-name descending. 缺省会是ascending升序排列。 如果有多个列需要排序,你可以使用多个by 选项。for each order no-lock by order-num by cust-num descending: display order.end. 下面说一说find语句。find的基本语法是:find first | next | prev | last | current table-name where where clause no-lock|share-lock|exclusive-lock no-wait no-error.find语句会把匹配的纪录取回到当前的缓冲区中。first是返回匹配的第一个记录next,prev,last同样的道理。 具体取回那一条记录,是跟索引相关的。current是把当前的纪录内容重新取回,当然你也可以在此更改你的锁选项。如果没有记录匹配,则当前记录为空。如果要取的纪录被锁定,则find会被阻塞,没有纪录被返回。如果你不想这样的话,就可以使用no-wait选项,这样find会立即返回。如果没有匹配纪录,progress会谈出一个错误警告.如果你不想有这个警告的话,就可以使用no-error选项.那么我们怎么才能知道有没有纪录被返回呢,这里需要用到available函数,其使用方法是 available buffer-name. 如果缓冲区内有记录,则返回真,不然返回假.比如:find first order where order.cust-num = cu001 no-lock no-error.if available order then display order.else message no order for cust-num:cu001.如果是纪录被锁定怎么辨别呢,就要使用locked函数了,其使用为locked(buffer-name).比如上例:find first order where order.cust-num = cu001 no-lock no-wait no-error.if available order then message order ok.else if locked(order) then message order locked.else message no order.find语句中也可以不指定first/next/prev/last/current,而是直接find order where order-num = O001 no-lock no-error. 如果符合条件的记录不止一个的话,会引发一个警告,并且没有纪录被返回,因为它不知道取哪一个.这种情况下怎么分辨没有记录还是有多条记录呢,这就要用到ambiguous函数,其用法为ambiguous buffer-name.find order where cust-num = c001 no-lock no-error.if avail order then message order ok.else if ambiguous order then message more than one order.else message no order.3.什么是bufferbuffer是一个缓冲区,同时也是一个数据类型.你可以定义一个buffer.define new shared buffer buffer-name for table-name.当你要在一个循环内部再次访问该表的时候就要用到buffer了.比如:define buffer border for order.for each order where order.order-num = O001 no-lock: find first border where border.order-related = order.order-num no-lock no-error. if available border then message order ok.end.表的名字就是一个缺省的buffer.4.query另外一种可以用到的方法就是使用query对象.其实query主要是使用在browser控件中的,就是相当于一个表格控件了.定义一个query:define query query-name for table-name/buffer-name cache n scrolling.在定义query的时候,需要预先定义好要是用到的缓冲.并且不能更改.如果需要一个动态查询的话,可以使用动态的query.cache n:表明这个查询可以缓存n条记录.scrolling:表明可以随机查询缓存中的纪录.不然的话只能使用向前或者向后的一一寻找.打开一个查询:open query for each buffer-name .后半部分for each开始基本上就是一个for each语句.如果该查询是在一个browser中的话,则它可以立即返回结果到缓冲区. 不然的话,只能在使用get之后返回到缓冲区.获取纪录:get first|last|next|prev query-name. get的作用就是把纪录从数据库拷贝到buffer中.重新定位:reposition query-name to row n | forwards n|backwards n.reposition只能对采用了scrolling选项的query进行操作.在调用了get之后,要确认是否有记录存在,一个方法是使用availabel语句,另外一种方法就是使用query-off-end函数.query-off-end(query-name). 如果当前没有记录,则返回真.关闭查询:close query query-name.在你关闭查询之后,还可以重新打开,同时使用新的查询字句.define query mq for order cache 5 scrolling.open query mq for each order no-lock.get first mq.repeat while not query-off-end(mq): disp order. get next mq.end.if available order then disp order.else MESSAGE no order.close query mq.如果使用动态查询,以及表的连接该怎么办呢,下一次谈.progress的数据库访问2 1.数据库的连接首先我们假设有这样两张表:表 order:field-name field-typeoid charcustid charref-oid charquantity decimalunit char表 customer:field-name field-typecustid charcustname charcustaddr char这里custid在两张表里起一个联结作用。假如有一个给定的订单号码mo1,想找出和它对应的客户信息:for each(first) order where order.oid = mo1 no-lock, first(each) customer where customer.sutid = order.custid no-lock: display order. display customer.end.因为通常订单号是唯一的,所以for each和for first是一样的效果。同样一个订单只会对应一个客户。如果反过来,已知客户号码名字cname,现在要找到该客户所有的订单:for first(each) customer where customer.custname = cname no-lock, each order where order.custid = customer.custid no-lock: display customer. display order.end.这仍然是一个for语句,要注意,第二个字句直接使用each/first/last即可,不再需要多余的for. 并且如果你想的话,你可以连接两张以上的表。这样的连接是一个自然连接。如果你要使用不等连接,只要改变一下操作符即可。很显然,一个迪卡尔连接是这样的:for each order no-lock, each customer no-lock: disp order. disp customer.end.当然对于这样的连接还有另外一种方法,就是使用嵌套的for语句:for each order no-lock: for each customer no-lock: disp order. disp customer. end.end.当然了,这种方法会慢一些。2.表的自身连接在sql语句中是使用别名来定义自身连接的。在progress中同样如此,不过这里使用的是缓冲区buffer.假定我们要对order这张表进行自身连接,oid=ref-oid:define buffer border for order.for each order where order.oid = o1 no-lock, each border where border.oid = order.ref-oid no-lock: disp order. disp border.end.3.再次介绍buffer作为一个buffer,实际上有两种类型,一种是静态的,一种是动态的。一个静态的buffer,前边已经使用过,现在重复一下作为对比:define buffer buffer-name for table-name.而一个动态的buffer,在变量上它是一个句柄:define variable hbuffer as widget-handle no-undo.create buffer hbuffer for table table-name.这里要注意的是,首先你要声明一个句柄变量,然后使用create语句来创建一个动态buffer.这个语法和define稍有不同。一个是前者有table关键字在表的前面,另外一个是表的名字必须是一个引在引号中的字符串变量。因为是动态的么,所以表的名字也必须是可变的。另外一点是,使用完之后需要释放内存:delete widget hbuffer.或者delete object hbuffer.从一个静态的buffer可以获得它的句柄从而得到一个动态的buffer,就像c/c+语言里的取地址操作符&可以把一个变量转变为指针一样。比如:define variable horder as widget-handle no-undo.horder = buffer order:handle.对于一个动态的buffer对象而言,它不但有自己的属性,还有自己的方法可以调用。访问方法如下:buffer-handle:attribute or buffer-handle:method对于一个buffer对象,最最重要的还是怎么访问各个域,这就要谈到另外一个对象buffer-field. 4.buffer-field对象buffer-field是一个特殊的对象,是因为没有对应的define buffer-field语句来创建一个对应的静态对象。得到一个buffer-field有两种方法:define variable hbf as widget-handle no-undo.1)从对应的buffer对象获得:define variable hb as widget-handle no-undo.hb = buffer order:handle.hbf = hb:buffer-field(orderno). 或者hbf = hb:buffer-field(1).这种方法具有很大的灵活性,特别是结合buffer-field的属性。2)直接获取句柄hbf = orderno:handle in buffer order.下面简单介绍几个buffer-field的重要的属性:属性名 类型 说明available logical 表明该缓冲区是否有记录buffer-handle handle 获取该field所在的buffer句柄buffer-name character 获取该field所在buffer的名字buffer-value(i) 具体的数据类型 该field所包含的值. 如果该field是一个数组的话,就可以使用索引ican-read logical can-write logicaldata-type character 该field所包含的数据类型dbname character 所在数据库名 extent int 返回维数key logical 是否在某一索引中name character field的名字。position int 在buffer中的位置 string-value(i) character 转化为字符串值table character 表名下面是一些重要的buffer的属性以及方法属性名 类型 说明available logical 是否有记录can-create logical can-delete logicalcan-read logicalcan-write logicalcurrent-change logical 是否有变化dbname character 数据库名new logical 该record是否是新创建num-fields int record-length int 长度,单位byterowid rowidtable character 表名table-handle handle table-number in

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论