ppt怎么制作网页表单制作流水号

博客访问: 23855
博文数量: 17
注册时间:
IT168企业级官微
微信号:IT168qiye
系统架构师大会
微信号:SACC2013
分类: Linux
Oracle Form. 6i开发的心得(1) 14:48Lab 0: Prepare
&& 环境:服务器LINUX,安装EBS11.5.10环境
&&&&&&&&& 工作站 XP-2 安装Oracle Form. 6i开发工具 路径:C:\OracleDev6i_new
先期准备:
&&&&&&& 配置tnsname.ora , C:\OracleDev6i_new\NET80\ADMIN
&&&&&&& Eg:&&&&&&&&&&
&&&&&&&&&&&&&&& (DESCRIPTION=
&&&&&&&&&&&&&&&&&&&& (ADDRESS=(PROTOCOL=tcp)(HOST=172.24.12.63)(PORT=1521))
&&&&&&&&&&&&&&&&&&&& (CONNECT_DATA=
&&&&&&&&&&&&&&&&&&&&&&&&& (SID=VIS)
&&&&&&&&&&&&&&&&&&&&& )
&&&&&&&&&&&&&&&& )
&&&&&&&&&&& 用FTP工具将服务器上EBS_Sys/visappl/11.5.0/au/forms/US路径下appstand.fmb , template.fmb文件,EBS_Sys/visappl/11.5.0/au/resource路径下所有后缀名为.pll的文件下载到C:\OracleDev6i_new\FORMS60路径下或者是注册表中oracle/formpath键值对应的某个路径下
Lab 1: Architecture
&&& 该部分介绍了如何在EBS中定义APPLICATION。
&&& 首先在系统中定义DEMVC用户,授予Application Developer和System administrator的 Responsibility,这两个Responsibility在随后的设置中会经常用到,可以说是开发中必须使用的两个Responsibility
&&&& 我在系统中定义下图所示的Application, Application和 Short Name在后续的forms、menus、concurrent programs和other application components设置中会经常用到,short name不应包含空格、长于四个字符并且不能和系统中其它Application重名,建议取名与Application全名意义相关,Basepath中输入的是服务器上环境变量的名字,该变量会被解析成服务器的对应路径,存放开发好的form文件(.fmx)及其相关的外部文件等。&&
其中AU_TOP路径下存放了许多共享文件,该路径下的doc、forms、resource子路径可以存放客制化的帮助文件、appstand.fmb和referenced forms、.pll库文件。
&举个例子来说,我曾经把客户机上开发的form直接上传到server的DEM_TOP路径下,直接在该路径下编译生成.fmx文件。
&& cd $DEM_TOP/forms/US& ;
f60gen module=DEMVCEOR userid=apps/apps
虽然编译、输出也能成功,但是生成的窗体在运行时总是有问题。
于是我将客户机上开发的form先上传到server的DEM_TOP路径下,编译后在DEM_TOP路径下生成.fmx文件
&& cd $AU_TOP/forms/US&
f60gen module=DEMVCEOR userid=apps/apps output_file=$DEM_TOP/forms/US/DEMVCEOR.fmx
& 这样就一点问题也没有了。
& 我想原因是存放在DEM_TOP路径下的.fmb文件在编译时无法获得依赖的文件或资源,虽然生成了可执行文件,但是因缺少依赖项不可用。
&至于诸如AU_TOP、DEM_TOP的环境变量是如何对应操作系统路径的,是因为在Sever端APPL_TOP路径下的.env文件设置了系统的环境变量,此外APPL_TOP/admin路径下的adovars.env文件可设置Custom Applications的环境变量。
& 实在对象如表格、Sequence、索引等建在本应用对应的Schema表空间中,其他代码对象如packages, views, procedures, functions, and triggers创建在Apps Schema下,常见错误是把表建在Apps Schema下,又来建别名,这个时候删除别名时会报对象不存在,而建别名的时候又报对象已存在。Apps Schema应创建其他用户对象的synonyms或者得到授权访问这些对象。
&& 这些结构,自底向上依次创建。
&& 随后的工作是Register Oracle User(Schema) [因为我使用的是Apps,该步省略)]——Add Your Application to a Data Group(我设置Data Group为Standard,Oracle ID为APPS)——Create a Responsibility——Create an Application User(这个我先前已创建过DEMVC用户)——Register Your Tables(这个步骤是针对那些需要用到flexfields or Oracle Alerts的tables,在本练习中有提及但是没有用到,系统已经预先定义好了,我们直接拿过来用就行了)
&Oracle Form. 6i开发的心得(2) 14:50Lab 2: Menus and Function Security
&& 在这章主要学习了如何设置Menus和 Functions的结构,使其显示在Navigation Windows中
& 设置次序为:
&& Forms——Functions(form. function / Subfunction)——Menus and Submenus——Responsibilities——Applications
&& 定义Forms时,注意Application代表该form属于哪个Application(定义Application时Application字段的内容),form字段必须和生成的.fmx同名,User Form. Name字段填写的内容在随后的Function窗口中将被用来标示该form。
& 下图定义了名为DEMVCEOR的form,也就是说在Server端$DEM_TOP\forms\US路径下必须生成名为DEMVCEOR.fmx的可执行文件。注意:User Form. Name-“TEAM VC DEMO ORDERS”会在后面的设置中用到。
& 定义Functions时,Description选项卡中Function 的内容唯一标示一个function,在启动窗体的代码里有时会用到Function的内容用于判断某个function的可用性(随后会有用到该情况的练习,个人认为subfunction这样使用的比较多)。User Function Name的内容会在用户将function添加到menu时用以标示该function和出现在Navigator窗体右侧的top ten list中。Description 内容我觉得是出现在Navigator窗体左侧用以标示该窗体。Form. 选项卡中form字段可以根据定义forms时的User Form. Name选出,Parameters的字段我没设,好像本练习没用到。
& 随后的工作是为Menu添加Submenu和function,比较简单。其中User Menu Name在向Responsibility中添加menu时用来标示menu; Sequence 我的理解就是menu的代号,用于描述menu和submenu之间的结构;Navigator Prompt内容会出现在Navigator窗体左侧用以标示该menu。Description: Navigator 窗体functions选项卡上方menu路径下的menu描述。
&然后就可以在Responsibility窗体中添加Menu或function了。&
&最后在User窗体中添加Responsibility。
Lab 3: Container Objects
&下面就真正开始进入Oracle form的开发。拷贝template.fmb的副本,打开后重命名为在定义Forms时form字段的名字,必须这样命名,否则系统找不到该form的可执行文件,我的窗体文件就叫DEMVCEOR.fmb
& 可以这么认为,最大的容器对象是Form,一个form可以包括多个window,一个window可以包括多个canvas,canvas又分content canvas,tab canvas和stacked canvas,content canvas上可以容纳tab canvas和stacked canvas,一个canvas又可以布置多个item;另一个体系是data,一个form可以包括多个datablock,一个datablock可以包括多个item。我觉得item是连接data和layout的桥梁,如果是基于数据库的item,就必须指定Database Item属性为Yes,并为Column Name属性赋相应值。若该Item需要显示在Canvas上,那就必须指定该Item的Canvas属性。除此之外,还需为每个canvas指定其对应的window属性。
&& 可以在block的属性中设置scroll bar属性;如果block要显示的是单条记录的话,设置Navigator Style属性为Same Record,如果要显示的是多条记录的话,设置Navigator Style属性为Change record;假如block的数据源是基于复杂视图的话,Key Mode属性设为Non-Updateable;
&&&& 在设置master-detail blocks时,在master block中可以设置许多控制master-detail行为的属性。例如:Master Deletes,Coordination等。Relation应当创建在master block中。我在练习中曾犯过这样的错误,在master和detail blocks中设置了相同的Relation,结果挂到系统里一看detail block中的数据怎么也出不来,同事告诉我这是因为两个block中的Relation形成了死锁。他还说如果要删除detail block的Relation,应在master block的data block wizard中进行,反之亦然。我自己在object navigator里直接删除了detail block的Relation,结果也没问题,所以我就没用他的方法。
&& 此外,还需设置各个block的顺序,如果没有显式指定各个block的Previous Navigation Data Block和Next Navigation Data Block,那么导航顺序将默认为各个
Block在object navigator中的顺序。此外module的Navigation Block属性将决定窗口打开时展现的block及其所在的Canvas、window。此外,最好将每个block的主键字段的item-level Primary Key属性设为Yes。
在本练习中,我还遇到了练习中遇到的第一个trigger,在后面的一节我会重点总结trigger。
还有一点不可忽视的是,对于object navigator中窗体的每个对象,都应尽可能地设置正确的Property Class,否则在Form. 6i中设计的对象在窗体被挂到系统中时无法正常显示,我被该问题困扰许久,直到问过同事才搞清楚,Form窗体的大多数对象都有对应的Property Class,开发时应一一设上。&Oracle Form. 6i开发的心得(3) 14:51Lab 4: Widgets
这个练习主要介绍了各种widget。
无论是在region、block还是在window中,item的导航顺序(Tab)总是从左到右,从上到下。
1.Text Items
&& 可以根据需要为Text Items设置不同的Property Class。大多数情况下property class—TEXT_ITEM,只读文本框property class—TEXT_ITEM_DISPLAY_ONLY,多行文本框property class—TEXT_ITEM_MULTILINE,日期文本框property class—TEXT_ITEM_DATE,WHO日期文本框 property class—CREATION_OR_LAST_UPDATE_DATE,百分数文本框property class—TEXT_ITEM_PERCENT_FIXED。
  Validate from List—Yes意味着配合LOV使用的Text Items可以根据输入的内容自动在LOV中寻找对应的内容。
