|
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。如果您注册时有任何问题请联系客服QQ: 83569622 。
您需要 登录 才可以下载或查看,没有帐号?注册
x
Developer/2000中各键盘触发子所对应的"按键"
封装过程 键触发子 含义 对应按键
ABORT_QUERY Key-EXIT [退出/取消]
BLOCK_MENU Key-MENU [块菜单] F5
CLEAR_BLOCK Key-CLRBLK [清空块] Shift+F5
CLEAR_FORM Key-CLRFRM [清空FORM] Shift+F7
CLEAR_RECORD Key-CLRREC [清空记录] Shift+F4
COMMIT_FORM Key-COMMIT [提交/存盘] F10
COUNT_QUERY Key-CQUERY [计算查询记录总数] Shift+F2
CREATE_RECORD Key-CREREC [插入新记录] F6
DELETE_RECORD Key-DELREC [删除记录] Shift+F6
DOWN Key-DOWN [下滚记录] Ctrl+l,下箭头
DUPLICATE_ITEM Key-DUP-ITEM [复制域/项] F3
DUPLICATE_RECORDKey-DUPREC [复制记录] F4
EDIT_TEXTITEM Key-EDIT [打开编辑器] Ctrl+E
ENTER Key-ENTER [Enter]
ENTER_QUERY Key-ENTQRY [输入查询条件] F7
EXECUTE_QUERY Key-EXEQRY [执行查询] F8
EXIT_FORM Key-EXIT [退出/取消查询] Ctrl+Q
HELP Key-HELP [帮助] F1
LIST_VALUES Key-LISTVAL [显示值列表LOV] F9
LOCK_RECORD Key-UPDREC [Lock Record]
NEXT_BLOCK Key-NXTBLK [下一块] Ctrl+Page Down
NEXT_ITEM Key-NEXT-ITEM [下一域/项] Ctrl+Tab,Tab,Enter
NEXT_KEY Key-NXTKEY [定位到下一个主键项] Shift+F3
NEXT_RECORD Key-NXTREC [下一条记录] Shift+Down
NEXT_SET Key-NXTSET [下一个记录集] Ctrl+>
PREVIOUS_BLOCK Key-PRVBLK [前一块] Ctrl+Page Up
PREVIOUS_ITEM Key-PREV-ITEM [前一域/项] Shift+Tab,Shift+Ctrl+Tab
PREVIOUS_RECORD Key-PRVREC [前一条记录] Shift+Up
PRINT Key-PRINT [打印当前屏幕] Shift+F8
SCROLL_DOWN Key-SCRDOWN [下翻屏] Page Down
SCROLL_UP Key-SCRUP [上翻屏] Page Up
UP Key-UP [上滚记录] Ctrl+p,上箭头
Esc 取消
Backspace 向后删除
Ctrl+U 清除域/项
Ctrl+F1 显示有效的功能键列表
Shift+F1 发生错误时,显示错误窗口
FORM中,当光标走到块的最后一项时,如何让按"enter回车"键时,光标自动走到下一条记录的第一项
设置块属性
导航器风格:改变记录
如何在启动FORM程序时直接登录到Oracle数据库上
调入Form Builder,打开一个新的FORM
在表格级新建一个ON_LOGON触发器
在ON_LOGON里输入以下代码:
DECLARE
PASS1 VARCHAR2(80); --PASS1为密码参数
BEGIN
LOGON('USER1','USER1'||'@'||'TNS1');
SELECT PASS INTO PASS1 FROM T_PASSWORD WHERE USERNAME='USER2';
LOGOUT;
LOGON('USER2',PASS1||'@'||'TNS1');
END;
FORM中,如何通过 ODBC 访问 Acress 数据
在控制面板中选取 ODBC 控制源
系统 DSN
添加(D)...
选定您需要的驱动程序来安装数据源(S):Microsoft Acress Driver (*.mdb)
完成(F)
Date Source Name:aaa(aaa就是数据源名称,也就是在应用程序中所要使用的)
选择一个mdb数据库文件(select)
高级属性:设置用户名,口令
OK
打开一个FORM
文件(F)—>连接(E)
用户名/口令@odbc:aaa
连接(O)
从FORM中调用REPORT时,如何使打印结果直接输出到打印机上
在parameter list中加入parameter_form=No
Add_parameter(list_id,'PSRAMETER_FORM',TEXT_PARAMETER,'NO');
FORM调用REPORT时,如何去掉report server
Add_parameter(list_id,'ORACLE_SHUTDOWN',TEXT_PARAMETER,'YES');
FORM中,如何实现屏幕同步刷新
现象说明:
FORM中,在做一连串大的操作时,有时希望用message来显示提示信息,但屏幕却不刷新,
解决方法:
message('信息1');
synchronize;(同步屏幕显示)
message('信息2');
synchronize;
在Developer/2000中如何读写文本型操作系统文件
PL/SQL 3.3以上的版本中,UTL_FILE包允许用户通过PL/SQL读写操作系统文件.如下:
declare
file_handle utl_file.file_type;
begin
file_handle:=utl_file.fopen('C:\','TEST.TXT','A'); --TEST.TXT是文件名
utl_file.put_line(file_handle,'写入的信息');
utl_file.fclose(file_handle);
end;
Developer/2000中,可以用Text_IO读写操作系统文件.如下:
DECALRE
in_file Text_IO.File_Type;
out_file Text_IO.File_Type;
BEGIN
in_file:=Text_IO.Fopen('文件名', 'R');
Text_IO.Get_Line(in_file,linebuf);
Text_IO.Fclose(in_file);
out_file:=Text_IO.Fopen('文件名', 'W');
Text_IO.Put_Line(out_file,'写入信息');
Text_IO.Fclose(out_file);
END;
--常用TEXT_IO
Declare
out_file text_io.file_type; --定义
Begin
out_file:=text_io.fopen('prn','w'); --打开文件prn
text_io.new_line(out_file,' '); --新建一行
text_io.put_line(out_file,' ') --写入一行
text_io.fclose(out_file); --关闭文件
End;
---文本输入输出
TEXT_IO
TEXT_IO.PACKAGE
TEXT_IO.FCLOSE
TEXT_IO.FILE_TYPE
TEXT_IO.FOPEN
TEXT_IO.IS_OPEN
TEXT_IO.GET_LINE
TEXT_IO.NEW_LINE
TEXT_IO.PUT
TEXT_IO.PUTF
TEXT_IO.PUT_LINE
Declare
Out_file Text_io.file_type;
L Varchar2(100);
L1 Varchar2(100);
L2 Varchar2(100);
Begin
Out_file :=text_io.fopen('c:\ll\login.txt','r');
If text_io.is_open(Out_file) then
text_io.get_line(Out_file,L);
text_io.get_line(Out_file,L1);
text_io.get_line(Out_file,L2);
Else
Null;
End if;
End;
如何改变FORM(FMX模块)运行时的title
Developer/2000中FMX默认title为:Developer/2000 Forms Runtime for Windows 95 / NT
在Form级触发器中添加触发WHEN-NEW-FORM-INSTANCE
在此触发器中写如下代码:
SET_WINDOW_PROPERTY(FORMS_MDI_WINDOW,TITLE,'您的提示');
FORM中,如何修改系统提示信息(默认英文)为中文
调入Form Builder,打开一个新的FORM
在表格级新建一个ON_ERROR触发器
在ON_ERROR里输入以下代码:
begin
if
error_code=40100 then message('已在第一 条记录!');
elsif error_code=40102 then message('您已在最后一条记录,请先输入处理此记录,然后再输入下一条记录!');
elsif error_code=40200 then message('此项仅用于查询参考,您无法更改此项!');
elsif error_code=40202 then message('此项必须输入! 产生错误原因:您未输入值,或您删去了原有值!');
elsif error_code=40203 then message('值必须输入完全! 产生错误原因:该项有定长要求!');
elsif error_code=40207 then message('您输入的值不在有效范围之内,请输入有效范围之内的值!');
elsif error_code=40401 then message('您没有修改或输入任何新的记录,无须保存!');
elsif error_code=40508 then message('编码不能相同,不能有相同编码的记录,编码必须唯一!');
elsif error_code=40509 then message('严重操作错误!,您可能输入了一个空的记录,无法保存记录!');
elsif error_code=41802 then message('您只能在输入新的记录时使用[复制记录]键,来复制上一条记录!');
else message(error_type||'_'||to_char(error_code)||':'||error_text);
end if;
raise form_trigger_failure;
end;
FORM中,怎样创建动态下拉列表List
1,打开Form Builder
2,文件(F)→新建(N)→表格(F)
3,新建一个非数据块,取名为tool
4,鼠标右键→布局编辑器(E)
5,建一个列表项,名为xl(属于tool块)
6,新建一过程,内写如下的代码
PROCEDURE create_xl IS --动态显示学历过程
CURSOR A IS SELECT DISTINCT(xl) FROM t_xl; --建立a游标,从学历档案表取原始数据(有可能动态变化)
CNT NUMBER; --记录总数变量,用于生成列表的总项数
i NUMBER; --循环变量
TNAME t_xl.name%TYPE; --TNAME变量和t_xl表中name项具有相同的结构
BEGIN
CLEAR_LIST('tool.xl'); --清空列表tool.xl(tool块上的xl项)
SELECT COUNT(DISTINCT(name)) INTO CNT FROM t_xl; --计算列表总数
OPEN A; --打开游标
FOR i IN 1..CNT LOOP --开始循环
FETCH A INTO TNAME; --取数
EXIT WHEN A%NOTFOUND; --退出条件
ADD_LIST_ELEMENT('tool.xl',i,TNAME,TNAME); --把查询出的值加入列表中(序号,实际值,显示值)
END LOOP; --结束循环
CLOSE A; --关闭游标
END;
7,在Form级触发器中添加触发WHEN-NEW-FORM-INSTANCE
在此触发器中写如下代码:create_xl;
使FORM程序一启动,就调用此过程,达到动态生成下拉列表List的效果.
附:
--学历档案表
create table t_xl(name varchar2(6));
insert into t_xl values('小学');
insert into t_xl values('初中');
insert into t_xl values('职高');
insert into t_xl values('技校');
insert into t_xl values('高中');
insert into t_xl values('中专');
insert into t_xl values('大专');
insert into t_xl values('本科');
insert into t_xl values('研究生');
commit;
FORM中,如何引入图像,制作封面
打开Form Builder
文件(F)→新建(N)→表格(F)
鼠标右键→布局编辑器(E)
文件(F)→导入(I)→图象(I)
可调入作好的图像,以制作封面.
所支持的图像格式有:TIF,JPG,BMP,TGA,PCX,PCT,GIF,CAL,RAS,OIF,PCD等
运行FORM时,如何使按钮变灰(即无效)
set_item_property('按钮名称',ENABLED,PROPERTY_FALSE);
FORM中,设置应用特性(光标类型)
在Form级触发器中添加触发WHEN-NEW-FORM-INSTANCE
SET_APPLICATION_PROPERTY(CURSOR_STYLE,'CROSSHAIR'|'BUSY'|'HELP'|'DEFAULT'|'INSERTION');
运行FORM时,如何使窗口(runtime窗口,画布窗口)自动变成最大化,最小化
在Form级触发器中添加触发WHEN-NEW-FORM-INSTANCE
在此触发器中写如下代码:
SET_WINDOW_PROPERTY(FORMS_MDI_WINDOW,WINDOW_STATE,MAXIMIZE);--最大化
SET_WINDOW_PROPERTY(FORMS_MDI_WINDOW,WINDOW_STATE,MINIMIZE);--最小化
FORM中,WINDOW标题的设置
在Form级触发器中添加触发WHEN-NEW-FORM-INSTANCE
SET_WINDOW_PROPERTY(FORMS_MDI_WINDOW, title,'你要写的标题');
或用以下方法
2. 对象导航器→窗口→WINDOW0(窗口的名字)→属性→标题→修改其属性
FORM中,Exception(例外)都有哪些,如何书写
BEGIN
《PL/SQL块》;
Exception
when no_data_found then --没有找到数据
《响应命令》;
when too_many_rows then --返回多行,隐式光标每次只能检索一行数据
《响应命令》;
when invalid_number then --字符向数字转换失败
《响应命令》;
when zero_divide then --被零除
《响应命令》;
when dup_val_on_index then --向唯一索引中插入重复数据
《响应命令》;
when invalid_cursor then --非法游标操作
《响应命令》;
when value_error then --数字的,数据转换,截字符串或强制性的错误
《响应命令》;
when others then --发生其它任何错误
null; --选择一:什么也不做,就当错误没发生
raise form_trigger_failure; --选择二:挂起当前程序
END;
如何在FORM运行中,使定制菜单中的"窗口(W)"菜单项不显示
对象导航器→窗口→WINDOW0(窗口的名字)→属性→模式→修改其属性
设置窗口属性:模式=是
FORM中,如何屏蔽默认的功能键
1. 在Form级触发器中添加触发KEY-OTHERS
2. 在此触发器中写如下代码:
null;
3. 这样FORM程序运行后,大部分的功能键都被屏蔽(包括一些必需键,如:上箭头,下箭头,退出...),
要想让这些键再恢复功能,就为这些键各自编程:
按键 触发器 代码 说明
上箭头 KEY-DOWN DOWN; 上滚记录
下箭头 KEY-UP UP; 下滚记录
Page Up KEY-SCRUP SCROLL_UP; 上翻屏
Page Down KEY-SCRDOWN SCROLL_DOWN; 下翻屏
F1 KEY-HELP HELP; 显示帮助
F3 KEY-DUP-ITEM DUPLICATE_ITEM; 复制项
F4 KEY-DUPREC DUPLICATE_RECORD; 复制记录
F5 KEY-MENU BLOCK_MENU; 块导航菜单
F6 KEY-CREREC CREATE_RECORD; 插入记录
F7 KEY-ENTQRY ENTER_QUERY; 输入查询条件
F8 KEY-EXEQRY EXECUTE_QUERY; 运行查询
F9 KEY-LISTVAL LIST_VALUES; 显示LOV
F10 KEY-COMMIT COMMIT; 存盘
Enter,Tab KEY-NEXT-ITEM NEXT_ITEM; 下一项
SHIFT+TAB KEY-PREV-ITEM PREVIOUS_ITEM; 前一项
Ctrl+Q KEY-EXIT EXIT_FORM; 退出/取消查询
FORM中,触发子exit_form的两种功能是什么
1,退出FORM
exit_form;
2,取消查询
if :System.Mode = 'ENTER-QUERY' then
exit_form;
end if;
FORM中如何存取图象 如何把图象从一个表中导到另一个表中
1,SQL*Plus中
SQL> create table t_photo1(photo1 long raw);
SQL> create table t_photo2(photo2 long raw);
2,硬盘上c:\下有一个图象文件tmp.bmp
3,打开FORM
新建两个块:t_photo1,t_photo2
t_photo1块是数据库块,连接的表是数据库中的一个表t_photo1
t_photo2块也是数据库块,连接的表是数据库中的另一个表t_photo2(备份表)
t_photo1块上新建一个图象项,名为photo1,对应的是即表t_photo1中的photo1列
t_photo2块上也新建一个图象项,名为photo2,对应的是即表t_photo2中的photo2列
新建一按钮1,输入以下程序,这个按钮实现读入图象到表里,即录入图象到表里
BEGIN
GO_BLOCK('t_photo1');--到块1
READ_IMAGE_FILE('c:\tmp.bmp','bmp','t_photo1.photo1');
--读入外部图象文件tmp.bmp(图象类型为BMP)到t_photo1块的photo1项,也就是到了t_photo1表里
COMMIT;--存盘
END;
新建一按钮2,输入以下程序,这个按钮实现图象的倒表(t_photo1到t_photo2)
BEGIN
GO_BLOCK('t_photo1');--到块1
execute_query;
--查询出表中的图象,这时,表中的图象到了FORM中的图象项上
WRITE_IMAGE_FILE('c:\tmp.bmp','bmp','t_photo1.photo1');
--把图象项中图象写入外部图象文件tmp.bmp
GO_BLOCK('t_photo2');--到块2
READ_IMAGE_FILE('c:\tmp.bmp','bmp','t_photo2.photo2');
--把外部图象文件tmp.bmp读入到t_photo2块的photo2项,也就是到了t_photo2表里
COMMIT;--存盘
END;
运行此程序,点击此按钮观察效果.
注释:t_photo1.photo1是正式图片表中的图象项(数据库项)(t_photo1块photo项1)
t_photo2.photo2是备份图片表中的图象项(数据库项)(t_photo2块photo项2)
FORM中如何存取声音
硬盘上c:\下有一个声音文件tmp.wav
打开FORM
新建一个块:t_sound
t_sound块上新建一个声音项,名为sound1
新建一按钮1,输入以下程序
BEGIN
GO_ITEM('sound1');
READ_SOUND_FILE('c:\tmp.wav','wave','sound1');
PLAY_SOUND('sound1');
END;
运行此程序,点击此按钮观察效果.
FORM中,当用鼠标点击标签画布的某一"标签页"时,如何判断点击的是哪一页
1. 在Form级触发器中添加触发WHEN-TAB-PAGE-CHANGED
2. 在此触发器中写如下代码:
DECLARE
canvas_id VARCHAR2(30); --标签页ID
BEGIN
canvas_id := GET_CANVAS_PROPERTY('标签画布名', topmost_tab_page);
IF canvas_id='标签页1' then go_block('块1');end if;
IF canvas_id='标签页2' then go_block('块2');end if;
IF canvas_id='标签页3' then go_block('块3');end if;
execute_query;
END;
FORM中,常用快捷键有哪些
CTRL+S 保存
CTRL+T 编译文件
CTRL+R 运行FORM
CTRL+J 连接
F1 调用帮助
F2 布局编辑器
F4 属性选项板
如何发布Developer/2000应用程序
FORM中,点击按钮实现字段排序
为什么在触摸屏上,我的按纽不响应我的"按"动作
为什么我的FMX程序里没有Message line
FORM中,如何设置水平滚动条
FORM中,触发子POST-CHANGE的作用
FORM中,触发子WHEN-VALIDATE-ITEM的作用
FORM中,触发子POST-QUERY的作用
怎样在form中使用宏
在 早 期FOXPRO 数 据 库 编 程 中, 经 常 用 到 宏 代 换 功 能, 但 在FORMS 中 却 没 有 此 功 能, 象"&","*" 等 在 编 程 中 经 常 用 到 的, 在FORMS 中 只 得 一 行 一 行 代 码 的 写, 但 后 来 发 现FORMS 中 也 有 类 似 功 能, 用NAME_IN(),COPY() 可 以 实 现 类 似 的 功 能.Name_in() 用 于 取 出 参 数 名 代 表 的 对 象 了 数 值, 而COPY() 把 一 个 参 数 值 传 递 给 另 一 参 数 值 表 示 的 对 象. 的 如 下 例:
FORM 结 构:
块B
项 L1,L2,L3,L4,L5,L6
在 作 录 入 程 序 时 要 对L1...L6 项 清 零
DELCATE
strItemName varchar2(20);
BEGIN
for I in 1 …6 loop
strItemName:=':b.l"||to_char(i);
copy(null,strItemNmae);
end loop;
END;
---- 对 于NAME_IN 的 应 用 可 能 更 多 一 些, 笔 者 在 做 社 保 软 件 时, 作 保 险 缴 费 录 入 时 曾 用 它 少 写 了 许 多 代 码. 当 然 代 码 的 减 少 就 义 意 味 维 护 工 作 量 的 减 少
----
FORM结构:
养老:
块:YLYJ(养老应缴)
项:DWJTC(单位缴统筹),DWJZH(单位缴帐户),GRJF(个人缴费)
块:YLSJ (养老实缴)
项:DWJTC(单位缴统筹),DWJZH(单位缴帐户),GRJF(个人缴费)
工伤:
块:GSYJ(工伤应缴)
项:DWJTC(单位缴统筹),DWJZH(单位缴帐户),GRJF(个人缴费)
块:GSSJ (工伤实缴)
项:DWJTC(单位缴统筹),DWJZH(单位缴帐户),GRJF(个人缴费)
医疗:
块:YILYJ(医疗应缴)
项:DWJTC(单位缴统筹),DWJZH(单位缴帐户),GRJF(个人缴费)
块:YILSJ (医疗实缴)
项:DWJTC(单位缴统筹),DWJZH(单位缴帐户),GRJF(个人缴费)
---- 三 个 块 的 结 构 相 同, 只 是 块 名 称 不 同, 缴 费 时 时 行 的 操 作 也 一 样, 实 缴 名 项 不 能 大 于 应 缴, 不 用NAME_IN 时, 只 能 写 三 段 程 序, 但 用 了NAME_IN 后 只 用 一 段 写 一 个 函 数 就 能 达 到 目 的. 如 下:
FUNCTION FUN_JF (PRE_BLOCK_NAME
IN VARCHAR) RETURN BOOLEAN IS
BEGIN
if name_in(pre_block_name||'sj.dwjtc')
>name_in(pre_block_name||'yj.dwjtc') or
name_in(pre_block_name||'sj.dwjzh')
>name_in(pre_block_name||'yj.dwjzh') or
name_in(pre_block_name||'sj.grjf')
>name_in(pre_block_name||'yj.grjf') then
message(' 实 缴 大 于 应 缴');
return false;
end if;
return true;
END;
---- 从 上 面 的 两 个 例 子 来 看NAME_IN 和COPY 的 应 用 能 起 到 其 它 编 程 语 言 的" 宏" 代 换 功 能, 代 码 的 优 化 方 面 确 实 能 起 不 少 的 作 用, 减 少 了 程 序 源 代 码 的 维 护 工 作.
Oracle中Forms与Reports的集成
Oracle产品Developer 2000中包括多种开发工具,其中在具体工作时用得最多的是Forms和Reports.Forms是一个设计表单的工具,利用它可以灵活方便地定义各种表单对象,以简化用户在运行期对相关数据库的操作(查询,插入,删除和更新等);Reports则是一个设计报表的工具,利用它可以按照用户的要求方便地生成报表.
在Oracle应用系统中,大量的具有交互性的功能是由Forms实现的.利用Forms所生成的表单模块可以彼此调用,实现业务流程的控制并完成与数据库有关的复杂操作;而由Reports所设计的报表模块往往当做最底层的功能被表单模块所调用.对于一些Oracle用户来说,独立地用好Forms或Reports是没有问题的,但他们却很少考虑如何使二者有机地结合起来,利用Forms对数据操纵的灵活性,由Forms模块向Reports模块传送大量结构化或非结构化的实时数据,减少(或避免)Reports对数据库的访问,从而高速地生成报表并保证报表数据与表单数据的一致性.本文通过实例介绍一种利用Forms的封装例程RUN_PRODUCT( )在Forms模块中集成Reports模块的方法,利用该方法可以把Forms和Reports有机地结合起来,减少不必要的操作,提高工作效率.
RUN_PRODUCT例程
在Forms模块中调用Reports模块,最有效的方法是利用Forms的封装例程RUN_PRODUCT().目前,很多程序开发人员在Forms模块中调用Reports模块时,或者没有采用这一例程,或者虽然采用这一例程但并没有充分利用参数表来传递表单中现成的数据,或者只是利用参数表来传递少量的文本参数(非结构化数据)作为Reports中的查询条件,报表的数据仍然要从数据库中查询得到,这样既增加了数据库服务器的负载,又增加了网络的流量,而且报表生成的速度慢,丧失了数据的实时性与一致性.因此,深入了解并熟练掌握参数表的使用方法便显得非常重要.
在使用RUN_PRODUCT( )之前要先建立参数表,并向参数表中添加参数.RUN_PRODUCT( )的使用格式如下:
RUN_PROCDUT(REPORTS, 'report_name', SYNCHRONOUS, RUNTIME, FILESYSTEM, pl_id, NULL);
其中各参数含义如下:
●REPORTS:说明被调模块是报表模块;
●report_name:被调模块的完整路径名;
●SYNCHRONOUS: 说明被调模块以同步的通信方式运行(被调模块退出之后主调模块才能继续执行,否则为ASYNCHRONOUS,即异步方式);
●RUNTIME:说明被调模块的执行方式为前台方式(否则为BATCH,即后台方式);
●FILESYSTEM:说明被调模块的存储位置是文件系统(否则为DATABASE,即数据库系统);
●pl_id:用户定义的参数表标识符.
使用参数表的要领
由Forms模块向Reports模块传递的数据可分为两类:一类是非结构化数据,即报表表头(表尾)的数据;另一类是结构化数据,即报表表目的二维数据.在如图1所示的报表中,学年,学期,班级编号,班级名称,专业名称,课程编号,课程名称,学分,班级人数等,属于表头数据;而学号,姓名,性别,修读性质,平时成绩,考试成绩,总评成绩,任课教师等属于表目数据.
图1 Reports模块执行情况
参数表中的参数有两种,文本参数(TEXT_PARAMETER)和数据参数(DATA_PARAMETER).文本参数是对字符型数据的引用,数据参数是对记录组的引用.对于非结构化数据,可借文本参数将数据加入参数表(注意:文本参数只接受字符型数据,对于其他类型的数据要通过TO_CHAR( )函数先转化为字符型数据);而对于结构化数据,则先要将数据存入记录组(RECORD_GROUP),然后借数据参数才能将数据加入到参数表中.注意:Forms模块的记录组中的各列和Reports模块中的查询(QUERY)对象的各列在名称,类型和顺序上要完全一致.这里文本参数是字符串指针,数据参数是记录组(结构数组)的指针,而参数表则是存储上述指针的指针数组.
如果RUN_PRODUCT( )的参数表中未加入与Reports模块中的查询对象同名的数据参数,则Reports 从数据库中查找与其模块中的查询对象相匹配的数据;如果RUN_PRODUCT( ) 的参数表中加入了与Reports模块中的查询对象同名的数据参数,则Reports 并不从数据库中查找数据,而是以参数表中的同名数据参数所引用的记录组作为其模块中的查询对象的数据源,在这种情况下,Reports查询对象的SELECT语句所映射的数据集合是不起作用的.
实现集成的具体方法
本文例子中用Forms模块来对学生的期末成绩进行管理,Forms模块运行如图2所示.
其中:
●标以单位,班级,课程,成绩的各个块对象间存在级联的主从关系;
●各个块对象中,有的项因不需要使用人员予以关注,故将其定义为非显示项,未在画布(canvas)上显示,但这并不影响对它们的引用,例如,班级块中的班级编号(BJBH),课程块中的课程编号(KCBH)等;
●标以课程的块对象是基于视图(view)而非基于表(table)的;
●画布上显示的项并非都是基表项(块对象所基于的表或视图中的列),而是通过触发子从其他的表或视图中查询的,这也不影响对它们的引用,例如,课程块中的名称(MC)和学分(XF)等.
图2 Forms模块运行情况
程序实现的步骤如下:
在Sql*plus下创建一个与图1所示的表目一致的表(或视图)REPT_001当做Reports模块的查询对象Q_001的虚拟数据源:
CREATE TABLE REPT_001( /* 期末成绩表 */
XH VARCHAR2(9), /* 学号 */
XM VARCHAR2(10), /* 姓名 */
XB VARCHAR2(2), /* 性别 */
XDXZ VARCHAR2(4), /* 修读性质 */
PSCJ NUMBER, /* 平时成绩 */
KSCJ NUMBER, /* 考试成绩 */
ZPCJ NUMBER, /* 总评成绩 */
RKJS VARCHAR2(10) /* 任课教师 */);
注意:该表仅供Reports定义查询对象Q_001之用(仅援引其列名与类型),与整个应用系统的数据库结构无关,不需要向该表插入任何数据(保持该表为空表),不存在数据的完整性和一致性的问题.
在Reports中定义报表模块,源模块的名称为REP_001.rdf.在该模块中,定义与表目数据相关的查询对象Q_001:
SELECT XH,XM,XB,XDXZ,PSCJ,KSCJ,ZPCJ,RKJS FROM REPT_001;
再定义与表头数据相关的用户参数:
P_XN1 /* 学年学期 */
P_XN2
P_XQ
P_BJBH /* 班级编号 */
P_BJMC /* 班级名称 */
P_ZYMC /* 专业名称 */
P_KCBH /* 课程编号 */
P_KCMC /* 课程名称 */
P_XF /* 学分 */
P_BJRS /* 班级人数 */
在Reports的布局编辑器中调整美化报表的输出格式,最后生成目标模块REP_001.rep.
在Forms模块中定义按钮以实现对Reports模块REP_001.rep的调用.
为按钮定义WHENBUTTONPRESSED触发子:
DECLARE
PL_ID PARAMLIST;
RG_ID RECORDGROUP;
GC_XH GROUPCOLUMN;
GC_XM GROUPCOLUMN;
……
BEGIN
/* 定义用来捆绑表目数据的记录组G_001*/
RG_ID:=FIND_GROUP('G_001');
IF ID_NULL(RG_ID) THEN
RG_ID:=CREATE_GROUP('G_001');
/* 定义记录组内各列,注意各列的列名,类型,顺序均要和Reports模块所定义的查询对象Q_001中的各列相一致 */
GC_XH:=ADD_GROUP_COLUMN(RG_ID,'XH',CHAR_COLUMN);
GC_XM:=ADD_GROUP_COLUMN(RG_ID,'XM',CHAR_COLUMN);
……
ELSE
DELETE_GROUP_ROW(RG_ID,ALL_ROWS);
GC_XH:=FIND_COLUMN(RG_ID,'XH',
CHAR_COLUMN);
GC_XM:=FIND_COLUMN(RG_ID,'XM',
CHAR_COLUMN);
……
END IF;
/* 把Forms模块中的数据传送到记录组中 */
GO_BLOCK('CJZB');
FIRST_RECORD;
ROW_NUM:=1;
FOR LOOP
ADD_GROUP_ROW(RG_ID,END_OF_GROUP);
SET_GROUP_CHAR_CELL(GC_XH,ROW_NUM,:CJZB.XH);
SET_GROUP_CHAR_CELL(GC_XM,ROW_NUM,:CJZB.XM);
……
EXIT WHEN :SYSTEM.LAST_RECORD='TRUE';
LOW_NUM:=LOW_NUM+1;
NEXT_RECORD;
END LOOP;
/* 建立参数表 */
PL_ID:=GET_PARAMETER_LIST('CJ_LIST');
IF NOT ID_NULL(PL_ID) THEN
DESTROY_PARAMETER_LIST('CJ_LIST');
END IF;
PL_ID:=CREATE_PARAMETER_LIST('CJ_LIST');
/* 通过向参数表中加入文本参数的方式传送表头数据.其中,第1个参数是参数表标识符,第2个参数是键(参数名),应与Reports模块中定义的用户参数同名,第3个参数指定参数的种类是文本参数,第4个参数引用Forms模块的数据项 */
ADD_PARAMETER(PL_ID, 'P_XN1',
TEXT_PARAMETER,:START.XN1);
ADD_PARAMETER(PL_ID, 'P_XN2',
TEXT_PARAMETER,:START.XN2);
……
/* 向参数表传送表目数据.其中,第1个参数是参数表标识符,第2个参数是键(参数名),应与Reports模块中定义的查询对象同名,第3个参数指定参数的种类是数据参数,第4个参数引用Forms模块的记录组 */
ADD_PARAMETER(PL_ID, 'Q_001',
DATA_PARAMETER,'G_001');
/* 调用报表模块REP_001 */
RUN_PRODUCT(REPORTS,'C:\Apps\REP_001',SYNCHRONOUS,RUNTIME,FILESYSTEM,PL_ID);
END;
小 结
通过上述方法,借助参数表实现Forms模块对Reports模块的集成,既能快速生成报表(包括实时的业务单据的套打),又提高了系统的效率.如果巧妙地将报表标题,栏目标题,表头数据,格式线段,表目数据等均通过参数传送,并借助Reports的格式触发子和SWR包的模块(过程,函数和例外处理),还可以生成各种复杂的动态报表,免除了使用第三方工具带来的麻烦和副作用(如增加新的连接等).
在DEVELOPER2000中利用DDE将数据倒入到EXCEL文件中的方法
在实际的工作中,经常遇到用户要将EXCEL文件中的数据倒入到ORACLE数据库中,也经常遇到用户要将ORCLE数据库中的数据倒入到EXCEL文件中,这方面的资料并不多见(PB6的这项功能很简单,只需在DATAWINDOW控件中加入dw_1.save()这一函数就可以了),通常的做法是利用DEVELOPER 2000自带的示例进行修改来完成任务,但效果也不好,尤其是对初学者,面对示例中的OLE示例可能如入雾里,我在实际工作中利用DDE将数据倒入到EXCEL文件中,效果也不错,在这里向大家作一介绍.
所谓DDE,就是动态数据交换,相信各位并不陌生.运用DDE倒数据的先提条件是先在本机安装微软office中的EXCEL,在C:盘上建立一空的EXCEL文件如EXCEL.xls,打开该文件,然后运行自己开发的FORM文件.
下面我就我工作中遇到的实际工作遵照原意逐步进行介绍:
先用form4.5(5.0当然更可以)建立一个新FORM,在canvas上的新blok中建一个button,然后在该button中的WHEN-BUTTON-PRESSED触发子中,输入以下代码:
DECLARE
CROW varchar2(8);
CCOL1 varchar2(8);
CCOL2 varchar2(8);
CCOL3 varchar2(8);
CCOL4 varchar2(8);
CCOL5 varchar2(8);
CCOL6 varchar2(8);
CCOL7 varchar2(8);
CCOL8 varchar2(8);
CCOL9 varchar2(8);
TEMP VARCHAR2(8);
ConvID PLS_INTEGER;
/*该游标c1是用来从ORACLE提取数据,
并将数据倒入到EXCEL文件中的*/
CURSOR C1 IS SELECT
A.SHIPMENT_NO,A.ARRIVAL_DATE,
B.DELIVERY_REF_1,B.DELIVERY_REF_3,
B.DELIVERY_REF_2,C.CASE_NO,C.LRCM_CODE,
C.ANN_QUANTITY,C.QUANTITY_DESCRIPTION,
C.SPARE_PART,C.TRANSFER_NUMBER,
C.TRANSFER_DATE FROM
ACM A,ACMCONTRACT B,ACMDELIVERY_PL D,
ACMCASE_PL C
WHERE
A.SHIPMENT_NO=B.SHIPMENT_NO AND
A.CONTRACT_NO=B.CONTRACT_NO AND
B.DELIVERY_REF_1=D.DELIVERY_REF_1 AND
B.DELIVERY_REF_2=D.DELIVERY_REF_2 AND
B.DELIVERY_REF_3=D.DELIVERY_REF_3 AND
D.DELIVERY_REF_1=C.DELIVERY_REF_1 AND
D.DELIVERY_REF_2=C.DELIVERY_REF_2 AND
D.DELIVERY_REF_3=C.DELIVERY_REF_3 AND
D.CASE_NO=C.CASE_NO AND C.SPARE_PART='SO' AND
C.TRANSFER_NUMBER IS NOT NULL
AND C.TRANSFER_DATE IS NOT NULL;
SHIPMENT_NO_TMP ACM.SHIPMENT_NO%TYPE;
ARRIVAL_DATE_TMP ACM.ARRIVAL_DATE%TYPE;
DELIVERY_REF_1_TMP ACMCONTRACT.DELIVERY_REF_1%TYPE;
DELIVERY_REF_3_TMP ACMCONTRACT.DELIVERY_REF_3%TYPE;
DELIVERY_REF_2_TMP ACMCONTRACT.DELIVERY_REF_2%TYPE;
CASE_NO_TMP ACMCASE_PL.CASE_NO%TYPE;
LRCM_CODE_TMP ACMCASE_PL.LRCM_CODE%TYPE;
ANN_QUANTITY_TMP ACMCASE_PL.ANN_QUANTITY%TYPE;
QUANTITY_DESCRIPTION_TMP ACMCASE_PL.QUANTITY
_DESCRIPTION%TYPE;
SPARE_PART_TMP ACMCASE_PL.SPARE_PART%TYPE;
TRANSFER_NUMBER_TMP ACMCASE_PL.TRANSFER
_NUMBER%TYPE;
TRANSFER_DATE_TMP ACMCASE_PL.TRANSFER
_DATE%TYPE;
NCOUNT NUMBER;
BEGIN
/*NCOUNT为游标循环的总记数*/
SELECT COUNT(*) INTO NCOUNT
FROM ACM A,ACMCONTRACT B,ACMDELIVERY_PL D,
ACMCASE_PL C
WHERE
A.SHIPMENT_NO=B.SHIPMENT_NO AND
A.CONTRACT_NO=B.CONTRACT_NO AND
B.DELIVERY_REF_1=D.DELIVERY_REF_1 AND
B.DELIVERY_REF_2=D.DELIVERY_REF_2 AND
B.DELIVERY_REF_3=D.DELIVERY_REF_3 AND
D.DELIVERY_REF_1=C.DELIVERY_REF_1 AND
D.DELIVERY_REF_2=C.DELIVERY_REF_2 AND
D.DELIVERY_REF_3=C.DELIVERY_REF_3 AND
D.CASE_NO=C.CASE_NO AND C.SPARE_PART='SO' AND
C.TRANSFER_NUMBER IS NOT NULL AND
C.TRANSFER_DATE IS NOT NULL;
/* 初始化DDE,同EXCEL及文件建立联系,
此时要确保EXCEL将EXCEL.XLS文件打开 */
ConvID := DDE.Initiate('EXCEL', 'C:\excel.xls');
/* 先在EXCEL文件中第一行加入字段名称,
其中DDE.CF_TEXT为文本型数据,1000为1000毫秒 */
DDE.Poke(ConvID, 'R1C1','船运号',
DDE.CF_TEXT, 1000);
DDE.Poke(ConvID, 'R1C2','到达日期',
DDE.CF_TEXT, 1000);
DDE.Poke(ConvID, 'R1C3','包装箱号',
DDE.CF_TEXT, 1000);
DDE.Poke(ConvID, 'R1C4','LRCM号',
DDE.CF_TEXT, 1000);
DDE.Poke(ConvID, 'R1C5','SO标识',
DDE.CF_TEXT, 1000);
DDE.Poke(ConvID, 'R1C6','移交单',
DDE.CF_TEXT, 1000);
DDE.Poke(ConvID, 'R1C7','移交日期',
DDE.CF_TEXT, 1000);
DDE.Poke(ConvID, 'R1C8','移交数量',
DDE.CF_TEXT, 1000);
DDE.Poke(ConvID, 'R1C9','设备材料描述',
DDE.CF_TEXT, 1000);
OPEN C1;
FOR i IN 1..NCOUNT LOOP
/*循环从此开始*/
FETCH C1 INTO SHIPMENT_NO_TMP,
ARRIVAL_DATE_TMP,DELIVERY_REF_1_TMP,
DELIVERY_REF_3_TMP,DELIVERY_
REF_2_TMP,CASE_NO_TMP,
LRCM_CODE_TMP,ANN_QUANTITY_TMP,
QUANTITY_DESCRIPTION_TMP,SPARE_PART_TMP,
TRANSFER_NUMBER_TMP,TRANSFER_DATE_TMP;
EXIT WHEN C1%NOTFOUND OR C1%NOTFOUND IS NULL;
/*下面是EXCEL.XLS文件的CELL,
如'R2C2'就是第二行第二列*/
CROW:=I+1;
CCOL1:='R'||CROW||'C1';
CCOL2:='R'||CROW||'C2';
CCOL3:='R'||CROW||'C3';
CCOL4:='R'||CROW||'C4';
CCOL5:='R'||CROW||'C5';
CCOL6:='R'||CROW||'C6';
CCOL7:='R'||CROW||'C7';
CCOL8:='R'||CROW||'C8';
CCOL9:='R'||CROW||'C9';
TEMP:=ANN_QUANTITY_TMP;
/*NUMBER型数据要先转化为varchar型*/
DDE.Poke(ConvID, CCOL1, SHIPMENT_NO_TMP,
DDE.CF_TEXT, 2000000000);
/*日期型要用tochar()进行转换*/
DDE.Poke(ConvID, CCOL2, TO_CHAR(ARRIVAL_DATE_TMP),
DDE.CF_TEXT, 2000000000);
DDE.Poke(ConvID,CCOL3,DELIVERY_REF_1_TMP
||DELIVERY_REF_3_TMP||
DELIVERY_REF_2_TMP||
CASE_NO_TMP, DDE.CF_TEXT, 2000000000);
DDE.Poke(ConvID, CCOL4, LRCM_CODE_TMP, DDE.CF_TEXT,
2000000000);
DDE.Poke(ConvID, CCOL5, SPARE_PART_TMP, DDE.CF_TEXT,
2000000000);
DDE.Poke(ConvID, CCOL6, TRANSFER_NUMBER_TMP,
DDE.CF_TEXT, 2000000000);
DDE.Poke(ConvID, CCOL7, TO_CHAR(TRANSFER_DATE_TMP),
DDE.CF_TEXT, 2000000000);
DDE.Poke(ConvID, CCOL8, TEMP, DDE.CF_TEXT, 2000000000);
DDE.Poke(ConvID, CCOL9, QUANTITY_DESCRIPTION_TMP,
DDE.CF_TEXT, 2000000000);
END LOOP;
CLOSE C1;
DDE.Terminate(ConvID);
/*结束DDE会话,此时数据已经全部倒入到EXCEL文件中了*/
END;
在做好以上工作后, 编译运行该fmx文件, 此时确保打开excel.xls文件,用鼠标点击按钮,然后将焦点移到excel.xls文件中,你就会发现一行行数据正在被倒入到EXCEL文件中,等完成后, 将EXCEL文件保存起来就可以了.
使用设置菜单项属性及form 数据项属性限制不同用户的访问范围
---- 一个应用系统往往有不同的用户,比如: 一个劳资系统中,一个用户负责管理职工基本档案部分,另一个用户负责管理职工工资部分,管理职工基本档案的用户对职工档案只有查询的权限而不能有修改的权限.实现上述功能的一个简单的实现办法是:
---- 设置两个全局变量分别记录用户名和密码,在进入系统时,两个用户分别输入不同的用户名和密码,判断用户名,使SET_MENU_PROPERTY(MENU1,ENABLED,FALSE)语句设置没有查询权限的用户不能访问菜单项'MENU1'.
提高表连接的查询速度
在表连接查询时,常常用下列查询方法查询数据是:
SELECT RECORDNO,NAME,AGE
FROM 表1
WHERE 表1.RECORDNO NOT IN
(SELECT RECORDNO
FROM 表2
WHERE BIRTHDAY='710618');
笔者发现,如果表1的长度为6000条记录,表2的长度为1000条记录, 则要4分钟才能出结果.原因是使用了比较运算符 NOT IN ,它的逻辑测试速度是最慢的.利用外连接替换NOT IN 运算符,查询时间则缩短为50秒.修改方法如下:
SELECT RECORDNO,NAME,AGE
FROM 表1,表2
WHERE 表1.RECORDNO=表2.RECORDNO(+)
AND 表2.RECORDNO IS NULL
AND 表2.BIRTHDAY(+)='710618';
利用用库模块实现模块资源共享
在编程中很多FROM 模块需要共用一个程序单元.ORACLE FORM 4.5提出了库模块的概念.使用库模块建立共享程序单元库,既减少了磁盘占用空间,又增加程序的可维护性.使用库模块共享程序单元的过程是:点击系统菜单的file-new-liberary选项,建立一库模块,在program units节点下增加一程序单元, 写入需共享程序的单元编码, 编译后存盘.当FORM模块需共享时,在模块的Attached Libraries节点下连接库模块(此时屏幕会提示是否要删除路径,用户选择NO).这样,用户便可在FORM模块中直接使用共享程序单元了.
易导致查询数据错误的原因
在执行数据查询时,经常发现查询结果与预想的不同,主要原因是:
1.使用 SELECT * FROM WHERE LIKE '%' 语句查询不出 为NULL的字段.此时需对字段为NULL的情况另外处理.如:SELECT * FROM WHERE LIKE '%' OR IS NULL
2.使用union 字段连接各表时,连接顺序不是按书写的先后顺序,而是按连接表的第一个字段排序.因此,为了使表按预想的顺序连接,需在各表中插入第一字段指定排序序号.
使用视图组织报表数据简单且易于维护
ORACLE REPORT2.5提供了多种报表格式,但在报表中定义各种统计信息不仅繁琐而且不利于今后的维护,使用视图预先将各种统计,汇总数据准备好,可以起到事半功倍的作用,一旦数据源有所调整,只需修改后台视图,而不用再改前端程序了.
表1结构为: UNIT NAME RECORENO SEX
办公室 王五 1 男
财务科 李四 2 女
.. .. .. ..
1. 首先建立视图对数据进行汇总:
CREATE VIEW RYTJ (UNIT, BOY,GIRL)
AS SELECT UNIT, SUM(DECODE(SEX,'男'
,1,0)) , SUM(DECODE(SEX,'女',1,0) )
FROM 表1;
2. 使用 ORACLE REPORT 2.5 对视图'RYTJ'建立报表.
给报表加序号的简单办法
ORACLE REPORT 2.5 没有提供加序号功能,使用下述简单方法可实现给报表自动加序号:在数据模板中, 向查询组中加入一个公式列 CF_XH NUMBER(4), 赋初值为0, 点击[EDIT] 按钮, 插入编码RETURN(:CF_CH+1).
用FORMS 实 现ORACLE 数 据 库 与 其 它 数 据 源 数 据 的 交 换
---- Developer/2000 不 能 实 现 同 时 多 数 据 源 的 同 时 连 接, 在 多 系 统 和 异 种 数 据 源 的 操 作 中 功 能 确 实 大 打 折 扣, 虽 然 可 以 用3GL 加ODBC 作 一DLL 应 用 能 实 现, 但 一 般 的 应 用 中 又 有 点 没 用 必 要 作 的 那 么 复 杂. 实 际 上Developer/2000 内 嵌 包TEXT_IO 为 我 们 提 供 了 一 个 更 简 单 的 方 法. 几 乎 所 有 的 数 据 库 或 数 据 库 前 端 开 发 工 具 都 提 供 文 本 文 件 的 操 作, 这 样 我 们 完 全 可 以 用 文 本 文 件 作 为 数 据 交 换 的 通 用 格 式. 下 例 是 在 保 险 业 中 的 一 应 用 要 用 到d2kwfile.dll 应 用)
DECLARE
filename varchar2(128):=null;
filenum text_io.file_type;
linebuf varchar2(100);
r_temp temp%rowtype;
BEGIN
filename:=d2k_file_dialog.show
('请选择缴费工资台帐原文件','c:\','源文件(*.txt)|*.txt|');
if filename is null then
raise form_trigger_failure; end if;
filenum:=text_io.fopen(filename,'r');
loop
BEGIN
text_io.get_line(filenum,linebuf);
TEXT_IO.PUT(linebuf);TEXT_IO.NEW_LINE;
exception when no_data_found then
exit;
END;
BEGIN
v_temp.l1=substr(linebuf,1,9);
v_temp.l2:= to_number(substr(linebuf,10,5));
insert into temp(l1,l2) values (v_temp.l1,v_temp.l2);
exception when others then
END;
< >
null;
end loop;
END;
FORMS 4.5 实 现 的 列 表 查 询, 多 行 录 入 中 的 实 现 行 累 计
---- 在PB 和VB 中 都 用 类 似 的 求 和 或 者 说 累 计 列, 但 在 早 期 的FORMS4.5 中 没 有 此 功 能, 对 于 多 条 记 录 的 录 入 中 需 要 进 行 求 和 时 很 不 方 便, 其 实 利 用FORM 的 触 发 子 很 容 易 实 现. 如 下 例:
块:b1 项:l1,l2.l3,l4
块:b2 项:l1,l2,l3,l4
块b2是B1的求和块
在块B1中的PRE_TEXT_ITEM中代码:
IF SUBSTR(:SYSTEM.CURRENT_ITEM,1,1) IN ('L') THEN
:GLOBAL.ITEM_PREVALUES:=NAME_IN
('B1.'||:SYSTEM.CURRENT_ITEM);
END IF;
在块 B2中的POST_TEXT_ITEM中代码:
DECLARE
num_cz number; --数据项在录入或修改前后的差值
num_hz number; --数据项在修改后的求合
BEGIN
if substr(:system.current_item,1,1) in ('l') then
:global.item_nextvalues:=name_in
('b1.'||:system.current_item);
num_cz:=nvl(to_number(:global.item_nextvalues),0)-
nvl(to_number(:global.item_prevalues),0);
--新的和值
num_hz:=nvl(to_number(name_in('b_sum.'
||:system.current_item)),0)+num_cz;
copy(to_char(num_hz),'b2.'||:system.current_item);
end if;
END;
---- 通 过 前 后 两 值 的 比 较 很 容 易 的 实 现 一 个 较 通 用 的 求 和 算 法, 另 外 又 一 次 用 到NAME_IN 和 COPY , 减 少 了 代 码 量. 在 块 上 实 现 触 发 子 也 减 少 了 代 码 维 护 工 作 量.
REPORT 2.5 中 实 现 的 动 态 报 表( 一 张 表 利 用 多 个QUERY 语 句, 生 成 一 样 格 式 的 多 张 报 表
---- 在 做 报 表 时 经 常 要 遇 到 类 似 的 报 表 有 多 张 的 情 况, 虽 然 通 过 简 单 的 拷 贝 可 以 减 少 编 程 的 工 作 量, 但 在 后 期 的 维 护 中 却 增 加 了 难 度, 一 张 表 改 完 后 又 改 另 一 张 表, 进 行 大 量 的 重 复 劳 动 不 是 每 个 程 序 员 想 做 的 工 作. 其 实 在REPORT 2.5 中 有 一 很 好 的 功 能 可 能 完 成 这 样 的 工 作. 就 是REPORT 的" 宏" 代 换. 如 下 例:
两个表:tab_temp1 (a number,b number,c number)
tab_temp2 (d number,e number,f number)
---- 作 两 张 报 表, 表 头 一 样, 但 查 询 不 一 样, 分 别 取 自 两 个 表
建 一 用 户 参 数(user parameters) p_1 类 型 CHAR 长 度 200, 缺 省 值 是 SELECT A,B,C FROM TAB_TEMP
建 一 查 询(QUERIES), 在 查 询 语 句 中 输 入:& _1
生 成 布 局, 可 按 要 求 画 出 报 表.
---- 因 在 查 定 义 中 用 的 是&p_1 定 义, 所 以 可 以 在 运 行 时 动 态 的 给P_1 传 递 能 数 只 要 能 满 足 其 列 名 定 义 即 可, 例 可 用 如 下 语 句 代 入P_1
SELECT D A,E B,F C FROM TAB_TEMP2
---- 这 样 就 生 成 了 一 个 多 功 能 报 表, 把 编 写REPROT 工 作 从 简 单 的 布 局 编 辑 中 解 脱 出 来, 而 投 入 到 实 质 性 的 工 作SQL 语 句 的 生 成 上 去.
如何屏蔽系统提示信息
在运行一个FORM时往往会弹出一些报警器,但提示的并非出错信息,屏蔽这些报警器的方法是将系统变量:SYSTEM.MESSAGE_LEVEL的值设置为'25'.
在编写PL/SQL代码中使用SELECT语句时如何避免例外发生
在使用SELECT语句为某变量赋值时,往往会出 quot;NO_DATA_FOUND"和"TOO_MANY_ROWS"等异常情况,使用SELECT语句分两种情况:第一种情况,判断某表中是否有符合某一条件的记录,这时使用聚组函数MAX就可以避免以上两个例外的发生.其格式:SELECTMAX(列1),MAX(列2)......INTO变量1,变量2......FROM基表WHERE条件,当没有符合条件的数据时,该语句返回空,即变量1,变量2......的值均为空,而不会出现"NO_DATA_FOUND"例外,另外使用聚组函数MAX的同时也就避免了"TOO_MANY_ROWS"例外.第二种情况,SELECT语句中含聚组函数SUM,这时如果使用了GROUPBY和HAVING子句,当没有符合条件的记录时将发生"NO_DATA_FOUND"例外,此时避免例外的办法是:去掉GROUPBY和HAVING子句,将HAVING子句的条件加到WHERE子句中.这样在使用SELECT语句时就不必再额外增加一段处理例外的代码,从而简化的代码的编写.
当使用主从块时,如何使从块自动提交
在FORM设计时有时需要用到主从块,在主从块录入时每当鼠标从从块移到主块准备录入一条新记录时,总是弹出一报警器,问你是否保存数据,从而影响录入速度,将该报警器去掉的方法是:在过程"CLEAR_ALL_MASTER_DETAILS"中的"CLEAR_BLOCK(ASK_COMMIT)"即清除从块时是否提交改为"CLEAR_BLOCK(DO_COMMIT)",这样从块录完数据再导航到主块录入新记录时,系统将自动提交数据,而不再出现上述提示.
如何减少FORM所占磁盘空间
(1)对于块中只用于查询并且无格式限制的项,设置为显示项.
(2)保存FORM时先断开与数据库的链接,然后在保存.以上两种方法均可减小FORM的大小,尤其是第二种方法更为明显.当硬盘空间较小,或将程序备份到软盘上时,这样作是很有意义的.
如何使定制菜单的主菜单中WINDOWS项不显示
在MAINMENU中建立一个为WINDOWS属性的菜单项,这样主菜单中WINDOWS项就不再显示.
如何使不同布局的报表显示在同一页上
复杂的报表往往是由几部分组成,需建立多个查询,而每个查询都对应着一个布局,怎样才能使具有不同布局的报表数据显示在同一页上呢 其方法如下:第一步,首先根据实际报表格式建立第一个查询组的布局,称为布局1,然后依次再建立起其他查询组的布局,分别称为布局2,布局3.......注意:每个布局最外围的单选框不要去掉.第二步,分别为布局2,布局3......建立一个到布局1的定位(ANCHOR),即选中工具栏中的ANCHOR,鼠标单击布局2的单选框,然后按住鼠标左键并拖动鼠标到布局1的单选框上(可以选择上边、下边、左边或右边),松开鼠标按钮,按此方法再建立布局3,布局4......到布局1的定位.建立定位的作用是使布局2,布局3......相对与布局1的位置保持不变,这样就使具有不同布局的报表数据显示并打印在同一物理页上.
怎样较快的生成FMX文件
用RUN命令,一次只能生成一个.FMX文件,如果想生成一批.FMX文件,这样做即麻烦又费时,一个生成.FMX较快的办法是:先打开要运行的.FMB文件,如何按住SHIFT键将这些文件全部选中,在从系统菜单"文件"中选择"ADMINISTRATION"中"GENERATE"即可.
如何在FORM中同时加入水平与垂直滚动条
首先,必须将画布类型设置为"堆叠式"画布,其它类型的画布不能显示滚动条.将画布类型设置为"堆叠式"之后,该画布属性选项板的"物理属性"子类会出现"显示水平滚动条"与"显示垂直滚动条"两项内容,将其同时设置为"是",则可以同时显示水平与垂直滚动条.
如何在告警框内显示message信息
当使用系统缺省设置,不进行任何设定时,message信息将在FORM窗口的底部以小字显示.如果希望引起用户注意,可以将message信息显示在告警框中.例如,如果用户输入的数据类型错误,则弹出一个告警窗口,并在其中显示message信息:"输入数据类型不符",这样,可以更加清晰地提醒用户输入有误,并允许用户及时地改正错误.
在告警框中显示message信息,只需要创建一个警告(alert)与一个ON_ERROR触发器,由于引用的是系统错误信息,所以不需要程序员自己编写捕捉错误并弹出相关警告信息的程序,从而提供了极大的便利.
在告警框内显示message信息的过程如下所述:
1. 创建一个只具有一个按钮的警告"general_error_alert".
2. 在FORM一级创建ON_ERROR触发器,在出现错误时,将错误代码与信息显示在告警框中,程序如下:
declare
v_button number;
v_message varchar2(255);
begin
--将不需要显示的mesage信息屏蔽掉
if error_code in (0,40100,40400,40401,41051,40350)
then null;
else
--将错误代码与错误信息联系起来
v_message:=error_type || '-' || to_char(error_code) || ':' || error_text;
--将错误信息显示为告警信息
set_alert_property('general_error_alert',alert_message_text,v_message);
v_button:=show_alert('general_error_alert');
end if;
raise form_trigger_failure;
end;
如何一次退出所有FORM
如果重复调用并打开了多个FORM,希望在点击任何一个FORM选单上的"退出"按钮时同时退出所有的FORM,需要在每一个FORM中设置一个全局变量global.quit_all,同时在选单条上加入一个"退出"按钮,并建立以下触发器:
1.在每一个FORM上建立WHEN_NEW_FORM_INSTANCE触发器:
:global.quit_all := 'N';
2.在每一个FORM上建立WHEN_WINDOW_ACTIVATED触发器:
if :global.quit_all = 'Y'
then exit_form;
end if;
3.在选单条的"退出"按钮上建立WHEN_BUTTON_PRESSED触发器:
:global.quit_all := 'Y';
exit_form;
注意,要么使用OPEN_FORM打开FORM,要么使用CALL_FORM打开FORM,不能两者混合使用,否则容易发生错误,无法一次退出所有的FORM.
如何在FORM与REPORT之间传递参数
由于FORM与REPORT是两项独立的产品,不可能使用全局变量传递数据,所以它们之间的数据无法共享.如果希望REPORT继承FORM中的一些数据,可以将FORM中的有关数据作为参数,以参数列表的形式传递给REPORT.
例如,可以根据用户在FORM中的选择,在REPORT中动态生成符合查询条件的数据,方法是将FORM中的查询条件,作为参数传递给REPORT,从而在REPORT中动态生成查询结果.
在FORM与REPORT之间传递参数的程序如下所示:
declare
pl_id ParamList;
begin
—获取tmpdep的参数列表值
pl_id := Get_Parameter_List( 'tmpdep' );
—如果参数列表pl_id已存在,则删除它,然后重建.如果不删除当前pl_id,则无法创建参数列表,并在运行FORM时出现错误提示:参数列表已存在,无法重建
if Not Id_Null( pl_id )
then Destroy_Parameter_List(pl_id);
end if;
--创建参数列表tmpdep
pl_id:=Create_Parameter_List('tmpdep' );
--在参数列表pl_id中加入参数w_clause,同时对w_clause赋值
where deptno=:dept_deptno.
Add_Parameter( pl_id,'w_clause', TEXT_Parameter, 'where deptno=:dept.deptno');
--运行报表,并将现有参数列表pl_id与值传递给报表report1
run_product(reports,'C:\report\report1',synchronous,runtime,filesystem,pl_id);
end ;
从FORM调用REPORT时,如何使REPORT以满屏方式显示
当从FORM调用REPORT时,REPORT将按缺省窗口大小(420×360)显示,如果希望REPORT以满屏方式显示,需要加入如下代码:
add_parameter(pl_id,maximize',TEXT_PARAMETER,'yes');
如何关闭REPORT运行时的参数窗口
当FORM调用REPORT时,首先会弹出一个参数窗口,显示所有FORM传递给REPORT的参数,待点击该窗口中的"运行"后,才运行REPORT.我们也可以不显示该参数窗口,方法是在FORM中加入如下代码:
Add_Parameter(pl_id,'w_clause',TEXT_Parameter,'NO');
在Oracle中实现报表的定长输出
Oracle*Reports是Oracle的数据统计及图形化报表工具,它提供了六种风格的报表格式,而我们通常使用的只有其中的两种,即Tabular和Matrix,无论用哪种风格生成的报表,打印出的表格数都是动态变化的.其中Tabular风格的报表,列数固定,而行数不定;Matrix风格的报表,行数和列数均不定.那么在Oracle*Reports中如何实现报表的定长与定宽输出呢 笔者在实际开发过程中对上述两种风格的报表各总结出一种行之有效的方法,供大家参考.
对于Tabular风格的报表,可用报表触发子After Parameter Form和After Report实现定长输出.其方法是:根据实际情况确定每页打印的行数,当最后一页的记录数少于每页打印的行数时,则用空记录补齐.在触发子After Parameter Form插入空记录,在触发子After Report中再将空记录删除,下面举例说明.
假设有一数据基表WZDM:存放物资代码信息,其数据结构为:
字段名
含义
长度
类型
wzdm
物资代码
9
c
wzmc
物资名称
20
c
xhgg
型号规格
20
c
jldw
计量单位
6
c
要求:按定长输出物资代码表,并且每页均输出x行(x可根据实际情况而定).
启动Oracle*Reports,建立物资代码打印报表(略),然后在报表触发子After Parameter Form中加入以下代码:
Declare
v—jls number(2);
i number(2):=1;
Begin
Select Count(*) Into V—jls From Wzdm;
If Mod(V—jls,x)〈〉0 Then
Loop
Exit When i〉=(x-mod(v—jls,x))+1;
Insert Into Wzdm(Wzdm,Wzmc,Xhgg,Jldw)
Values(′′,′′,′′,′′);
i:=i+1;
End Loop;
Commit;
End If;
End;
在报表触发子After Report中分别加入以下代码:
Begin
Delete From Wzdm Where Wzdm Is Null;
Commit;
End;
运行报表后即可输出定长的物资代码表.
说明:对于其它Tabular风格的报表,在编写上述两个触发子时只需将基表名与列名根据实际情况修改一下,并确定x的值即可.
二,对于Matrix风格的报表,可利用视图实现定长与定宽输出,其思路是:当行记录数和列记录少于实际报表的行数和列数时,均以空记录补齐.下面举例说明.
假设有一物资资金消耗去向统计月报,该表横向显示本期消耗去向,纵向显示物资类别,由于每月物资消耗去向和消耗物资均不定,所以此类报表即为一矩阵报表.该报表的数据存放在基表T—ZJXHQX中,其数据结构如下:
字段名
含义
长度
类型
lbmc
类别名称
20
c
dwmc
单位名称
20
c
je
金额
14,2
n
要求:按定长定宽输出物资资金消耗去向统计月报,并且每页均输出x行y列(行数和列数可根据实际情况而定).
首先建一基表T—kjl,用来存放空记录,其数据结构为:
字段名
含义
长度
类型
no
序号
2
n
建完该数据表后,再往其中插入记录,记录数可根据实际情况而定,一般为一页所能打印的最大行数,这里假设为z条,即No的值为1,2,3…z.
建视图,其过程如下:
Create View V—TJBB As
Select Dwmc,Lbmc,Je From T—zjxhqx
Union
Select Dwmc,Null,To—Number(Null) From T—zjxhqx,T—kjl
Where No-(z-x)〉(Select Mod(Count(Distinct Lbmc)-1,x)+1 From T—zjxhqx)
Union
Select Null,Lbmc,To—Number(Null) From T—zjxhqx,T—kjl
Where No-(z-y)〉(Select Mod(Count(Distinct Dwmc)-1,y)+1 From T—zjxhqx);
3. 启动Oracle*Reports,建立矩阵报表查询时直接引用视图V—TJBB即可.这样运行时输出的报表每页都是x行y列,即实现了定长和定宽输出.
Developer/2000 FROMS 4.5 中 的" 宏" 代 换
---- 在 早 期FOXPRO 数 据 库 编 程 中, 经 常 用 到 宏 代 换 功 能, 但 在FORMS 中 却 没 有 此 功 能, 象"&","*" 等 在 编 程 中 经 常 用 到 的, 在FORMS 中 只 得 一 行 一 行 代 码 的 写, 但 后 来 发 现FORMS 中 也 有 类 似 功 能, 用NAME_IN(),COPY() 可 以 实 现 类 似 的 功 能.Name_in() 用 于 取 出 参 数 名 代 表 的 对 象 了 数 值, 而COPY() 把 一 个 参 数 值 传 递 给 另 一 参 数 值 表 示 的 对 象. 的 如 下 例:
FORM 结 构:
块B
项 L1,L2,L3,L4,L5,L6
在 作 录 入 程 序 时 要 对L1...L6 项 清 零
DELCATE
strItemName varchar2(20);
BEGIN
for I in 1 …6 loop
strItemName:=':b.l"||to_char(i);
copy(null,strItemNmae);
end loop;
END;
---- 对 于NAME_IN 的 应 用 可 能 更 多 一 些, 笔 者 在 做 社 保 软 件 时, 作 保 险 缴 费 录 入 时 曾 用 它 少 写 了 许 多 代 码. 当 然 代 码 的 减 少 就 义 意 味 维 护 工 作 量 的 减 少
FORM结构:
养老:
块:YLYJ(养老应缴)
项:DWJTC(单位缴统筹),DWJZH(单位缴帐户),GRJF(个人缴费)
块:YLSJ (养老实缴)
项:DWJTC(单位缴统筹),DWJZH(单位缴帐户),GRJF(个人缴费)
工伤:
块:GSYJ(工伤应缴)
项:DWJTC(单位缴统筹),DWJZH(单位缴帐户),GRJF(个人缴费)
块:GSSJ (工伤实缴)
项:DWJTC(单位缴统筹),DWJZH(单位缴帐户),GRJF(个人缴费)
医疗:
块:YILYJ(医疗应缴)
项:DWJTC(单位缴统筹),DWJZH(单位缴帐户),GRJF(个人缴费)
块:YILSJ (医疗实缴)
项:DWJTC(单位缴统筹),DWJZH(单位缴帐户),GRJF(个人缴费)
---- 三 个 块 的 结 构 相 同, 只 是 块 名 称 不 同, 缴 费 时 时 行 的 操 作 也 一 样, 实 缴 名 项 不 能 大 于 应 缴, 不 用NAME_IN 时, 只 能 写 三 段 程 序, 但 用 了NAME_IN 后 只 用 一 段 写 一 个 函 数 就 能 达 到 目 的. 如 下:
FUNCTION FUN_JF (PRE_BLOCK_NAME
IN VARCHAR) RETURN BOOLEAN IS
BEGIN
if name_in(pre_block_name||'sj.dwjtc')
>name_in(pre_block_name||'yj.dwjtc') or
name_in(pre_block_name||'sj.dwjzh')
>name_in(pre_block_name||'yj.dwjzh') or
name_in(pre_block_name||'sj.grjf')
>name_in(pre_block_name||'yj.grjf') then
message(' 实 缴 大 于 应 缴');
return false;
end if;
return true;
END;
---- 从 上 面 的 两 个 例 子 来 看NAME_IN 和COPY 的 应 用 能 起 到 其 它 编 程 语 言 的" 宏" 代 换 功 能, 代 码 的 优 化 方 面 确 实 能 起 不 少 的 作 用, 减 少 了 程 序 源 代 码 的 维 护 工 作.
用FORMS 实 现ORACLE 数 据 库 与 其 它 数 据 源 数 据 的 交 换
---- Developer/2000 不 能 实 现 同 时 多 数 据 源 的 同 时 连 接, 在 多 系 统 和 异 种 数 据 源 的 操 作 中 功 能 确 实 大 打 折 扣, 虽 然 可 以 用3GL 加ODBC 作 一DLL 应 用 能 实 现, 但 一 般 的 应 用 中 又 有 点 没 用 必 要 作 的 那 么 复 杂. 实 际 上Developer/2000 内 嵌 包TEXT_IO 为 我 们 提 供 了 一 个 更 简 单 的 方 法. 几 乎 所 有 的 数 据 库 或 数 据 库 前 端 开 发 工 具 都 提 供 文 本 文 件 的 操 作, 这 样 我 们 完 全 可 以 用 文 本 文 件 作 为 数 据 交 换 的 通 用 格 式. 下 例 是 在 保 险 业 中 的 一 应 用:( 要 用 到d2kwfile.dll 应 用)
DECLARE
filename varchar2(128):=null;
filenum text_io.file_type;
linebuf varchar2(100);
r_temp temp%rowtype;
BEGIN
filename:=d2k_file_dialog.show
('请选择缴费工资台帐原文件','c:\','源文件(*.txt)|*.txt|');
if filename is null then
raise form_trigger_failure; end if;
filenum:=text_io.fopen(filename,'r');
loop
BEGIN
text_io.get_line(filenum,linebuf);
TEXT_IO.PUT(linebuf);TEXT_IO.NEW_LINE;
exception when no_data_found then
exit;
END;
BEGIN
v_temp.l1=substr(linebuf,1,9);
v_temp.l2:= to_number(substr(linebuf,10,5));
insert into temp(l1,l2) values (v_temp.l1,v_temp.l2);
exception when others then
END;
< >
null;
end loop;
END;
FORMS 4.5 实 现 的 列 表 查 询, 多 行 录 入 中 的 实 现 行 累 计
---- 在PB 和VB 中 都 用 类 似 的 求 和 或 者 说 累 计 列, 但 在 早 期 的FORMS4.5 中 没 有 此 功 能, 对 于 多 条 记 录 的 录 入 中 需 要 进 行 求 和 时 很 不 方 便, 其 实 利 用FORM 的 触 发 子 很 容 易 实 现. 如 下 例:
块:b1 项:l1,l2.l3,l4
块:b2 项:l1,l2,l3,l4
块b2是B1的求和块
在块B1中的PRE_TEXT_ITEM中代码:
IF SUBSTR(:SYSTEM.CURRENT_ITEM,1,1) IN ('L') THEN
:GLOBAL.ITEM_PREVALUES:=NAME_IN
('B1.'||:SYSTEM.CURRENT_ITEM);
END IF;
在块 B2中的POST_TEXT_ITEM中代码:
DECLARE
num_cz number; --数据项在录入或修改前后的差值
num_hz number; --数据项在修改后的求合
BEGIN
if substr(:system.current_item,1,1) in ('l') then
:global.item_nextvalues:=name_in
('b1.'||:system.current_item);
num_cz:=nvl(to_number(:global.item_nextvalues),0)-
nvl(to_number(:global.item_prevalues),0);
--新的和值
num_hz:=nvl(to_number(name_in('b_sum.'
||:system.current_item)),0)+num_cz;
copy(to_char(num_hz),'b2.'||:system.current_item);
end if;
END;
---- 通 过 前 后 两 值 的 比 较 很 容 易 的 实 现 一 个 较 通 用 的 求 和 算 法, 另 外 又 一 次 用 到NAME_IN 和 COPY , 减 少 了 代 码 量. 在 块 上 实 现 触 发 子 也 减 少 了 代 码 维 护 工 作 量.
REPORT 2.5 中 实 现 的 动 态 报 表( 一 张 表 利 用 多 个QUERY 语 句, 生 成 一 样 格 式 的 多 张 报 表
---- 在 做 报 表 时 经 常 要 遇 到 类 似 的 报 表 有 多 张 的 情 况, 虽 然 通 过 简 单 的 拷 贝 可 以 减 少 编 程 的 工 作 量, 但 在 后 期 的 维 护 中 却 增 加 了 难 度, 一 张 表 改 完 后 又 改 另 一 张 表, 进 行 大 量 的 重 复 劳 动 不 是 每 个 程 序 员 想 做 的 工 作. 其 实 在REPORT 2.5 中 有 一 很 好 的 功 能 可 能 完 成 这 样 的 工 作. 就 是REPORT 的" 宏" 代 换. 如 下 例:
两个表:tab_temp1 (a number,b number,c number)
tab_temp2 (d number,e number,f number)
---- 作 两 张 报 表, 表 头 一 样, 但 查 询 不 一 样, 分 别 取 自 两 个 表
建 一 用 户 参 数(user parameters) p_1 类 型 CHAR 长 度 200, 缺 省 值 是 SELECT A,B,C FROM TAB_TEMP
建 一 查 询(QUERIES), 在 查 询 语 句 中 输 入:&P_1
生 成 布 局, 可 按 要 求 画 出 报 表.
---- 因 在 查 定 义 中 用 的 是&p_1 定 义, 所 以 可 以 在 运 行 时 动 态 的 给P_1 传 递 能 数 只 要 能 满 足 其 列 名 定 义 即 可, 例 可 用 如 下 语 句 代 入P_1
SELECT D A,E B,F C FROM TAB_TEMP2
---- 这 样 就 生 成 了 一 个 多 功 能 报 表, 把 编 写REPROT 工 作 从 简 单 的 布 局 编 辑 中 解 脱 出 来, 而 投 入 到 实 质 性 的 工 作SQL 语 句 的 生 成 上 去.
用ORACLE*Forms 和ORACLE*Graphics实现数据与图形动态显示
1 . 引 言
---- ORACLE 关 系 数 据 库 管 理 系 统 是 目 前 世 界 上 最 流 行 的 高 性 能 数 据 库 管 理 系 统 之 一,Developer/2000 是ORACLE 公 司 推 出 的 集 成 化 软 件 开 发 和 运 行 环 境. ORACLE *Forms 是Developer/2000 的 一 部 分, 它 是 一 种 功 能 丰 富, 用 于 构 建 应 用 的 工 具 产 品, 产 品 化 屏 幕 处 理 存 储 在 数 据 库 中 的 数 据. 在 许 多 实 际 应 用 中, 往 往 需 要 将 数 据 用 很 直 观 的 图 形 表 示 出 来. 例 如: 饼 图, 折 线 图, 直 方 图 等, 从 而 使 数 据 及 其 比 例 关 系 一 目 了 然.Developer/2000 的 另 一 工 具ORACLE *Graphics 提 供 了 丰 富 的 图 形 化 表 示 数 据 的 方 法, 它 可 以 从 各 种 数 据 源 获 得 数 据, 并 可 以 与Forms 模 块 结 合 起 来, 更 有 效 地 表 示 数 据.
---- 笔 者 曾 参 加 某 企 业 决 策 支 持 系 统 的 开 发 工 作, 通 过 在Forms 中 调 用Graphics 中 的 图 形 功 能, 使 数 据 表 示 更 为 直 观, 并 可 根 据Forms 中 数 据 的 变 化 来 动 态 地 显 示 图 形, 从 而 帮 助 决 策 人 员 进 行 数 据 分 析, 达 到 支 持 决 策 的 目 的. 下 文 是 笔 者 在 实 际 开 发 中, 完 成 动 态 显 示 图 形 功 能 制 作 过 程 中 的 一 点 体 会.
动 态 图 形 显 示 的 实 现
---- 本 例 假 设 有 一 个 产 品 销 售 数 据 表SALES, 并 含 有 销 售 时 间, 产 品 名 称, 销 售 量 三 个 字 段( 销 售 时 间 以 年 为 单 位), 其 数 据 字 典 为
字 段 名 字 段 长 度 字 段 含 义 TIME number(4)
销 售 时 间
NAME
char(10)
产 品 名 称
AMOUNT
number(10,2)
销 售 量
---- 启 动Graphics, 建 立 一 个 新 的 图 形 文 件, 并 命 名 为chart.ogd. 在Queries 中 定 义SQL 查 询 语 句 以 显 示 图 形, 并 在 图 形 的 属 性 栏 中 定 义x 轴 和y 轴 所 需 显 示 的 数 据. 本 例 将 在x 轴 显 示 产 品 名 称,y 轴 显 示 各 种 产 品 的 销 售 量.
---- 启 动Forms, 建 立 一 个 新 的 Forms 应 用 文 件sale.fmb. 在 画 布CANVAS1 中 填 加 一 个List Item 控 件LIST1 , 并 在LIST1 的 属 性 中 填 充 所 要 显 示 的 时 间 值. 然 后 填 加 一 个Chart Item 控 件chart_area1, 并 调 节 好chart_area1 的 边 界 和 大 小, 以 显 示 图 形chart.ogd.
---- 在Forms 中 调 用 图 形, 必 须 与Graphics 进 行 参 数 值 的 传 递. 首 先 回 到Graphics 中, 在chart.ogd 中 设 置 如 下 结 构:
---- (1) 在 参 数 表Parameters 中 定 义 参 数. 本 例 需 传 递 时 间 参 数, 并 设 其 为 m1, 在 参 数 表 中 设 置 其 属 性
parameter m1
name m1
type number
initial value 1998
---- (2) 定 义 图 形 的 查 询 语 句. 在Queries 中 定 义"query0" 查 询, 如 下 所 示:
select product,amount
from sales
where time=:m1
---- (3) 定 义 过 程. 在 Program Unit 中 编 写 update_chart 过 程, 完 成 图 形 随 参 数 变 化 显 示 的 功 能.
PROCEDURE update_chart IS
BEGIN
og_execute_query(og_get_query('query0'));
END;
---- 完 成 以 上 工 作 后, 回 到Forms 中, 首 先 打 开orawin95\forms45\plsqllib\og.pll 文 件, 然 后 定 义 如 下 结 构:
---- (1) 在LIST1 的 属 性List elements 中 填 写 列 表 框 中 所 要 显 示 的 数 值, 然 后 设 置WHEN_LIST_CHANGED 触 发 器, 并 编 写 触 发 器 代 码, 如 下
pl ParamList;
pl := Get_Parameter_List('plist');
IF NOT Id_Null(pl) THEN
destroy_parameter_list(pl);
END IF;
pl := Create_Parameter_List('plist');
add_parameter(pl,'m1',text_parameter,:blk1.list1);
og.intERPret('c:\chart.ogd','chart_area1','
update_chart;',true,pl);
---- (2) 在Forms 中 设 置WHEN_NEW_FORM_INSTANCE 触 发 器, 完 成 初 始 化 工 作, 其 程 序 如 下:
Set_Window_Property (Forms_MDI_Window,
Window_State,Maximize);
Show_Window ('sales');
set_window_property('sales',window_state,
maximize);
og.open('c:\chart.ogd','chart_area1');
---- (3) 在Forms 中 设 置POST_FORM 触 发 器, 用 来 在 程 序 结 束 时 关 闭 图 形.
og.close('c:\chart.ogd','blk1.chart_area1');
---- 通 过 以 上 过 程, 动 态 图 形 显 示 得 以 实 现. 当 改 变 时 间 列 表 中 的 数 值 时, 图 形 随 着 时 间 的 改 变 而 变 化, 显 示 另 一 个 时 间 相 应 的 各 种 产 品 的 销 售 量 的 值.
3. 结 论
---- 本 文 介 绍 了 一 些Developer/2000 中Forms 和Graphics 的 开 发 方 法 及 使 用 技 巧. 当 然Developer/2000 中 还 有 许 多 其 他 的 触 发 器 及 内 部 例 程, 需 要 在 实 践 中 不 断 探 索.
数字分金额转成大写汉字元金额程序!
CREATE OR REPLACE FUNCTION CONVERT_MONEY(INPUT_NBR IN NUMBER DEFAULT 0)
/*
函数名称: CONVERT_MONEY
用 于: 将以分为单位输入的数值转换为大写汉字形式
注 释: 当转换后的汉字以分结尾时,不加"整",当以角或元结尾时加"整",这符合银行的规定.
数字金额凡是中间出现0的,必须转为大写的"零",连续多个0时只转为一个"零"字,
结尾出现0时要加"整",结尾不是0时不加"整",这与前面的规定是一致的.
由于圆是货币单位,所以在多于1元钱时,圆是必须出现的.但是,万佰等是数字单位,有
时可能不出现.
代码:
*/
RETURN VARCHAR2 IS
INPUT_NBR_BAK NUMBER(20); /*用于接收输入参数 INPUT_NBR */
NUM_CHARACTER VARCHAR2(20) := '零壹贰叁肆伍陆柒捌玖';
UNIT_CHARACTER VARCHAR2(40) := '分角圆拾佰仟万拾佰仟亿拾佰仟万拾佰仟亿';
OUTPUT_STRING VARCHAR2(100):= '';
REMAIN_NBR NUMBER(20);
BIT_NUM NUMBER(20); /*每一位上的数字*/
BIT_UNIT VARCHAR2(2); /*每一位所对的单位*/
BIT_INDIC NUMBER(1) :=0; /*每一位的数字是否为0,0表示为0,1表示不为0*/
I NUMBER(2) :=0; /*循环次数,索引变量从0开始*/
SPE_UNIT VARCHAR2(2):='A';/*特殊位,包括万和亿,表示该亿汉字是否已写入结果字串*/
SIGN_INDIC VARCHAR2(1); /*用于标志数值符号:0为正,1为负*/
BEGIN
IF INPUT_NBR=0 THEN RETURN '零圆整';
ELSIF INPUT_NBR>0 THEN SIGN_INDIC:='0';
INPUT_NBR_BAK:=INPUT_NBR;
ELSIF INPUT_NBR 0 THEN /*当前位的值不为0*/
BIT_INDIC :=1;
IF I=6 OR I=14 THEN /*当前位是'万'位或'万亿'位*/
SPE_UNIT:='万'; /*表示万已经写入OUTPUT_STRING中,在BIT_UNIT中会包含万字*/
ELSIF (I>=7 AND I=15 AND I<=17) THEN /*当前位在万及千万之间或万亿及千万亿之间*/
IF SPE_UNIT!='万' THEN /*万还没写入OUTPUT_STRING中,则要写入一次*/
OUTPUT_STRING:='万'||OUTPUT_STRING;
SPE_UNIT:='万'; /*表示万已经写入OUTPUT_STRING中*/
END IF;
END IF; /*高于千万亿的数本程序不考虑了*/
OUTPUT_STRING := SUBSTR(NUM_CHARACTER, BIT_NUM * 2 + 1, 2)||BIT_UNIT||OUTPUT_STRING;
ELSE /*当前位等于0时,走此分支*/
IF BIT_INDIC = 1 THEN /*当前位的前一位不为0时写 零 */
OUTPUT_STRING := '零'||OUTPUT_STRING;
END IF;
IF BIT_UNIT IN ('圆','亿') THEN /*若已达圆位,则圆是必须出现的,由于亿太大,不与万相同处理,所以就与圆一样处理*/
SPE_UNIT:=BIT_UNIT; /*保存圆与亿,以与万相区别*/
OUTPUT_STRING := BIT_UNIT||OUTPUT_STRING;
END IF;
BIT_INDIC :=0; /*当前位的值为0*/
END IF;
I := I + 1;
EXIT WHEN INPUT_NBR_BAK = 0;
END LOOP;
IF MOD(INPUT_NBR,10)=0 THEN /*输入的数字没有分,最小的是角,则尾部串个整*/
OUTPUT_STRING:=OUTPUT_STRING||'整';
END IF;
IF SIGN_INDIC='1' THEN
OUTPUT_STRING:='负'||OUTPUT_STRING;
END IF;
RETURN OUTPUT_STRING;
END;
/ |
|