- UID
- 7453672
- 阅读权限
- 20
- 帖子
- 203
- 精华贴数
- 3
- 技术排名
- 3105
- 技术积分
- 891
- 社区排名
- 26265
- 社区积分
- 5
- 注册时间
- 2006-6-10
- 精华贴数
- 3
- 技术积分
- 891
- 社区积分
- 5
- 注册时间
- 2006-6-10
- 论坛徽章:
- 1
|
发表于 2006-8-23 17:27:33
|显示全部楼层
Lab 0: Prepare
环境:服务器LINUX,安装EBS11.5.10环境
工作站 XP-2 安装Oracle Form 6i开发工具 路径:C:\OracleDev6i_new
先期准备:
配置tnsname.ora , C:\OracleDev6i_new\NET80\ADMIN
Eg:
SATYAM=
(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,在本练习中有提及但是没有用到,系统已经预先定义好了,我们直接拿过来用就行了)
Lab 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,开发时应一一设上。
Lab 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的首字段。
7. LOVS
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属性。
Lab 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中调用。
Eg:
PROCEDURE item_name (EVENT VARCHAR2) IS
BEGIN
IF (EVENT = ’INIT’) THEN
... /* your code here */
END IF;
IF (EVENT = ’WHEN_NEW_RECORD_INSTANCE’) THEN
... /* your code here */
END IF;
IF (EVENT = ’WHEN_VALIDATE_ITEM’) THEN
... /* your code here */
END IF;
END item_name;
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获得更好的性能;
declare
x_id item;
begin
x_id := find_item(’block.item’);
/* your code here */
end;
*总是使用显式游标;
*超过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 ;
Eg:
* 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。
1. 打开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: 2006/07/18 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
BEGIN
IF (EVENT IN ('WHEN-BUTTON-PRESSED', 'KEY-NXTBLK'))
THEN APP_CUSTOM.OPEN_WINDOW('LINES');
ELSE
FND_MESSAGE.DEBUG('Invalid event passed to orders.lines: '|| EVENT);
END IF;
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的同步关系。
Eg:
PROCEDURE orders_lines(EVENT VARCHAR2) IS
BEGIN
IF (EVENT = 'WHEN-CHECKBOX-CHANGED') THEN
APP_WINDOW.SET_COORDINATION (EVENT, :CONTROL.ORDERS_LINES, 'ORDERS_LINES');
ELSE
FND_MESSAGE.DEBUG('Invalid event passed to control.order_lines '|| EVENT);
END IF;
END orders_lines;
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 Canvas0,Viewport Y Position on Canvas0,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节介绍。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
内容实在太多总共21节,不贴了,有兴趣的话看附件吧。 |
|