2. Display Items
Display Item应当设置的足够宽以显示数据库中取出的内容。
3. Check Boxes
&&& Check Boxes需要设置一个数据库内容对应的值。还有一类比较特殊的Check Boxes(property class—CHECKBOX_COORDINATION),用以控制Master-Detail Block的关联行为,在随后的练习中能看到。
4. Buttons
可设置Access Key。
5. Option Groups
&& 必须设定缺省值。
6. Poplists
&& 在可选值不超过15个情况下,Poplists是个不错的选择。和.net平台下的dropdownlist控件类似,它也有List Elements和List Item Value(大写字母)之分,对Poplists的编程应对应List Item Value。应尽量避免将Poplists设为multi-row blocks的首字段。
LOV可以比Poplists容纳更多的记录,而且设置上也比较复杂,随后有专门的练习。
8. Descriptive Flexfields
关于Key弹性域和描述性弹性域后面的练习会有更详细的说明,我觉得这个东西有点难理解,暂且把它当成某个数据库字段来用了。
Lab 5: Layout
上图反映了Layout的一般顺序。
布局设置:Format—>Layout Options—>Ruler中可以设置Content Canvas标尺的间距;Format—> Ruler设置是否在Layout界面中显示标尺栏;Format—> Grid设置是否在Layout界面中显示间距点;Format—> Snap to Grid设置是否以设定大小进行控件在Layout界面中的移动;Format—> Show View设置是否在Layout界面中显示window的尺寸;Format—> Show Canvas设置是否在Layout界面中显示Content Canvas;
对于各个Item来说,考虑到界面转译的需要,应尽量给prompt、label等描述性字段留出足够的空间。
Coordination Check Boxes是个比较特殊的对象,如果Master-Detail Blocks分属不同的windows,Coordination Check Boxes应放在Detail Blocks所在window的右上方。否则如果Master-Detail Blocks在同一window中以分界线隔开,Coordination Check Boxes应放在分界线右边window最右边3个字符的位置。还有一种布局与folder title有关,放在folder title line最右边3个字符的位置。
Lab 6: Enhance Items: Create LOVs
LOV相对于Poplists来说,可以容纳的记录更多,使用起来也更加灵活。
创建正确的LOV的前提是创建正确的Record Group,顺序是:在select语句中选择需要的column—>选择需要显示的column—>设置column的title和description —> 设置column的Return Value—>指定能使用该LOV的item—>设置LOV的Title和尺寸。
如果LOV在发现符合查询条件的返回记录只有一条时,自动选择该记录。如果查询到的记录很多的话,设置Automatic Refresh—> Yes,系统会缓存这些记录。
对于和LOV配合使用的其它item对象来说,必须指定其List of Values属性。&Oracle Form. 6i开发的心得(4) 14:52Lab 7: Coding with PL/SQL&
&& 我觉得这节是学习form开发的重点和难点。这一节里又会出现很多的概念、术语、以及和Oracle数据库相关的一些知识。
&& 首先我花了些时间去搞清楚Handler的概念,于.net平台下的事件驱动机制类似,form也依靠events,不同点在于form把这些事件分了form,block,item三个层次,以trigger的形式面向开发者。而Handler就类似于处理事件的函数,不同的是Handler既可以位于database server层,又可以位于application server层。通常这些handlers被封装在package对象中,调用方式如:package_name. handler_name。按照作用对象的不同,Handler又可以分为Item handlers、Event handlers、Table handlers三类。
1.Item Handlers&
Item Handlers 经常会在多种trigger触发的时候被调用,比如一个Item会在WHEN-VALIDATE-ITEM、WHEN-NEW-RECORD-INSTANCE和初始化的时候被触发,每种触发事件的处理方法又不一样,于是定义如下的Handlers,并在相应的trigger中调用。
PROCEDURE item_name (EVENT VARCHAR2) IS
IF (EVENT = ’INIT’) THEN
... /* your code here */
IF (EVENT = ’WHEN_NEW_RECORD_INSTANCE’) THEN
... /* your code here */
IF (EVENT = ’WHEN_VALIDATE_ITEM’) THEN
... /* your code here */
2. Events Handlers
在某个Event发生时,可以调用多个对象的与该 Events相关的Events Handlers,需要注意的是Events Handlers必须以该Event命名。
3. Table Handlers
&& Table handlers主要支持block-level views的insert、update、delete和locks操作。
&&& 那么这些代码究竟是存放于database server层,还是存放于application server层?有这样的标准:调用Oracle Forms built-ins和直接引用数据库字段(我的理解是硬编码的)的Procedures,放在application server层;调用数据库Procedures的、使用多个表和程序的和大型的(>64k)Procedures,放在database server层。Oracle建议:复杂的SQL代码尽量放到database server层;尽量用存储过程参数的形式代替直接引用数据库字段的形式;而且对于某些Procedures的使用,根据实际情况可以同时放在database server层和application server层。
4.编码标准
&&& Oracle提出了一下的编码标准来提高性能:
&&&&& *引用字段时,使用BlockName.ItemName的形式;
&&&&& *使用亚元直接用dual,不要用sys.dual和system.dual;
&&&&& *使用object IDs获得更好的性能;
x_id := find_item(’block.item’);
/* your code here */
&&&&& *总是使用显式游标;
&&&&& *超过64k的Package存放与database server层,每个Package包含的Procedures和Functions总数不超过25;
&&&&& *处理好异常;(本练习接触的不多)FND_MESSAGE显示系统信息,FORM_TRIGGER_FAILURE停止application层的事务,APP_EXCEPTION.RAISE_EXCEPTION停止database层的事务,此外还需编码处理可预计的database server异常。
&&&& 同时Oracle还建议尽可能用Application语法代替Forms built-ins;
* FND_FUNCTION.EXECUTE代替OPEN_FORM;
*不要使用CALL_FORM;
* do_key(‘exit_form’)代替EXIT_FORM;
* do_key(‘commit_form’)代替COMMIT;
* do_key(‘edit_field’)代替EDIT_FIELD/EDIT_TEXTITEM;
5.Examine工具
最后我还要提一下一个很有用的调试工具,当系统运行时,窗体Menu:Help–>Tools–>Examine,可以在这个工具中查看系统变量,全局变量,操作系统环境变量,SQL*PLUS变量,用户概要文件设置以及显示/隐藏的字段值。虽然我现在还不大熟悉这个功能,直觉告诉我能否用好这个工具也是高手与菜鸟的区别之一。
Lab 8: Controlling Windows
&& 这节练习主要介绍了如何对windows进行控制。概括起来包括:打开windows,关闭windows,控制master-detail windows。
& 在分别介绍之间,先来了解以下windows的动作规则:
&& *在非模型窗体中不要使用button编码关闭窗体,使用关闭箭头或menu项;
&& *可以通过CASCADE, RIGHT, BELOW, OVERLAP or CENTER参数设置detail window 与master window之间的相对位置;
&& *Context-dependent titles remain in context这个没大理解,估计说的是动态生成window title依赖于那些在title中出现的字段;
&& *在query模式下window不能被关闭;
&& *关闭window后并不会自动执行commit操作,除非开发人员编码提交;
&& *关闭parent window时系统会提醒用户是否保存detail window变化;
&& *关闭window后,焦点会离开该窗体返回previous block所在windows;
&& *关闭master window会自动关闭其所有detail windows和其相关的find windows;
*关闭first window会退出form。&Oracle Form. 6i开发的心得(5) 14:521.打开windows
一般情况下 会在form-level的pre-form. trigger中调用app_window.set_window_position函数来指定the first window.
FND_STANDARD.FORM_INFO('$Revision: 115.12 $', 'Demo Order Form', 'DEMVCEOR', '$Date:
17:12& $', '$Author: appldemvc $');
app_standard.event('PRE-FORM');
app_window.set_window_position('ORDERS', 'FIRST_WINDOW');
其它情况下,如使用键盘切换当前Block或用button打开窗体时,需使用APP_CUSTOM.OPEN_WINDOW函数,APP_CUSTOM.OPEN_WINDOW 中又会调用app_window.set_window_position。如果是Master-Detail Block需要建立coordination关系的,在APP_CUSTOM.OPEN_WINDOW('LINES')时,调用APP_WINDOW.SET_COORDINATION('OPEN-WINDOW', :CONTROL.ORDERS_LINES, 'ORDERS_LINES');
PROCEDURE LINES(EVENT VARCHAR2) IS
& IF (EVENT IN ('WHEN-BUTTON-PRESSED', 'KEY-NXTBLK'))
&&& THEN APP_CUSTOM.OPEN_WINDOW('LINES');
&&& FND_MESSAGE.DEBUG('Invalid event passed to orders.lines: '|| EVENT);
END LINES;
可在Block-level的KEY-NXTBLK trigger 或Block-level的when-button-pressed trigger中调用这些PROCEDURE;需要注意的是这些代码请先在app_custom包中改写,对应包中的注释,可以很好理解OPEN_WINDOW的逻辑。
总结一下打开windows的逻辑:1设置windows位置;2重置master-detail关系(如有需要的话);3导航到window中的一个block。
2.关闭windows
关闭windows的逻辑可参看app_custom.close_window函数及其注释,不难发现步骤1是判断该窗体是否处于query-mode,是的话不允许关闭;2判断该window是否为the first window,是的话调用app_window.close_first_window函数;3假如window是Detail window的话,延迟其与Master window的同步同步关系(APP_WINDOW.SET_COORDINATION)并GO_BLOCK(' previous-block ')。最后是Hide_Window。
此处我有个疑问:Oracle文档一直提是延迟(defer)而不是重设coordination,难道close windows时会自动使coordination check box变成‘DEFERRED’,一直不解。另外Hide_Window是不是也仅使window不可见,而不是使其在内存中卸载。
3.控制master-detail windows
master-detail windows的行为控制需通过coordination check box来表现,coordination check box创建在Control block下,Property Class –> CHECKBOX_COORDINATION。coordination check box选中与否决定其取值是‘IMMEDIATE’还是‘DEFERRED’。如果coordination check box选中的话,即使焦点在Master window时,Detail window中数据会于Master window同步;如果coordination check box没有选中,Detail window的内容不会于Master window同步,直到焦点落在Detail window时,系统才会执行查询更新数据。这个过程自己试验一下会非常的清楚。使用coordination check box必须在其WHEN-CHECKBOX-CHANGED trigger中重置Master-Detail windows的同步关系。
PROCEDURE orders_lines(EVENT VARCHAR2) IS
&&& IF (EVENT = 'WHEN-CHECKBOX-CHANGED') THEN
&&&&& APP_WINDOW.SET_COORDINATION (EVENT, :CONTROL.ORDERS_LINES, 'ORDERS_LINES');
&&&&& FND_MESSAGE.DEBUG('Invalid event passed to control.order_lines '|| EVENT);
&&& END IF;
END orders_
4. Set Context-Dependent Window Title
&&&& 动态设置相关联的窗体标题依靠APP_WINDOW.SET_TITLE函数,注意在两类trigger中需要调用它。一类是Block-level的pre-record和on-insert trigger,另一类是相关联字段的when-validate-item trigger,我一直没搞清楚pre-record trigger为什么要调用APP_WINDOW.SET_TITLE函数。
Lab 9: Tabbed Regions
这节的内容让我记忆犹新,痛定思痛,不为别的,就为它让我郁闷了好几天,出现了错误却怎么也找不到原因。事情是这样的:根据练习的要求,我在Object Navigator中创建了多个canvas并且按要求将各个widget分布其上,然后在Form. 6i环境中编译成功,随后上传到服务器上重新编译,却总是报有个canvas上的item超界,无法生成可执行文件。检查了许久,发现不了错误,郁闷的重做一遍情况还是如此;无奈,请教同事,告知,在content canvas中添加tab canvas和stacked canvas时,需在content canvas的layout edit中创建,在Object Navigator中创建的将不会出现在content canvas上,因此即使item超界也发现不了,这才如梦方醒,真是麻烦啊!
关于Stacked Canvas尺寸和位置的设置,从属性窗口中发现有两套位置体系:一是Viewport X Position,Viewport Y Position,Viewport Width,Viewport Height;二是Viewport X Position on Canvas,Viewport Y Position on Canvas,Width,Height。试验了一下发现决定Stacked Canvas尺寸和位置的是第一套体系,修改参数后可在layout editor中看出明显的差别。而第二套体系参数修改后Canvas没什么变化,而且看的操作提示中所有Stacked Canvas的Viewport X Position on Canvasà0,Viewport Y Position on Canvasà0,Width,Height值分别比Viewport Width,Viewport Height值略大而已。我想这套体系总是有作用的,只是我不知道而已,请不吝赐教。
对于某个block的scrollbar,是可以修改其canvas属性的,决定scrollbar显示在指定的canvas上。
Tabbed Regions的行为特性:
*主键字段和fixed字段一样,最好放在fixed field stacked canvas,不要放在可变区;
*tab控制列表可从键盘激活(好像没碰到);.
*利用tab键导航item时能够跨越tab页;
*tab页可以根据需要动态地启用和禁用;
*Tabs must remain operable in query by example mode(不理解)
Tab-related Built-ins
&Set/Get_tab_page_property (canvas.tabpage...)
– ENABLED&&&&& – LABEL&&&&& – VISIBLE
Set/Get_canvas_property (canvas...)
– TOPMOST_TAB_PAGE
Set/Get_view_property (canvas...)
– VIEW_X/Y_POS&&&&& – HEIGHT&&&& – WIDTH
Tab-related Variables
:SYSTEM.TAB_NEW_PAGE
– name of the tab page the user clicked on
:SYSTEM.EVENT_CANVAS
– name of canvas that owns the newly-selected tab page
:SYSTEM.TAB_PREVIOUS_PAGE
– name of the tab page that was topmost before the user clicked on the new one
Dynamically Changing Tabs
Dynamically hide tabs only at form. startup.
– set_tab_page_property(...VISIBLE)
Dynamically enabling/disabling tabs.
– set_tab_page_property(...ENABLED...)
此外是与tab相关的trigger,在About Trigger节介绍。&Oracle Form. 6i开发的心得(6) 14:53Lab 10: Currency Fields
这节练习主要介绍如何动态控制item的显示格式和动态生成非database item。尽管是以currency number为例,对于其他类型的字段,处理方式可以借鉴
1.动态控制item的显示格式
在Block-level的Post--query trigger和Item-level的when-validate-item trigger调用handler,控制显示格式。
PROCEDURE FORMAT_PRICE(EVENT VARCHAR2) IS
& IF (EVENT IN ('WHEN-VALIDATE-ITEM','POST-QUERY'))
APP_ITEM_PROPERTY.SET_PROPERTY('LINES.SUGGESTED_PRICE',FORMAT_MASK,&&&&& FND_CURRENCY.GET_FORMAT_MASK(:ORDERS.CURRENCY_CODE,GET_ITEM_PROPERTY('LINES.SUGGESTED_PRICE',MAX_LENGTH)));
&&& APP_ITEM_PROPERTY.SET_PROPERTY('LINES.TOTAL_PRICE',FORMAT_MASK,&&&&& FND_CURRENCY.GET_FORMAT_MASK(:ORDERS.CURRENCY_CODE,GET_ITEM_PROPERTY('LINES.TOTAL_PRICE',MAX_LENGTH)));
&&&&&&& FND_MESSAGE.DEBUG('Invalid event passed to lines.format_price '||EVENT);
END FORMAT_PRICE;
2.动态生成非database item
在Block-level的Post--query trigger和Item-level的when-validate-item trigger调用handler,仍可动态生成非database item的值。前一个trigger在从数据库中获取记录时起作用,后一个trigger在修改记录后起左右,使得非database item随着database item值的改变而改变。
PROCEDURE TOTAL_PRICE(EVENT VARCHAR2) IS
& IF (EVENT IN ('WHEN-VALIDATE-ITEM','POST-QUERY'))
:LINES.TOTAL_PRICE:= NVL(:LINES.ORDERED_QUANTITY,0)*NVL(:LINES.SUGGESTED_PRICE,0);
&&& FND_MESSAGE.DEBUG('Invalid event passed to lines.total_price '||EVENT);
END TOTAL_PRICE;
Lab 11: Runtime Behavior.
&& 这节练习主要介绍了在运行时怎样对各种类型的Item(日期、数字、字符串等)进行控制。
&& 日期型的Item往往会使用Calendar LOV,要点在于:LOV—> ENABLE_LIST_LAMP,Validate from List LOV—>No,Item-level KEY-Listval trigger调用CALENDAR.SHOW;且trigger属性Execution Hierarchy—>Override,fire in enter-query mode—>No。
&&& Form还经常会用到sequence,往往是在插入记录前,需要一个流水号,作为插入记录的主键字段。
PROCEDURE ORDER_ID(EVENT VARCHAR2) IS
& CURSOR C IS
&&& SELECT DEM_ORDERS_S.NEXTVAL FROM DUAL;
& IF (EVENT='ON-INSERT') THEN
&&& OPEN C;
&&& FETCH C INTO :ORDERS.ORDER_ID;
&&& IF (C%NOTFOUND) THEN
&&&&& CLOSE C;
&&&&& RAISE NO_DATA_FOUND;
&&& END IF;
&&& CLOSE C;
&&& FND_MESSAGE.DEBUG('Invalid event passed to orders.order_id: '||EVENT);
END ORDER_ID;
此段代码会放block-level on-insert trigger中被调用,而且应放在insert_row过程之前执行。
如果有title依赖Master window的Detail window,那么在Master window插入新记录时,应立即随后设置Detail window的title。
Eg:(on-insert trigger)
ORDERS.ORDER_ID('ON-INSERT');
ORDERS.INSERT_ROW;
LINES.LINES_TITLE('ON-INSERT');
除了这些,还有很多控制格式的API,如:APP_MUMBER,APP_DATE,FND_DATE,FND_CURRENCY,需要的时候再去手册中查阅。
Lab 12: Conditionally Dependent Items
这节练习主要是介绍窗体上各个widget之间的Dependencies控制。Dependencies
我觉得这种控制的关键在于:1确定具有Dependencies关系的items,2正确设置这种Dependencies控制逻辑,3在恰当的时刻调用这些逻辑。
Dependencies关系有多种,比如说一个item依赖一个item,多个item依赖一个item,一个item依赖多个item等。
控制逻辑也有多种,比如说一个item只在另一个item非空时才被激活;一个Item只在另一个item满足某些特定条件时才被激活;一个item从非激活状态变成激活状态后不能为空;一组Item同时只能有一个Item可被赋值;一组Item如果有一个Item被赋值,其他Item也一定要被赋值;当被依赖的item值发生变化时,依赖项值立刻被清空等。
我们经常会在以下的trigger中调用Dependencies控制逻辑:PRE-RECORD,when-create-record, when-validate-item,when-checkbox-changed, when-radio-changed,when-list-changed和‘INIT’事件。我觉得PRE-RECORD和INIT是在操作数据前初始化这些逻辑,而其他是在item发生变化后验证这些逻辑,满足条件则进行后续的动作。
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
:block.master_item = CONDITION,
’block.dependent_item’);
APP_FIELD.SET_DEPENDENT_FIELD(EVENT,
((:block.master_item1 IS NOT NULL) AND
(:block.master_item2 IS NOT NULL)),
’block.dependent_item’);
APP_FIELD.SET_EXCLUSIVE_FIELD(EVENT,
’block.item1’,
’block.item2’,
’block.item3’);
APP_FIELD.SET_INCLUSIVE_FIELD(EVENT,
’block.item1’,
’block.item2’);
APP_FIELD.SET_REQUIRED_FIELD(EVENT,
(CONDITION),
’block.item’);
Oracle建议使用APP_ITEM_PROPERTY.SET_PROPERTY API函数取代SET_ITEM_PROPERTY (Oracle Forms built-in函数)动态设置Item的属性。可以设置的属性有:DISPLAYED,ENABLED,ENTERABLE,ALTERABLE (item instance level),ALTERABLE_PLUS (item level),REQUIRED。
设置Item有两种方式:根据Item_ID和根据Item_NAME。
Syntax Using Item ID
item_id:= Find_item(’block_name.item_name’);
app_item_property.set_property(item_id,
property_name,
note_item_id := Find_item(’orders.note’);
app_item_property.set_property(note_item_id,
REQUIRED, PROPERTY_ON);
Syntax Using Block.Item_Name
app_item_property.set_property(
’block_name.item_name’,
property_name,
app_item_property.set_property(’orders.note’,
DISPLAYED, PROPERTY_OFF);
与之相对应的是可以使用APP_ITEM_PROPERTY.GET_PROPERTY API函数取代GET_ITEM_PROPERTY (Oracle Forms built-in函数)动态获取Item的属性。
设置Item-level和Item-instance-level属性时需特别的注意,Item-level属性影响所有的记录,而Item-instance-level属性只影响特定的记录(我的理解是当前行)。对于诸如INSERT_ALLOWED,UPDATEABLE和NAVIGABLE等属性来说,是能够在item level和item-instance level重复设置的。如果在item-level设成OFF,而在item-instance level设成ON ,重复设置的最终效果仍是OFF。如果同时设了ALTERABLE和ENABLED,可能最终效果也不会像预期的那样。所以碰到这样的情况时要特别小心。
&&&& 此外,本节还提到一些有关User Profile的知识,好像没什么具体示例,没大搞明白,留待以后研究吧。&Oracle Form. 6i开发的心得(7) 14:55Lab 13: Message Dictionary
本节介绍如何在窗体中使用Message。使用Message应该是挺简单的,主要是两个步骤:设置Message和显示Message。
1.&&&& 设置Message
我觉得按照是否需要在Message Dictionary定义Message可以分为两种。下图显示的是在Message窗体中定义了一个名为DEMVC_SHIP_BEFORE_ORDER的Message。
Oracle建议Name采用大写字母加下划线的命名方式,Application就是需要用到该Message的Application,Language当前语言(应该与后面的翻译有关),Number在显示的时候有时会用到(前面还会带前缀,不填的话就不出现,前缀也会省略),Current Message Text就是要显示的文本了,带’&’的则说明该Message带参数,图中的Message就有&ORDERDATE和&SHIPDATE两个参数。
定义Message信息时除了语法、语义上的注意事项外,还需遵循一些编码规范。比如说:定义的参数最好有特定的含义并且易于区分,尽量不要将一些仅表达语义的短语作为参数传入(因为Oracle在翻译Message的时候默认不会翻译参数,相当于这些参数都是硬编码的)。
在Message Dictionary定义完Message后,在窗体中显示Message之前,还需要在窗体中定义Message。步骤为1FND_MESSAGE.SET_NAME设置MESSAGE_NAME和Application Short Name;2 FND_MESSAGE.SET_TOKEN设置MESSAGE参数,注意必要时对参数进行格式转换。
IF (EVENT = 'WHEN-VALIDATE-ITEM') THEN
&IF :ORDERS.DATE_SHIPPED IS NOT NULL THEN
&& IF :ORDERS.DATE_SHIPPED < :ORDERS.DATE_ORDERED THEN&&
&&& FND_MESSAGE.SET_NAME('DEM','DEMVC_SHIP_BEFORE_ORDER');&
FND_MESSAGE.SET_TOKEN('ORDERDATE',APP_DATE.DATE_TO_CHARDATE(:ORDERS.DATE_ORDERED),FALSE);
&&& FND_MESSAGE.SET_TOKEN('SHIPDATE', APP_DATE.DATE_TO_CHARDATE(:ORDERS.DATE_SHIPPED),FALSE);
&&& FND_MESSAGE.ERROR;
有些Message并不需要先在Message Dictionary中定义,只需在窗体中定义后就可直接调用,如:
/* Set up a specific string (from a variable) and show it */
FND_MESSAGE.SET_STRING (sql_error_message);
FND_MESSAGE.ERROR;
/* Set up a specific string and show it */
FND_MESSAGE.SET_STRING (’Hello World’);
FND_MESSAGE.SHOW;
下例展示了FND_MESSAGE.RETRIEVE函数的用法。我的理解是必须在服务器端执行APP_EXCEPTION.RAISE_EXCEPTION过程后才RETRIEVE到信息。
FND_MESSAGE.SET_NAME (’FND’, ’FLEX_COMPILE_ERROR’);
FND_MESSAGE.SET_TOKEN (’PROCEDURE’, ’My Procedure’);
APP_EXCEPTION.RAISE_EXCEPTION;
/* Retrieve an expected message from the server side,
then show it to the user */
FND_MESSAGE.RETRIEVE;
FND_MESSAGE.ERROR;
/* Then either raise FORM_TRIGGER_FAILURE, or exit
再来看下fnd_message.get的用法,我感觉有点像赋值。
fnd_message.set_name(appl_short_name,message_name);
fnd_message.get(window_title);
set_window_property(’WINDOW_NAME’, TITLE,
window_title);
2.显示Message
&&& 显示Message使用FND_MESSAGE API函数,根据需要选用。
? FND_MESSAGE.ERROR to display an error
? FND_MESSAGE.WARN to display a warning
? FND_MESSAGE.QUESTION to display a question
? FND_MESSAGE.SHOW to display an informational message
? FND_MESSAGE.HINT to display a hint
还有一点比较遗憾,练习中提及可以设置外部文件,获取和写入Message信息,我试了,好像有报错,可能是路径不对,以后再研究吧&Oracle Form. 6i开发的心得(8) 14:55Lab 14: Flexfields
&&&& 刚开始看这一节的文档时,觉的Flexfields的概念很难理解,生吞活剥地按照步骤做完这一练习,再联系后面几节的练习又生吞了一遍文档,Flexfields的面貌才渐渐清晰过来。
&&& 学完了这节,我才知道为什么Orders表中会有atrribute1~attribute9这几个奇怪的字段。
&&&& Flexfields分为两种,Key Flexfields和Discriptive Flexfields,Flexfields中包含的字段叫做segment。尽管使用Flexfields的目的都是使系统获得更加具有柔性的数据结构,但是两种Flexfields的作用、组成结构和使用时机都有很大的不同。
1. Key Flexfields
&&&& 在我看来,Key Flexfields可以看作是Keys的集合,这些Keys每个都对应与数据库中的一个字段。而且每个Key Flexfield都对应一个Combination Table,按照Combination Table的不同使用Key Flexfields主要可分为三类:一是Combinations Form(Maintenance Form), Key Flexfield对应的字段的基表就是Combination Table,Table中会包括structure id和很多segment字段,segment字段记录那些Keys的值;二是Form. with Foreign Key Reference ,基表中Key Flexfield对应的字段作为外键引用了Combination Table中的主键字段,同样改Table中也会包括structure id和很多segment字段。通过查看Combination Table的记录,我觉得该表包含了多个Key字段的所有可能的组合(如果Key很多的话,这样是不是重复太多了);三是Form. with a Range Flexfield ,使用这种类型的Flexfield,并不需要真正绑定一个Combination Table,只需在一个Table设置structure id和多个segment N_LOW、segment N_HIGH字段,多用于出报表的情况。
&&&& 使用Key Flexfield时,由于可为每个Key Flexfield定义多个structure(对应上段提及的structure id),因此在系统中根据商务规则的需要动态的改变Key Flexfield的structure。从下图可看出,title为Accounting Flexfield的Flexfield具有多个structure。
2. Discriptive Flexfields
&&&& Discriptive Flexfields相对来说比较容易些,没有那么多类别,依赖的基表就是Form的基表,表中包含了Attribute Catalog和多个Attribute N字段,至于Attribute Catalog字段我个人觉得和Key Flexfield中的structure id字段功能类似,不知道是否正确。
&&& 与定义Key Flexfield类似,定义Discriptive Flexfields时定义一个Flexfield时不过指定对应的Application和Base Table,就是向指定场所和提供了原材料,至于如何将这些原材料组合成什么样的structure以及这些structure中的segment又有什么特殊的要求,其实是在Segment窗体中设置的。
3.开发Flexfields的步骤
*设计合理的Combination Table表结构,根据Flexfield的类别,创建相应的Combination Table并设计合适的attribute、segment、structure id、attribute catalog等字段。
*在Form. 6i中创建Flexfield:
Discriptive Flexfield:property class—〉TEXT_ITEM_DESC_FLEX,List of Values—〉ENABLE_LIST_LAMP&
Key Flexfield:List of Values—〉ENABLE_LIST_LAMP&
如果是Range Flexfields,就创建2个field。
*调用Flexfield的API函数,在Form-level的when-new-form-instance trigger中调用。
? FND_DESCR_FLEX.DEFINE for descriptive flexfields
? FND_KEY_FLEX.DEFINE for key flexfields
? FND_RANGE_FLEX.DEFINE for range flexfields
FND_DESCR_FLEX.DEFINE和FND_KEY_FLEX.DEFINE参数有所不同。
FND_KEY_FLEX.DEFINE(
BLOCK=>’LINES’,
FIELD=>’ACCTG_FLEX_VALUES’,
ID=>’GL_ACCOUNT_CC_ID’,
APPL_SHORT_NAME=>’SQLGL’,
CODE=>’GL#’,
NUM=>’101’);
FND_DESCR_FLEX.DEFINE(
BLOCK=>’ORDERS’,
FIELD=>’DESC_FLEX’,
APPL_SHORT_NAME=>’DEM’,
DESC_FLEX_NAME=>’DEM_ORDERS’);
这种区别和不同Flexfield的定义方法有关。
此外在Form-level的下列trigger中,加入后面的函数。如果在block/item-level上override了这些trigger,在处理代码中加上后面的函数。Block/ item-level的POST-QUERY trigger,Execution Hierarchy--à‘After’。
PRE-QUERY&&&&&&&&&&&&&&&&&& FND_FLEX.EVENT(‘PRE-QUERY’);
POST-QUERY&&&&&&&&&&&&&&&&& FND_FLEX.EVENT(‘POST-QUERY’);
PRE-INSERT&&&&&&&&&&&&&&&&&& FND_FLEX.EVENT(‘PRE-INSERT’);
PRE-UPDATE&&&&&&&&&&&&&&&&& FND_FLEX.EVENT(‘PRE-UPDATE’);
WHEN-VALIDATERECORD&&&&& FND_FLEX.EVENT(‘WHEN-VALIDATE-RECORD’);
WHEN-NEW-ITEMINSTANCE&&& FND_FLEX.EVENT(‘WHEN-NEW-ITEMINSTANCE’);
WHEN-VALIDATE-ITEM&&&&&&& FND_FLEX.EVENT(‘WHEN-VALIDATE-ITEM’);
&& 另外TEMPLATE form在下列form-level triggers调用的APP_STANDARD.EVENT 过程直接调用了FND_FLEX函数。如果在block/item-level上override了这些trigger,在处理代码中加上后面的函数。
KEY-EDIT&&&&&&&&&&&&&&&&&&&& APP_STANDARD.EVENT(‘KEY-EDIT’);
KEY-LISTVAL&&&&&&&&&&&&&&&& APP_STANDARD.EVENT(‘KEY-LISTVAL’);
POST-FORM&&&&&&&&&&&&&&&&&& APP_STANDARD.EVENT(‘POST-FORM’);
*在系统中注册Flexfield
&&& 注册Key Flexfield时,可以使用Qualifiers来设置Key之间的规则,Columns设置包含的可用列(尽管不会全被用到),KFV View Name和定义Descriptive Flexfield时DFV View Name类似,是一种特殊的View,用于生产报表,其名字我无法更改,猜想是系统根据Table Name自动生成。(假如一个Table使用了两个Description Flexfield,DFV View Name该如何命名?)
*在系统中定义Flexfield
定义Flexfield,Key Flexfield实际是用Segment窗体定义Structure及其对应的Segments,Descriptive Flexfield是用Segment窗体定义Context及其对应的Segments,每个Segment的值还可通过Value Set ,Segment Value去控制,具体的设置方法我就没有深入研究了。
最后我总结一下Flexfield的使用步骤:首先定义合理的Combination Table,这个是必须的前提。然后在系统里注册并定义需要的Flexfield,接着在Form. 6i中添加Flexfield字段并设置好属性,最后在Form-Level的when-new-form-instance trigger中调用函数设置Flexfield到相关字段,注意在相应级别的trigger中添加处理函数或修改属性。&Oracle Form. 6i开发的心得(9) 14:56Lab 15: Query Find
Query Find的主要作用是在Non-Query状态下查询记录,而且比query mode要灵活方便。主要有两类用法:Row-LOV和Find window。所有queryable block都应该支持这两种用法中的一种,否则主菜单中ViewàFind…/Find All会报错。
1. Row-LOV
Row-LOV类似与普通LOV,在下列情况下适于使用:
*一次只返回一条记录,特别适合single row block;
*在detail block中自动查询关联master block的所有记录;
*基于主键而不是其他属性查询记录;
*数据量很少的情况。
下面是创建Row-LOV的步骤:首先创建一个parameter用于存储返回的Primary Key,接着创建合适的Row-LOV设置Primary Key返回给parameter,再创建block-level PRE-QUERY trigger (Execution Hierarch—>Before)
&&& IF :parameter.G_query_find = 'TRUE' THEN
&&& :lines.order_line_num := :parameter.ORDER_LINE_NUM_QF;
&&& :parameter.G_query_find := 'FALSE';
最后创建block-level QUERY_FIND trigger (Execution Hierarch—>Override)
app_find.query_find('ORDER_LINES_QF');
2. Find window
Find window在下列情况下适于使用:
*一次返回多条记录,特别适合multi-row block;
*需要多个查询条件关联进行复杂查询的;
*数据量很多的情况。
创建Find window的步骤相对比较复杂::
* 从APPSTAND.fmb中拷贝QUERY_FIND Object Group到开发窗体的.fmb文件中,此时开发窗体中会自动多出生成新的Window、Canvas、Block。删除拷贝过来的QUERY_FIND Object Group,然而新生成的对象不会被删除,合理设置这些对象的property classes属性;
*重命名这些新对象,比如:ORDERS_QF,ORDERS_QF_CANVAS,ORDERS_QF_WINDOW;
*修改Find Windows的title名为“Find ”;
* 编辑NEW Button的WHEN-BUTTON-PRESSED Trigger;
app_find.new('ORDERS');& results block name& 这个函数使得Find Window关闭回到原来的Block,创建一条新记录。
*编辑FIND Button的WHEN-BUTTON-PRESSED Trigger;
& :parameter.G_query_find := 'TRUE';
app_find.find('ORDERS');& results block name
:parameter.G_query_find := 'FALSE';
如果查询到数据,则关闭Find Window关闭回到原来的Block,显示查询到的记录。
*编辑Find block-level的KEY-NXTBLK Trigger
& :parameter.G_query_find := 'TRUE';
app_find.find('ORDERS');
:parameter.G_query_find := 'FALSE';
作用与FIND Button相同。
&&&&& Find block的Previous Navigation Data Block应设为results block,应保证用户即使不作查询也能退出Find Window。而通过导航Block进入Find Window也是不推荐的。
*开发Canvas
   在Find Canvas上创建所需的Item,所有的Item都可为空,default values均设置为NULL;Check boxes和option groups都改为允许空值的poplists;唯一可以设置Item logic的字段类型是LOV,使用时注意Find Window不要和results Window共用LOV,因为Find Window的返回值会同时返回到results Window中,但是Find Window要和results Window共享Record Groups,保证数据一致性;创建那些在查询中要用到的隐藏字段;创建Item时,可从results block上拷贝,但要注意设置所有item为non-database items,正确的canvas、property class属性,删除所有item的trigger,保留或修改date fields的Calendar控制逻辑。
  *合理设置Find Window的大小
*创建Results Block-Level PRE-QUERY Trigger (Execution hierarchy of Before),将Find Window中的值拷贝到results Window中。
IF :parameter.G_query_find = 'TRUE' THEN
& :orders.order_id := :ORDERS_QF.ORDER_ID;
& app_find.query_range(:orders_qf.date_ordered_from,
&&&&&&&&&&&&&&&&&&&&&& :orders_qf.date_ordered_to,
&&&&&&&&&&&&&&&&&&&&&& 'ORDERS.DATE_ORDERED');
& COPY (:orders_qf.order_status, 'ORDERS.ORDER_STATUS');
& :orders.customer_id := :ORDERS_QF.CUSTOMER_ID;
& COPY (:orders_qf.customer_name, 'ORDERS.CUSTOMER_NAME');
& :orders.sales_rep_id := :ORDERS_QF.SALES_REP_ID;
& COPY (:orders_qf.sales_rep_name, 'ORDERS.SALES_REP_NAME');
& if&& :orders_qf.payment_type is not null then --判断poplist是否非空
&&&&&& COPY (:orders_qf.payment_type, 'ORDERS.PAYMENT_TYPE');
 :parameter.G_query_find := 'FALSE';
  *创建Results Block-level QUERY_FIND trigger (Execution hierarchy of Override)打开Find Window
app_find.query_find('ORDERS',
&&&&&&&&&&&&&&&& 'ORDERS_QF_WINDOW',
&&&&&&&&&&&&&&&& 'ORDERS_QF');
注意使用Find Window时不要设置Find Window和Results Window的Item同步,减少cross-field validation的使用,当Find Window没有查到数据时,焦点仍然停留在该窗体中。&Oracle Form. 6i开发的心得(10) 14:57Lab 16: Advanced Function Security
  在Lab2中我们了解了Basic Function Security,这是一种基于responsibility、menu和function(功能)的管理机制。Advanced Function Security将考虑更加详细的安全机制,用户是否有权使用某个form中的某个subfunction,是否有权看见form的某个部件,是否有权打开新的窗体等等。
对于这种安全控制策略,我的理解是这样的:首先在系统里定义一个subfunction,然后把它挂到某个responsibility的menu下,然后在form里判断登录的responsibility是否具有对form里特定function的使用权限,激活或禁用这些function。
定义subfunction时,还要在Form选项卡里选择依附的Form,在Property选项卡里将Type设置为subfunction。然后将该subfunction挂到指定的menu下面,下图所示的是把两个用户自定义的Function:VC Demo Form.:SPECIAL和VC Demo Form. DEMVC_DEMVCEOR_PRINT_ORDER挂到了TEAM VC MENU的下面,注意因为它们的Prompt字段没有赋值,因此它们不会出现在Object Navigator中,实际上也不需要出现。
如果不把subfunction挂到menu下面,用户将无法访问该subfunction 。
然后在form的pre-form. trigger中调用FND_FUNCTION.TEST函数验证登录用户的权限:
IF (FND_FUNCTION.TEST('DEMVC_DEMVCEOR_PRINT_ORDER')) THEN
&&&& --处理代码;
处理代码往往是激活或禁用一些窗体部件,比如buttons, windows, fields, alternative regions等。实际也是激活或禁用某些窗体功能。
此处我有个疑问,我定义的Function如果Type设置为subfunction,系统就会报错。设置为Form,其他不变,运行正常,百思不得其解。
  Oracle EBS还允许客制化Form的菜单栏。
用户最多可以定义45个form-level的trigger,名称必须为SPECIALn,其中SPECIAL1 to SPECIAL15属于Tools菜单项,SPECIAL16 to SPECIAL30属于Reports菜单项, SPECIAL31 to SPECIAL45属于Actions菜单项,其中Reports、Actions的名称可以被修改。
初始化示例:
&  IF (FND_FUNCTION.TEST('DEMVC_DEMVCEOR_PRINT_ORDER')) THEN
& app_special.instantiate('SPECIAL1','&Print Order');
& app_special.enable('SPECIAL1',PROPERTY_ON);
& app_special.instantiate('SPECIAL2','Specia&l 2 Line', '',TRUE,'LINE');
&&& app_special.instantiate('SPECIAL3_CHECKBOX','Spe&cial 3 Box w Line', '',TRUE,'LINE');
&&& app_special.set_checkbox('SPECIAL3_CHECKBOX','TRUE');
&&& app_special.instantiate('SPECIAL4_CHECKBOX','Special &4 Box');
&&& app_special.set_checkbox('SPECIAL4_CHECKBOX','TRUE');
&&& app_special.instantiate('SPECIAL18','Specia&l 18 Line SEP', separator=>'LINE');
&&& app_special.instantiate('SPECIAL32','Specia&l 32 Line', '',TRUE,'LINE');
&&& app_special.instantiate('SPECIAL33','Specia&l 33');
&&& app_special.instantiate('SPECIAL30','Specia&l 30');
&&& app_special.instantiate('SPECIAL31','Specia&l 31 Line','',TRUE,'LINE');
&&& app_special.instantiate('SPECIAL45','Spe&cial 45');
&/* and display a button on the form. */
&&& app_item_property.set_property('orders.print_order',
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& DISPLAYED, PROPERTY_ON);
&&& app_item_property.set_property('orders.print_order',
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& DISPLAYED, PROPERTY_OFF);
&&& END IF;
app_special.instantiate设置菜单项的文字说明,app_special.enable设置菜单项是否可用,app_special.set_checkbox设置check_box菜单项的选定状态。
在form-level的SPECIALn trigger中,定义了这些菜单项选中后的处理代码,如下所示:
& demvceor.PRINT_ORDER('SPECIAL1');
 if (app_special.get_checkbox('SPECIAL3_CHECKBOX')='TRUE') then
&&&& fnd_message.debug('Special 3 is True!');
&&&& fnd_message.debug('Special 3 is False!');
  右键菜单也可以自定义,form-level PRE-POPUP-MENU trigger引用APPSTAND.EVENT('PRE-POPUP-MENU')建立default menu;建立block /item level pre-pop-menu trigger须(Execution Hierarchy àAfter)。
从block /item level pre-pop-menu trigger(Execution Hierarchy àAfter)中调用 app_popup.instantate函数初始化右键菜单项:
   procedure APP_POPUP.INSTANTIATE(
option_name varchar2,
txt varchar2,
initially_enabled boolean default true,
        separator varchar2 default null);
   Example
  ? This example results in a menu that has a line above the second custom entry and
   has the third custom entry grayed out (disabled)
APP_POPUP.INSTANTIATE(
‘POPUP1’,’First Entry’);
APP_POPUP.INSTANTIATE(
‘POPUP2’,’Second Entry’, TRUE, ‘LINE’);
APP_POPUP.INSTANTIATE(
‘POPUP3’,’Third Entry’, FALSE);
  右键菜单的处理函数写在名为POPUP1 through POPUP10的trigger中,应该在正确的level上建立这些trigger (通常是block/item level)。
Lab 17: Setting Up Attachments
我觉得Oracle中这个功能很好,就像在不破坏基表结构的前提下,动态地创建了若干个非结构化列,既可以存储普通文本,网页,还可以上传文件像word,excel,ppt,mp3等类型文件。比如对一行记录要做大量说明或是音频视频说明的,就可以采用这种办法。
在应用Attachment之前,先要搞清楚几个概念。一是Document Entity,Document Entity 可分为Base Entity和Related Entity,简言之都可以认为是数据库的表,也是Attachment依附的主体。一个Entity中每条记录都可附加多个Attachment,依靠Entity的Primary Key对应。
所以应用Attachment的第一个步骤是定义Document Entity。如下图所示:
另一个是先要搞清楚的概念Document Category,我的理解是Document Category限制了可附加Attachment的类型。所以第二个步骤是定义Document Category。
第三个步骤是定义Attachment Function,Attachment Function必须指定应用的窗体,在下图的Name中选择。Enabled Session Context Field我觉得是应用上下文Title。
接下来在Category窗体中选择第二步定义的Category,可选择多个。
打开Block窗体,下面的设置是关键。Block Declaration窗体中的Context字段与上下文Title有关。
再打开Entity Declaration窗体,设置Privileges选项卡的各项属性,接着再设置Primary Key Fields选项卡的各项,个人觉得这个地方非常重要不能设错。
在系统中运行Form,点击工具条别针型按钮,就可以添加附件了,效果如图所示:
  注意,如果你在某个Form中利用某个Entity的Primary Key应用了Attachment,在系统其他任何Form中,只要引用了该Entity的Primary Key,用户就可以查看基于这些Primary Key的Attachment。&Oracle Form. 6i开发的心得(11) 14:58Lab 18: Concurrent Processing
在系统里我们会经常用到并发处理,最常见的使用是报表以及数据库的操作。所有的并发处理都是由Concurrent Manager进程处理的,这其中包括了很多排队调度的机制以及出错恢复的机制,文档中说的很详细也很复杂。本节仅仅介绍了如何从系统中提交并发请求。提交并发请求的发式有很多种,比如使用Standard Request Submission,使用View/Requests或者使用某个窗体不见引发等等。
下面结合一下使用Concurrent Requests的步骤作进一步的说明。
第一步是建立Concurrent Program Executable,这是建立Concurrent Program的前提,随后建立的Concurrent Program会引用这个Concurrent Program Executable,一个Concurrent Program Executable可以被任意多个Concurrent Program所引用。
上图建立了一个名为DEMVCREPORT的Concurrent Program Executable,在Team VC Order Entry Demo Application中被使用,Execution Method指的是这种Executable的类型(Oracle Report、SQL*Loader、PL/SQL Stored Procedure等),Execution File Name这里指的是DEMREPRT.sql文件。Execution File Path指的是Execution File存放的路径,一般是在Application Basepath对应目录下。
第二步是建立Concurrent Program,Enabled checkbox决定是否立即激活该Concurrent Program;Execution Region中选择上一步定义的Concurrent Program Executable;Request Region中的Use in SRS checkbox决定是否可以在Standard Request Submission窗体中提交request;Output Region是输出设置的常规选项。
Copy to选项卡:可以把当前Concurrent Program的设置拷贝到另一个Concurrent Program中;Session Control选项卡:对当前Session属性进行设置,比如优化模式,回退段等;Incompatibilities选项卡:设置与当前Concurrent Program不可同时处理的其他Program;Parameters选项卡:设置当前Concurrent Program的传入参数。
如下图所示:当前Concurrent Program定义了一个名为Order Number的传入参数,同时还设置了它的验证方式和显示格式。
第三步是建立Concurrent Program Library,由于这一步在练习中没有出现,我也就没做。
  第四步是将Concurrent Program添加到System Administrator Reports request group中。这步说的比较隐晦,初学者往往不知道该怎么做。处理方法其实就是在Responsibility设置Request Group,如果不设的话,Concurrent Request没法用。
完成了以上的步骤后,就可以在系统中提交Concurrent Request。先看一下在SRS中提交的情况。
此外,在Form中也可以提交请求。先期工作如下:在form中添加一个parameter REQ_ID,用以存储concurrent request ID。编写Request的Handler,如下所示:
PROCEDURE PRINT_ORDER(EVENT VARCHAR2) IS
& IF (EVENT = 'SPECIAL1') OR (EVENT = 'WHEN-BUTTON-PRESSED') 
&&&& :parameter.req_id :=
&&&& fnd_request.submit_request('DEMVC',
&&&& 'DEMREPRT','', '',
&&&& FALSE, NAME_IN('ORDERS.ORDER_ID'),chr(0),'','','','','','','','',
&&&& '','','','','','','','','','',
&&&& '','','','','','','','','','',
&&&& '','','','','','','','','','',
&&&& '','','','','','','','','','',
&&&& '','','','','','','','','','',
&&&& '','','','','','','','','','',
&&&& '','','','','','','','','','',
&&&& '','','','','','','','','','',
&&&& '','','','','','','','','','');
&&&& IF :parameter.req_id = 0 THEN
&&&&&&&& FND_MESSAGE.RETRIEVE;
&&&&&&&& FND_MESSAGE.ERROR;
&&&&&&& IF :SYSTEM.FORM_STATUS != 'CHANGED' THEN
&&&&&&&&&&& IF app_form.quietcommit& THEN
&&&&&&&&&&&&&&&& /*form. commits without asking user to save changes*/
       fnd_message.set_name('SQLGL','GL_REQUEST_SUBMITTED');
&&&&&&&&&&&&& fnd_message.set_TOKEN('REQUEST_ID',  
        TO_CHAR(:PARAMETER.REQ_ID), FALSE);
&&&&&&&&&&&&& fnd_message.
&&&&&&&&&&& ELSE
&&&&&&&&&&&&& fnd_message.set_name('FND', 'CONC-REQUEST
        SUBMISSION FAILED');
&&&&&&&&&&&&& fnd_message.
&&&&&&&&&&& END IF;
&&&&  ELSE
&&&&&&&&&&& DO_KEY('COMMIT_FORM');
&&&&&&&&&&& IF :SYSTEM.FORM_STATUS != 'CHANGED' THEN
&&&&&&&&&&&&&&&& /*commit was successful*/
&&&&&&&&&&&&&&&& fnd_message.set_name('SQLGL','GL_REQUEST_SUBMITTED');
&&&&&&&&&&&& fnd_message.set_TOKEN('REQUEST_ID',
       TO_CHAR(:PARAMETER.REQ_ID), FALSE);
&&&&&&&&&&&&& fnd_message.
&&&&&&&&&&& END IF;&&&&&&&&&&&&&
&&&&&  END IF;
&  END IF;
&&&&& fnd_message.debug('Invalid event passed to
&     DEMXXEOR.PRINT_order: ' || EVENT);
END PRINT_ORDER;
然后在form-level的Special1和PRINT_ORDER Button的when-button-pressed Trigger中调用处理代码。
demvceor.PRINT_ORDER('SPECIAL1');
我在练习中做到这一步,在窗体中提交Request报错,同事说是由于先前定义的Execution File在系统中不存在,我在网上也没找到该文件的脚本,因此这节练习也就做到这里了。&Oracle Form. 6i开发的心得(12) 14:59Lab 19: Implementing Zoom Use the Custom Library
使用CUSTOM library可以在不修改Oracle Application代码的情况下实现Oracle Application功能的扩展,在下面的情形下,会使用到CUSTOM library,当然每种情况的处理代码也不一样。
? Zoom—从当前窗体获得参数又打开另一个窗体;
? Logic for generic events—对某些form. events的控制等,比如WHEN–FORM–NAVIGATE,WHEN–NEW–FORM–INSTANCE,WHEN–NEW–BLOCK–INSTANCE,WHEN–NEW–RECORD–INSTANCE,WHEN–NEW–ITEM–INSTANCE,WHEN–VALIDATE–RECORD,EXPORT,KEY–Fn (where n is a number between 1 and 8);
? Logic for product–specific events—对某些product–specific events的控制等,比如WHEN–LOGON–CHANGED,WHEN–RESPONSIBILITY–CHANGED;
? Custom entries for the special menus—添加客制化菜单的功能SPECIALn (where n is a number between 1 and 45);
? Setting visual attributes —运行时修改visual属性等。
有些问题在使用前先弄清,在customer library中WHEN–FORM–NAVIGATE,WHEN–NEW–BLOCK–INSTANCE,WHEN–NEW–RECORD–INSTANCE或者WHEN–NEW–ITEM–INSTANCE只在form/block/item level的同名trigger触发后才触发;WHEN–NEW–FORM–INSTANCE会在调用app_standard_event时触发,如form when-new-form-instance的app_standard_event.(when-new-form-instance);
WHEN–VALIDATE–RECORD会在调用app_standard_event或 fnd_flex.event时触发(form/ block level);SPECIALn在同名trigger触发前触发;ZOOM靠(View–>Zoom)或工具条按钮触发;EXPORT靠(File–>Export)触发;KEY–Fn在按下corresponding function key或key combination触发。在Help–>Keyboard菜单项可以找到快捷键。
下面我介绍如何利用CUSTOM library使用Zoom功能。
首先在窗体中添加两个parameter:ORDER_ID和CUSTOMER_NAME;
然后修改ORDERS block的WHERE clause属性,该block应是目标block,即目标窗体所对应的block,我认为这样改的目的兼顾非Zoom下的查询和匹配先前定义parameter的查询;
WHERE (:parameter.order_id is null or
    dem_orders_v.order_id like :parameter.order_id)
AND (:parameter.customer_name is null or
    dem_orders_v.customer_name like :parameter.customer_name)
接着在WHEN–NEW–FORM–INSTANCE trigger中添加下列代码:
/* fire automatic query if a parameter has a value from Zoom */
if (:parameter.order_id is not null) or (:parameter.customer_name is not null) then
GO_BLOCK('ORDERS');
do_key('EXECUTE_QUERY');
/* clear the parameters after the query so they don’t remain
criteria for future queries */
:parameter.order_id :=
:parameter.customer_name :=
目的在于每次处理完Zoom Event后清空相关parameter。
  最后我在CUSTOM.PLL文件中作了如下的修改:
function zoom_available return boolean is
&&& form_name& varchar2(30) := name_in('system.current_form');
&&& block_name varchar2(30) := name_in('system.cursor_block');&
&&& if (form_name = 'DEMVCEOR' and block_name = 'ORDERS')
&&&&& return TRUE;
&&&&& return FALSE;
& end zoom_
  这个函数会在form-level when-new-form-instance trigger的
app_standard.event(when-new-form-instance)中被调用,用来判断是否可以激活工具条上的Zoom图标按钮。
procedure event(event_name varchar2) is
&&&& form_name&&&&& varchar2(30) := name_in('system.current_form');
&  block_name&&&& varchar2(30) := name_in('system.cursor_block');&
&&  param_to_pass1 varchar2(255);
&&  param_to_pass2 varchar2(255);
&& if (event_name = 'ZOOM') then&&
&&&&& if (form_name = 'DEMVCEOR' and block_name = 'ORDERS') then
&&&&&&& param_to_pass1 := name_in('ORDERS.order_id');
&&&&&&& param_to_pass2 := name_in('ORDERS.customer_name');
&&&&&&& fnd_function.execute(FUNCTION_NAME=>'DEMVC_DEMVCEOR',&
&&&&&&  & OPEN_FLAG=>'Y', SESSION_FLAG=>'Y',&
&&&&&&&&&&& OTHER_PARAMS=>'ORDER_ID="'||param_to_pass1||
&&&&&&&&&&& '" CUSTOMER_NAME="'||param_to_pass2||'"');
&&&&&&&&&&&&&&&&&
  这个过程就是Zoom事件的处理函数,它的传入参数包括了两个预先定义的参数,form_name和block_name。注意fnd_function.execute函数的作用就是打开一个新窗体,该窗体使用了传入的参数。该过程也会在系统预先定义好的form-level ZOOM trigger的appcore_custom.event('ZOOM')中被调用。
做完以上步骤后,就可以在系统中使用ZOOM功能了,可是我很遗憾的失败了。探究原因可能是由于编译CUTOM.PLL生成的CUTOM.PLX方法不对。
我的方法:
f60gen module=CUTOM.PLL userid=apps/apps module_type=LIBRARY;
查看文档后觉得可能是:
f60gen module=DEMVCEOR userid=apps/apps COMPILE_ALL=Yes output_file=$DEM_TOP/forms/US/DEMVCEOR.fmx
  我想既然系统不自动激活ZOOM图标,那么我就自己写代码显式激活,然后显式调用处理函数,于是做了下面的工作。
在Orders block-level的when-new-block-instance trigger中添加了下列代码:
SET_MENU_ITEM_PROPERTY('VIEW.ZOOM',ENABLED,PROPERTY_TRUE;
在form-level的zoom trigger中改写成下列代码:
custom.event('ZOOM');
重新编译生成后就可以,如下图所示:
& 到这里,我就做完了这个关于Form的练习,完成之后算是对开发Form的过程、重点、难点有了个大致的了解。后面是一些总结,当是补充吧,内容实现太多了,就怕自己过两天又忘了。
&Oracle Form. 6i开发的心得(13) 15:00Lab 20: About Trigger1. Pre-form. trigger
&& FND_STANDARD.FORM_INFO
('$Revision: 115.12 $', 'Demo Order Form', 'DEMVCEOR', $Date:
17:12& $', '$Author: appldemvc $');
app_standard.event('PRE-FORM');
app_window.set_window_position('ORDERS', 'FIRST_WINDOW');
demvceor.pre_
&& Pre-form. trigger调用APPCORE Routing APIS的APP_WINDOW.SET_WINDOW_POSITION和FNDSQF Routing APIS的 FND_STANDARD.FORM_INFO函数,这些函数在template.fmb的Pre-form. trigger中已经存在,但是必须改变这些函数的参数值,窗体才能正常使用。
& 2. Record history (WHO): Track Data Changes
在练习中我发现一个奇怪的现象,在Block-Level的Pre-insert和Pre-update的trigger中都调用了FND_STANDARD.SET_WHO;而且在Order和Line Block中都包括了下表所示的几个字段。
请教过同事,他说一般的ebs的oracle table中都会包括这几个字段,主要用于数据处理的跟踪,调用FND_STANDARD.SET_WHO函数后系统将自动完成对这几个字段的操作过程,如果是并发程序,还会用到下面的几个字段。
我觉得这种字段设置方式对我们开发其它系统也是一个很好的启发。
3. Triggers in TEMPLATE
&前面已经提过,forms的开发大多由template.fmb修改而成,template窗体本身就预包含了许多标准格式的form-level的trigger,等待开发者修改。在这之中,必须要修改的trigger有:PRE-FORM;可能要修改的trigger有:KEY-CLRFRM,POST-FORM,QUERY_FIND,ACCEPT;在Block或Item Level可以添加的trigger有WHEN-NEW-RECORD-INSTANCE,WHEN-NEW-BLOCK-INSTANCE,WHEN-NEW-ITEM-INSTANCE,KEY-DUPREC,KEY-MENU,KEY-LISTVAL,QUERY_FIND,ACCEPT,ON-ERROR等。
&4. Coding Triggers
&& 创建Trigger时要特别注意Trigger的Execution Hierarch属性。一般情况下Block或Item-Level Triggers的Execution Hierarch属性—>Before,但是以下两种情况例外:一是定义用户右键菜单的,Block或Item-Level Triggers的Execution Hierarch属性—>After;二是窗体中某个字段使用了form-level POST-QUERY trigger,那么block-level POST-QUERY trigger的Execution Hierarch属性—>After。
&&&&& 以下是oracle给出的Block或Item-Level Triggers的Execution Hierarch属性的限定:必须设置为Before的trigger有WHEN-NEW-RECORD-INSTANCE, WHEN-NEW-BLOCK-INSTANCE,WHEN-NEW-ITEM-INSTANCE;可以设置为Override的trigger有KEY-DUPREC,KEY-MENU,KEY-LISTVAL,QUERY_FIND, ACCEPT。
5. Tab Triggers
&& 与Tab相关的trigger,一个是form-level的when-tab-page-changed,另一个是block-level的when-new-item-instance。when-new-item-instance trigger处理由于tab键导航引起的tab问题,逻辑相对比较简单。when-tab-page-changed trigger则比较复杂,对着代码我也不很明白。我个人觉得处理逻辑是这样的:先判断current_canvas是不是fixed_stacked_canvas,是的话就将show_view(target_canvas)在go_item,不是的话就将target_canvas设为tab_topmost_page,然后show_view(target_canvas)在go_item。总之,要保证target_canvas一定会show出来。我的理解可能有误,希望知道的同仁能够告诉我正解,实在是复杂。
6.自己的一些感想
说到Trigger,个人觉得就是Oracle Form控制逻辑的精要,后面很多章节的Trigger我就不在这里再单单列出了。我想总结一下使用Trigger要注意的地方:
*Trigger的level 什么样的Trigger放在什么样的level上,什么样的Trigger放在多级level上,注意此时的Execution Hierarch属性该怎么设;
*Trigger该调用什么样的处理代码,有些Trigger调用API函数,有些调用客制化过程,虽然内容很多,但是一类Trigger调用了一类API,应多加熟悉;
*Trigger的执行顺序,这个很多网上都有详尽的说明;
*Trigger中多个处理过程的执行顺序,这个地方在某些时候是需要特别注意的。&Lab 21: Naming Standard
当年在用.net编程就因变量、控件命名不符合规范经常被老师骂,当时还不服气,现在越来越觉得命名规范的重要性,所以在新学习一门开发技术的时候,就要养成良好的命名习惯,以免日后积重难返。
1. Form. Objects命名标准
Module应与Form文件名匹配,最好由大写连续的英文字符组成,中间无任何分隔符;
  Window,canvas,block,item的命名应当简洁而有意义,一般是以对象名称命名。特殊的block 应用特殊的命名,比如TOOLBAR,CONTROL,CONTEXT;
  Query–Find Canvasses,Windows,Blocks,LOVs和Related Record Groups
命名如QF_object;
   Relations命名如master_detail
2. Subfunction 命名标准
开发人员需预先在系统中为form定义受限的subfunction。
Subfunctions的命名标准为 _
Eg:PO_POXPOMPO_DELETE AR_FNDRSRUN_LISTING_RPTS
User function的命名标准为 :
Eg:Purchase Orders: Delete& Run Reports: Listing
这种统一的命名规范使得系统管理员可以在Responsibilities窗体中利用LOV的Auto-reduction方便地查到某个responsibility下的可用或不可用的functions(我这种理解可能值得商榷)
  如果对于某个特定的form存在许多受限的subfunction,可以将这些subfunction分类分组。
3. Program Unit命名编码标准
Program Unit中package命名多以对象名为主,常常和Block重名,为每个Block创建一个同名的package也易于管理。
Package中的function和Procedure命名多重用Item的名字,定义一个传入参数event,代码对应多个事件的一一处理分支,调用起来很方便。另外就是以下划线为分隔符命名,可能是某种事件,trigger,某个特定含义。
PACKAGE ORDERS IS
PROCEDURE Insert_R
PROCEDURE Update_R
PROCEDURE Lock_R
PROCEDURE Delete_R
PROCEDURE PRE_UPDATE;
PROCEDURE PRE_INSERT;
PROCEDURE lines(EVENT VARCHAR2);
PROCEDURE ORDER_ID(EVENT VARCHAR2);
PROCEDURE PAYMENT_TYPE(EVENT VARCHAR2);
PROCEDURE CHECK_NUMBER(EVENT VARCHAR2);
PROCEDURE CREDIT(EVENT VARCHAR2);
PROCEDURE DATE_SHIPPED(EVENT VARCHAR2);
PROCEDURE DESC_FLEX(EVENT VARCHAR2);
PROCEDURE VISA(EVENT VARCHAR2);
怎样从Oracle的FORM中调用REPORT
从Oracle的FORM中调用REPORT:
◆在菜单中调用REPORT程序(注释:不传参数,传参数可用下面的程序段)
Run_Product(REPORTS, '报表程序名.REP', SYNCHRONOUS, RUNTIME, FILESYSTEM, '', NULL);
◆在FORM中调用REPORT程序(注释:可以传参数)
DECLAREpl_id ParamLBEGINpl_id := Get_Parameter_List('参数列表名');IF NOT Id_Null(pl_id) THENDestroy_Parameter_List( pl_id );END IF;pl_id := Create_Parameter_List('参数列表名');Add_Parameter(pl_id,'REPORT参数名1',DATA_PARAMETER,':FORM项名1');Add_Parameter(pl_id,'REPORT参数名2',TEXT_PARAMETER,':FORM项名2');… …Run_Product(REPORTS, '报表程序名.REP', SYNCHRONOUS, RUNTIME, FILESYSTEM, pl_id, NULL);END;&
◆在报表中使用参数作为帮定变量时在其前面加一个冒号(:),例如:有一个参数p_deptno,传来的值为10,则select * form. emp where deptno=:p_deptno将返回表emp中deptno为10的记录。
◆在报表中使用参数作为词汇参数时在起前面加一个“与”符号(&),例如:有一个参数p_where,传来的值为where deptno=10,则select * from emp &p_where也将返回表emp中deptno为10的记录。
◆在在调用REPORT时,去掉report server:
Add_parameter(pl_id,'ORACLE_SHUTDOWN',TEXT_PARAMETER,'YES');
◆在调用REPORT时,使报表结果直接输出到打印机上:
Add_parameter(pl_id,'PSRAMETER_FORM',TEXT_PARAMETER,'NO');
◆在调用REPORT时,不弹出参数窗口:
add_parameter(pl_id,'PARAMFORM',TEXT_PARAMETER,'NO');
◆在调用REPORT时,以满屏方式显示:
add_parameter(pl_id, 'maximize', TEXT_PARAMETER,'yes');
阅读(5388) | 评论(0) | 转发(0) |
相关热门文章
给主人留下些什么吧!~~
请登录后评论。

我要回帖

更多关于 微信表单制作 的文章

 

随机推荐